aboutsummaryrefslogtreecommitdiff
path: root/vendor/cfitsio
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/cfitsio')
-rw-r--r--vendor/cfitsio/License.txt25
-rw-r--r--vendor/cfitsio/Makefile166
-rw-r--r--vendor/cfitsio/Makefile.in166
-rw-r--r--vendor/cfitsio/README144
-rw-r--r--vendor/cfitsio/README.MacOS70
-rw-r--r--vendor/cfitsio/README.win3274
-rw-r--r--vendor/cfitsio/adler32.c167
-rw-r--r--vendor/cfitsio/buffers.c1371
-rw-r--r--vendor/cfitsio/cfileio.c6965
-rw-r--r--vendor/cfitsio/cfitsio.doc9535
-rw-r--r--vendor/cfitsio/cfitsio.pc11
-rw-r--r--vendor/cfitsio/cfitsio.pc.in11
-rw-r--r--vendor/cfitsio/cfitsio.pdfbin0 -> 944242 bytes
-rw-r--r--vendor/cfitsio/cfitsio.ps15233
-rw-r--r--vendor/cfitsio/cfitsio.tex10644
-rw-r--r--vendor/cfitsio/cfitsio.toc123
-rw-r--r--vendor/cfitsio/cfitsio_mac.sit.hqx1
-rw-r--r--vendor/cfitsio/cfortran.doc2088
-rw-r--r--vendor/cfitsio/cfortran.h2515
-rw-r--r--vendor/cfitsio/changes.txt3844
-rw-r--r--vendor/cfitsio/checksum.c508
-rw-r--r--vendor/cfitsio/config.log591
-rwxr-xr-xvendor/cfitsio/config.status916
-rwxr-xr-xvendor/cfitsio/configure6682
-rw-r--r--vendor/cfitsio/configure.in507
-rw-r--r--vendor/cfitsio/cookbook.c571
-rw-r--r--vendor/cfitsio/cookbook.f772
-rw-r--r--vendor/cfitsio/crc32.c440
-rw-r--r--vendor/cfitsio/crc32.h441
-rw-r--r--vendor/cfitsio/deflate.c1832
-rw-r--r--vendor/cfitsio/deflate.h340
-rw-r--r--vendor/cfitsio/drvrfile.c966
-rw-r--r--vendor/cfitsio/drvrgsiftp.c522
-rw-r--r--vendor/cfitsio/drvrgsiftp.h21
-rw-r--r--vendor/cfitsio/drvrmem.c1184
-rw-r--r--vendor/cfitsio/drvrnet.c2741
-rw-r--r--vendor/cfitsio/drvrsmem.c973
-rw-r--r--vendor/cfitsio/drvrsmem.h179
-rw-r--r--vendor/cfitsio/editcol.c2474
-rw-r--r--vendor/cfitsio/edithdu.c883
-rw-r--r--vendor/cfitsio/eval.l545
-rw-r--r--vendor/cfitsio/eval.y5837
-rw-r--r--vendor/cfitsio/eval_defs.h163
-rw-r--r--vendor/cfitsio/eval_f.c2823
-rw-r--r--vendor/cfitsio/eval_l.c2252
-rw-r--r--vendor/cfitsio/eval_tab.h42
-rw-r--r--vendor/cfitsio/eval_y.c7333
-rw-r--r--vendor/cfitsio/f77.inc31
-rw-r--r--vendor/cfitsio/f77_wrap.h288
-rw-r--r--vendor/cfitsio/f77_wrap1.c345
-rw-r--r--vendor/cfitsio/f77_wrap2.c711
-rw-r--r--vendor/cfitsio/f77_wrap3.c853
-rw-r--r--vendor/cfitsio/f77_wrap4.c572
-rw-r--r--vendor/cfitsio/fits_hcompress.c1858
-rw-r--r--vendor/cfitsio/fits_hdecompress.c2618
-rw-r--r--vendor/cfitsio/fitscopy.c60
-rw-r--r--vendor/cfitsio/fitscore.c9243
-rw-r--r--vendor/cfitsio/fitsfile.tpt8
-rw-r--r--vendor/cfitsio/fitsio.doc6607
-rw-r--r--vendor/cfitsio/fitsio.h1934
-rw-r--r--vendor/cfitsio/fitsio.pdfbin0 -> 688002 bytes
-rw-r--r--vendor/cfitsio/fitsio.ps11353
-rw-r--r--vendor/cfitsio/fitsio.tex7688
-rw-r--r--vendor/cfitsio/fitsio.toc95
-rw-r--r--vendor/cfitsio/fitsio2.h1205
-rw-r--r--vendor/cfitsio/fpack.c387
-rw-r--r--vendor/cfitsio/fpack.h171
-rw-r--r--vendor/cfitsio/fpackguide.pdfbin0 -> 545957 bytes
-rw-r--r--vendor/cfitsio/fpackutil.c2391
-rw-r--r--vendor/cfitsio/funpack.c168
-rw-r--r--vendor/cfitsio/getcol.c1055
-rw-r--r--vendor/cfitsio/getcolb.c2002
-rw-r--r--vendor/cfitsio/getcold.c1677
-rw-r--r--vendor/cfitsio/getcole.c1680
-rw-r--r--vendor/cfitsio/getcoli.c1902
-rw-r--r--vendor/cfitsio/getcolj.c3728
-rw-r--r--vendor/cfitsio/getcolk.c1895
-rw-r--r--vendor/cfitsio/getcoll.c614
-rw-r--r--vendor/cfitsio/getcols.c835
-rw-r--r--vendor/cfitsio/getcolsb.c1991
-rw-r--r--vendor/cfitsio/getcolui.c1908
-rw-r--r--vendor/cfitsio/getcoluj.c1902
-rw-r--r--vendor/cfitsio/getcoluk.c1917
-rw-r--r--vendor/cfitsio/getkey.c3242
-rw-r--r--vendor/cfitsio/group.c6463
-rw-r--r--vendor/cfitsio/group.h65
-rw-r--r--vendor/cfitsio/grparser.c1379
-rw-r--r--vendor/cfitsio/grparser.h185
-rw-r--r--vendor/cfitsio/histo.c2221
-rw-r--r--vendor/cfitsio/imcompress.c9247
-rw-r--r--vendor/cfitsio/imcopy.c233
-rw-r--r--vendor/cfitsio/infback.c632
-rw-r--r--vendor/cfitsio/inffast.c340
-rw-r--r--vendor/cfitsio/inffast.h11
-rw-r--r--vendor/cfitsio/inffixed.h94
-rw-r--r--vendor/cfitsio/inflate.c1480
-rw-r--r--vendor/cfitsio/inflate.h122
-rw-r--r--vendor/cfitsio/inftrees.c330
-rw-r--r--vendor/cfitsio/inftrees.h62
-rw-r--r--vendor/cfitsio/iraffits.c2073
-rw-r--r--vendor/cfitsio/iter_a.c147
-rw-r--r--vendor/cfitsio/iter_a.f224
-rw-r--r--vendor/cfitsio/iter_a.fit1111
-rw-r--r--vendor/cfitsio/iter_b.c114
-rw-r--r--vendor/cfitsio/iter_b.f193
-rw-r--r--vendor/cfitsio/iter_b.fitbin0 -> 408960 bytes
-rw-r--r--vendor/cfitsio/iter_c.c171
-rw-r--r--vendor/cfitsio/iter_c.f347
-rw-r--r--vendor/cfitsio/iter_c.fit701
-rw-r--r--vendor/cfitsio/iter_image.c93
-rw-r--r--vendor/cfitsio/iter_var.c100
-rw-r--r--vendor/cfitsio/longnam.h592
-rw-r--r--vendor/cfitsio/make_dfloat.com90
-rw-r--r--vendor/cfitsio/make_gfloat.com88
-rw-r--r--vendor/cfitsio/make_ieee.com87
-rw-r--r--vendor/cfitsio/makefile.bc588
-rw-r--r--vendor/cfitsio/makefile.vcc793
-rw-r--r--vendor/cfitsio/makepc.bat87
-rwxr-xr-xvendor/cfitsio/mklibs31
-rw-r--r--vendor/cfitsio/mkpkg74
-rw-r--r--vendor/cfitsio/modkey.c1706
-rw-r--r--vendor/cfitsio/pliocomp.c331
-rw-r--r--vendor/cfitsio/putcol.c1929
-rw-r--r--vendor/cfitsio/putcolb.c1013
-rw-r--r--vendor/cfitsio/putcold.c1060
-rw-r--r--vendor/cfitsio/putcole.c1074
-rw-r--r--vendor/cfitsio/putcoli.c986
-rw-r--r--vendor/cfitsio/putcolj.c1992
-rw-r--r--vendor/cfitsio/putcolk.c1013
-rw-r--r--vendor/cfitsio/putcoll.c369
-rw-r--r--vendor/cfitsio/putcols.c303
-rw-r--r--vendor/cfitsio/putcolsb.c974
-rw-r--r--vendor/cfitsio/putcolu.c629
-rw-r--r--vendor/cfitsio/putcolui.c969
-rw-r--r--vendor/cfitsio/putcoluj.c977
-rw-r--r--vendor/cfitsio/putcoluk.c993
-rw-r--r--vendor/cfitsio/putkey.c3085
-rw-r--r--vendor/cfitsio/quantize.c3888
-rw-r--r--vendor/cfitsio/quick.pdfbin0 -> 279588 bytes
-rw-r--r--vendor/cfitsio/quick.ps3850
-rw-r--r--vendor/cfitsio/quick.tex2159
-rw-r--r--vendor/cfitsio/quick.toc25
-rw-r--r--vendor/cfitsio/region.c1747
-rw-r--r--vendor/cfitsio/region.h82
-rw-r--r--vendor/cfitsio/ricecomp.c1382
-rw-r--r--vendor/cfitsio/sample.tpl121
-rw-r--r--vendor/cfitsio/scalnull.c229
-rw-r--r--vendor/cfitsio/smem.c77
-rw-r--r--vendor/cfitsio/speed.c511
-rw-r--r--vendor/cfitsio/swapproc.c247
-rw-r--r--vendor/cfitsio/testf77.f2488
-rw-r--r--vendor/cfitsio/testf77.out746
-rw-r--r--vendor/cfitsio/testf77.stdbin0 -> 66240 bytes
-rw-r--r--vendor/cfitsio/testprog.c2588
-rw-r--r--vendor/cfitsio/testprog.out797
-rw-r--r--vendor/cfitsio/testprog.std48
-rw-r--r--vendor/cfitsio/testprog.tpt12
-rw-r--r--vendor/cfitsio/trees.c1242
-rw-r--r--vendor/cfitsio/trees.h128
-rw-r--r--vendor/cfitsio/uncompr.c57
-rw-r--r--vendor/cfitsio/vmsieee.c130
-rw-r--r--vendor/cfitsio/vmsieeed.mar137
-rw-r--r--vendor/cfitsio/vmsieeer.mar106
-rw-r--r--vendor/cfitsio/wcssub.c1043
-rw-r--r--vendor/cfitsio/wcsutil.c503
-rw-r--r--vendor/cfitsio/winDumpExts.mak191
-rw-r--r--vendor/cfitsio/windumpexts.c502
-rw-r--r--vendor/cfitsio/zcompress.c504
-rw-r--r--vendor/cfitsio/zconf.h426
-rw-r--r--vendor/cfitsio/zlib.h1613
-rw-r--r--vendor/cfitsio/zuncompress.c603
-rw-r--r--vendor/cfitsio/zutil.c316
-rw-r--r--vendor/cfitsio/zutil.h272
173 files changed, 249366 insertions, 0 deletions
diff --git a/vendor/cfitsio/License.txt b/vendor/cfitsio/License.txt
new file mode 100644
index 00000000..2f5f48d3
--- /dev/null
+++ b/vendor/cfitsio/License.txt
@@ -0,0 +1,25 @@
+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.
diff --git a/vendor/cfitsio/Makefile b/vendor/cfitsio/Makefile
new file mode 100644
index 00000000..3e0d0da7
--- /dev/null
+++ b/vendor/cfitsio/Makefile
@@ -0,0 +1,166 @@
+#
+# 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
+#
+
+prefix = /d1/build.v216/iraf
+exec_prefix = /d1/build.v216/iraf
+DESTDIR =
+CFITSIO_LIB = ${DESTDIR}/d1/build.v216/iraf/bin
+CFITSIO_INCLUDE = ${DESTDIR}${prefix}/include
+INSTALL_DIRS = ${prefix} ${CFITSIO_INCLUDE} ${CFITSIO_LIB} ${CFITSIO_LIB}/pkgconfig
+
+
+SHELL = /bin/sh
+RANLIB = ranlib
+CC = gcc
+CFLAGS = -g -O2 -Dg77Fortran -fPIC
+SSE_FLAGS =
+FC = gfortran
+LDFLAGS = $(CFLAGS)
+DEFS = -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MATH_H=1 -DHAVE_LIMITS_H=1 -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DHAVE_FTRUNCATE=1 -DHAVE_LONGLONG=1 -DHAVE_SHMEM_SERVICES=1 -DHAVE_NET_SERVICES=1
+LIBS =
+FLEX = flex
+BISON = bison
+
+SHLIB_LD = gcc -shared
+SHLIB_SUFFIX = .so
+
+
+CORE_SOURCES = buffers.c cfileio.c checksum.c drvrfile.c drvrmem.c \
+ drvrnet.c drvrsmem.c drvrgsiftp.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 fits_hcompress.c fits_hdecompress.c zuncompress.c zcompress.c \
+ adler32.c crc32.c inffast.c inftrees.c trees.c zutil.c \
+ deflate.c infback.c inflate.c uncompr.c \
+
+SOURCES = ${CORE_SOURCES} ${FITSIO_SRC}
+
+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} ${LDFLAGS} -o $@ ${OBJECTS} -lm ${LIBS}
+
+install: libcfitsio.a $(INSTALL_DIRS)
+ @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}/; \
+ /bin/cp cfitsio.pc ${CFITSIO_LIB}/pkgconfig
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(DEFS) $<
+
+swapproc.o: swapproc.c
+ $(CC) -c $(CFLAGS) $(SSE_FLAGS) $(DEFS) $<
+
+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}
+
+fpack: fpack.o fpackutil.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o fpack fpack.o fpackutil.o libcfitsio.a -lm ${LIBS}
+
+funpack: funpack.o fpackutil.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o funpack funpack.o fpackutil.o libcfitsio.a -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 cfitsio.pc config.* configure.lineno
+
+# 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}
+
+cfitsioLibSrcs:
+ @echo ${SOURCES}
+
+# This target actually builds the objects needed for the lib in the above
+# case
+objs: ${CORE_OBJECTS}
+
+$(INSTALL_DIRS):
+ @if [ ! -d $@ ]; then mkdir -p $@; fi
diff --git a/vendor/cfitsio/Makefile.in b/vendor/cfitsio/Makefile.in
new file mode 100644
index 00000000..cf105ca1
--- /dev/null
+++ b/vendor/cfitsio/Makefile.in
@@ -0,0 +1,166 @@
+#
+# 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
+#
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+DESTDIR =
+CFITSIO_LIB = ${DESTDIR}@libdir@
+CFITSIO_INCLUDE = ${DESTDIR}@includedir@
+INSTALL_DIRS = @INSTALL_ROOT@ ${CFITSIO_INCLUDE} ${CFITSIO_LIB} ${CFITSIO_LIB}/pkgconfig
+
+
+SHELL = /bin/sh
+RANLIB = @RANLIB@
+CC = @CC@
+CFLAGS = @CFLAGS@
+SSE_FLAGS = @SSE_FLAGS@
+FC = @FC@
+LDFLAGS = $(CFLAGS)
+DEFS = @DEFS@
+LIBS = @LIBS@
+FLEX = flex
+BISON = bison
+
+SHLIB_LD = @SHLIB_LD@
+SHLIB_SUFFIX = @SHLIB_SUFFIX@
+
+
+CORE_SOURCES = buffers.c cfileio.c checksum.c drvrfile.c drvrmem.c \
+ drvrnet.c drvrsmem.c drvrgsiftp.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 fits_hcompress.c fits_hdecompress.c zuncompress.c zcompress.c \
+ adler32.c crc32.c inffast.c inftrees.c trees.c zutil.c \
+ deflate.c infback.c inflate.c uncompr.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} ${LDFLAGS} -o $@ ${OBJECTS} -lm ${LIBS}
+
+install: libcfitsio.a $(INSTALL_DIRS)
+ @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}/; \
+ /bin/cp cfitsio.pc ${CFITSIO_LIB}/pkgconfig
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(DEFS) $<
+
+swapproc.o: swapproc.c
+ $(CC) -c $(CFLAGS) $(SSE_FLAGS) $(DEFS) $<
+
+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}
+
+fpack: fpack.o fpackutil.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o fpack fpack.o fpackutil.o libcfitsio.a -lm ${LIBS}
+
+funpack: funpack.o fpackutil.o libcfitsio.a ${OBJECTS}
+ ${CC} $(CFLAGS) $(DEFS) -o funpack funpack.o fpackutil.o libcfitsio.a -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 cfitsio.pc config.* configure.lineno
+
+# 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}
+
+cfitsioLibSrcs:
+ @echo ${SOURCES}
+
+# This target actually builds the objects needed for the lib in the above
+# case
+objs: ${CORE_OBJECTS}
+
+$(INSTALL_DIRS):
+ @if [ ! -d $@ ]; then mkdir -p $@; fi
diff --git a/vendor/cfitsio/README b/vendor/cfitsio/README
new file mode 100644
index 00000000..201d53f1
--- /dev/null
+++ b/vendor/cfitsio/README
@@ -0,0 +1,144 @@
+ 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), cfitsio.ps, or cfitsio.pdf 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_xxxx_borland.zip and cfitsiodll_xxxx_vcc.zip, where 'xxxx'
+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.
+
+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
+HEASARC, NASA/GSFC
+email: William.D.Pence@nasa.gov
diff --git a/vendor/cfitsio/README.MacOS b/vendor/cfitsio/README.MacOS
new file mode 100644
index 00000000..9f732870
--- /dev/null
+++ b/vendor/cfitsio/README.MacOS
@@ -0,0 +1,70 @@
+To build CFITSIO library on an Intel Mac as a Universal Binary
+
+Unzip the library:
+- tar xzf cfitsio3060.tar.gz (or whatever version this is)
+
+- cd cfitsio/
+
+- copy the cfitsio-xcodeproj.zip file here
+
+- unzip cfitsio-xcodeproj.zip
+
+- start Xcode and open cfitsio.xcodeproj
+
+- expand the "Targets" menu under "Groups & Files"
+
+- choose one of the following build options:
+
+ * right-click on Build PPC -> Build "Build PPC"
+
+ * right-click on Build i386 -> Build "Build i386"
+
+ * right-click on Build x86_64 -> Build "Build x86_64"
+
+ * right-click on Build Universal -> Build "Build Universal"
+ (Builds all three of the above options, i.e. a Universal Binary
+ usable on ppc, i386, and x86_64 architectures)
+
+ (For some reason clicking on the menu "Build" icon doesn't seem to
+ work correctly, but the right-click menus do).
+
+-------------------------------------------------------
+
+Another way to build the universal binary:
+
+- unpack the cfitsio source code tar file
+- cd cfitsio
+
+Set the CFLAGS environment variable for building a Universal Binary:
+
+ C-Shell variants:
+ setenv CFLAGS "-arch ppc -arch i386 -arch x86_64 -g -O2"
+
+ Bourne Shell variants:
+ export CFLAGS="-arch ppc -arch i386 -arch x86_64 -g -O2"
+
+Then proceed with the standard cfitsio build, i.e.:
+
+- ./configure
+- make
+- make install
+
+
+-------------------------------------------------------
+
+Below, are the old (and now obsolete) instructions for building CFITSIO
+on classic Mac OS-9 or earlier versions:
+
+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.
+
diff --git a/vendor/cfitsio/README.win32 b/vendor/cfitsio/README.win32
new file mode 100644
index 00000000..aaca099a
--- /dev/null
+++ b/vendor/cfitsio/README.win32
@@ -0,0 +1,74 @@
+ Instructions on using CFITSIO on Windows platforms for C programmers
+
+These instructions use a simple DOS-style command window. It is also possible
+to build and use CFITSIO within a GUI programming environment such as Visual
+Studio, but this is not supported here.
+
+===============================================================================
+1. Build the CFITSIO dll library
+
+This step will create the cfitsio.def, cfitsio.dll, and cfitsio.lib files.
+(If you downloaded the CFITSIO .zip file that contains the pre-built binary
+.dll file, then SKIP THIS STEP).
+
+ A. With Microsoft Visual C++:
+
+ 1. Open a DOS command window and execute the vcvars32.bat file that
+ is distributed with older versions of Visual C++, or simply open
+ the Visual C++ command window (e.g., when using Visual Studio 2010).
+
+ 2. Unpack the CFITSIO source files (cfitxxxx.zip) into a new empty directory
+
+ 3. In the DOS command window, cd to that directory and enter the
+ following commands:
+
+ nmake winDumpExts.mak
+ nmake makefile.vcc
+ (ignore the compiler warning messages)
+
+ B: With Borland C++:
+
+ First, follow the instructions provided by Borland to set up
+ the proper environment variables and configure files for the compiler.
+
+ Unpack the cfitsio.zip source file distribution into a suitable directory.
+
+ In a DOS command window, cd to that directory and then execute the
+ makepc.bat batch file on the command line to build the CFITSIO library,
+ and the testprog and cookbook sample programs.
+
+===============================================================================
+2. Test the CFITSIO library with Visual C++
+
+ Compile and link the testprog.c test program. When using Visual Studio,
+ the command is:
+
+ cl /MD testprog.c cfitsio.lib
+
+
+ This will create the testprog.exe executable program. Running this
+ program should print out a long series of diagnostic messages
+ that should end with "Status = 0; OK - no error"
+
+===============================================================================
+3. Compile and link an application program that calls CFITSIO routines
+ with Visual C++
+
+ Include the fitsio.h and longnam.h header files in the C source code.
+
+ Link the program with the cfitsio.lib file:
+
+ cl /MD your_program.c cfitsio.lib
+
+
+ NOTE: The /MD command line switch must be specified on the cl
+ command line to force the compiler/linker to use the
+ appropriete runtime library. If this switch is omitted, then
+ the fits_report_error function in CFITSIO will likely crash.
+
+ When building programs in the Visual Studio environment, one
+ can force the equivalent of the /MD switch by selecting
+ 'Settings...' under the 'Project' menu, then click on the C/C++
+ tab and select the 'Code Generator' category. Then under 'User
+ Run-time Library' select 'Multithreaded DLL'.
+
diff --git a/vendor/cfitsio/adler32.c b/vendor/cfitsio/adler32.c
new file mode 100644
index 00000000..172de603
--- /dev/null
+++ b/vendor/cfitsio/adler32.c
@@ -0,0 +1,167 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2007 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 >= BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
diff --git a/vendor/cfitsio/buffers.c b/vendor/cfitsio/buffers.c
new file mode 100644
index 00000000..8d80f462
--- /dev/null
+++ b/vendor/cfitsio/buffers.c
@@ -0,0 +1,1371 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffmbyt(fitsfile *fptr, /* I - FITS file pointer */
+ LONGLONG 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 = (long) (bytepos / IOBUFLEN); /* zero-indexed record number */
+
+ /* if this is not the current record, then load it */
+ if ( ((fptr->Fptr)->curbuf < 0) ||
+ (record != (fptr->Fptr)->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 */
+ LONGLONG 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;
+ LONGLONG 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 = (long) nbytes;
+
+ if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */
+ { /* so reload the last one that was used */
+ ffldrc(fptr, (long) (((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 = (fptr->Fptr)->bufrecnum[nbuff]; /* starting record */
+ recend = (long) ((filepos + nbytes - 1) / IOBUFLEN); /* ending record */
+
+ /* bufpos is the starting position within the IO buffer */
+ bufpos = (long) (filepos - ((LONGLONG)recstart * IOBUFLEN));
+ nspace = IOBUFLEN - bufpos; /* amount of space left in the buffer */
+
+ if (nspace)
+ { /* fill up the IO buffer */
+ memcpy((fptr->Fptr)->iobuffer + (nbuff * IOBUFLEN) + bufpos, cptr, nspace);
+ ntodo -= nspace; /* decrement remaining number of bytes */
+ cptr += nspace; /* increment user buffer pointer */
+ filepos += nspace; /* increment file position pointer */
+ (fptr->Fptr)->dirty[nbuff] = TRUE; /* mark record as having been modified */
+ }
+
+ for (ii = 0; ii < NIOBUF; ii++) /* flush any affected buffers to disk */
+ {
+ if ((fptr->Fptr)->bufrecnum[ii] >= recstart
+ && (fptr->Fptr)->bufrecnum[ii] <= recend )
+ {
+ if ((fptr->Fptr)->dirty[ii]) /* flush modified buffer to disk */
+ ffbfwt(fptr->Fptr, ii, status);
+
+ (fptr->Fptr)->bufrecnum[ii] = -1; /* 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((fptr->Fptr)->iobuffer + (nbuff * IOBUFLEN), 32, IOBUFLEN); /* blank fill */
+ else
+ memset((fptr->Fptr)->iobuffer + (nbuff * IOBUFLEN), 0, IOBUFLEN); /* zero fill */
+ }
+ else
+ {
+ /* read next record */
+ ffread(fptr->Fptr, IOBUFLEN, (fptr->Fptr)->iobuffer + (nbuff * IOBUFLEN), status);
+ (fptr->Fptr)->io_pos += IOBUFLEN;
+ }
+
+ /* copy remaining bytes from user buffer into current IO buffer */
+ memcpy((fptr->Fptr)->iobuffer + (nbuff * IOBUFLEN), cptr, ntodo);
+ (fptr->Fptr)->dirty[nbuff] = TRUE; /* mark record as having been modified */
+ (fptr->Fptr)->bufrecnum[nbuff] = recend; /* record number */
+
+ (fptr->Fptr)->logfilesize = maxvalue((fptr->Fptr)->logfilesize,
+ (LONGLONG)(recend + 1) * IOBUFLEN);
+ (fptr->Fptr)->bytepos = filepos + nwrite + ntodo;
+ }
+ else
+ {
+ /* bufpos is the starting position in IO buffer */
+ bufpos = (long) ((fptr->Fptr)->bytepos - ((LONGLONG)(fptr->Fptr)->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((fptr->Fptr)->iobuffer + ((fptr->Fptr)->curbuf * IOBUFLEN) + bufpos, cptr, nwrite);
+ ntodo -= nwrite; /* decrement remaining number of bytes */
+ cptr += nwrite;
+ (fptr->Fptr)->bytepos += nwrite; /* increment file position pointer */
+ (fptr->Fptr)->dirty[(fptr->Fptr)->curbuf] = TRUE; /* mark record as modified */
+
+ if (ntodo) /* load next record into a buffer */
+ {
+ ffldrc(fptr, (long) ((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, (long) (((fptr->Fptr)->bytepos) / IOBUFLEN), REPORT_EOF, status);
+ }
+
+ cptr = (char *)buffer;
+ bcurrent = (fptr->Fptr)->curbuf; /* number of the current IO buffer */
+ record = (fptr->Fptr)->bufrecnum[bcurrent]; /* zero-indexed record number */
+ bufpos = (long) ((fptr->Fptr)->bytepos - ((LONGLONG)record * IOBUFLEN)); /* start pos */
+ nspace = IOBUFLEN - bufpos; /* amount of space left in buffer */
+ ioptr = (fptr->Fptr)->iobuffer + (bcurrent * IOBUFLEN) + 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 */
+ {
+ (fptr->Fptr)->dirty[bcurrent] = TRUE; /* mark record as having been modified */
+ record++;
+ ffldrc(fptr, record, IGNORE_EOF, status); /* load next record */
+ bcurrent = (fptr->Fptr)->curbuf;
+ ioptr = (fptr->Fptr)->iobuffer + (bcurrent * IOBUFLEN);
+
+ 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? */
+ {
+ (fptr->Fptr)->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 = (fptr->Fptr)->iobuffer + (bcurrent * IOBUFLEN) + 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 */
+ {
+ (fptr->Fptr)->dirty[bcurrent] = TRUE; /* mark record as having been modified */
+ record++;
+ ffldrc(fptr, record, IGNORE_EOF, status); /* load next record */
+ bcurrent = (fptr->Fptr)->curbuf;
+ ioptr = (fptr->Fptr)->iobuffer + (bcurrent * IOBUFLEN);
+
+ nwrite = gsize - nwrite;
+ memcpy(ioptr, cptr, nwrite);
+ }
+
+ (fptr->Fptr)->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 */
+ LONGLONG 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;
+ LONGLONG 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 = (long) (filepos / IOBUFLEN); /* starting record */
+ recend = (long) ((filepos + nbytes - 1) / IOBUFLEN); /* ending record */
+
+ for (ii = 0; ii < NIOBUF; ii++) /* flush any affected buffers to disk */
+ {
+ if ((fptr->Fptr)->dirty[ii] &&
+ (fptr->Fptr)->bufrecnum[ii] >= recstart && (fptr->Fptr)->bufrecnum[ii] <= recend)
+ {
+ ffbfwt(fptr->Fptr, 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, (long) 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, (long) (((fptr->Fptr)->bytepos) / IOBUFLEN), REPORT_EOF, status);
+ }
+
+ /* bufpos is the starting position in IO buffer */
+ bufpos = (long) ((fptr->Fptr)->bytepos - ((LONGLONG)(fptr->Fptr)->bufrecnum[(fptr->Fptr)->curbuf] *
+ IOBUFLEN));
+ nspace = IOBUFLEN - bufpos; /* amount of space left in the buffer */
+
+ ntodo = (long) nbytes;
+ while (ntodo)
+ {
+ nread = minvalue(ntodo, nspace);
+
+ /* copy bytes from IO buffer to user's buffer */
+ memcpy(cptr, (fptr->Fptr)->iobuffer + ((fptr->Fptr)->curbuf * IOBUFLEN) + 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, (long) ((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, (long) (((fptr->Fptr)->bytepos) / IOBUFLEN), REPORT_EOF, status);
+ }
+
+ cptr = (char *)buffer;
+ bcurrent = (fptr->Fptr)->curbuf; /* number of the current IO buffer */
+ record = (fptr->Fptr)->bufrecnum[bcurrent]; /* zero-indexed record number */
+ bufpos = (long) ((fptr->Fptr)->bytepos - ((LONGLONG)record * IOBUFLEN)); /* start pos */
+ nspace = IOBUFLEN - bufpos; /* amount of space left in buffer */
+ ioptr = (fptr->Fptr)->iobuffer + (bcurrent * IOBUFLEN) + 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 = (fptr->Fptr)->iobuffer + (bcurrent * IOBUFLEN);
+
+ 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 = (fptr->Fptr)->iobuffer + (bcurrent * IOBUFLEN) + 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 = (fptr->Fptr)->iobuffer + (bcurrent * IOBUFLEN);
+
+ 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;
+ LONGLONG 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 = (fptr->Fptr)->ageindex[ibuff];
+ if (record == (fptr->Fptr)->bufrecnum[nbuff]) {
+ goto updatebuf; /* use 'goto' for efficiency */
+ }
+ }
+
+ /* record is not already loaded */
+ rstart = (LONGLONG)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 ((fptr->Fptr)->dirty[nbuff])
+ ffbfwt(fptr->Fptr, 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((fptr->Fptr)->iobuffer + (nbuff * IOBUFLEN), 32, IOBUFLEN); /* blank fill */
+ else
+ memset((fptr->Fptr)->iobuffer + (nbuff * IOBUFLEN), 0, IOBUFLEN); /* zero fill */
+
+ (fptr->Fptr)->logfilesize = maxvalue((fptr->Fptr)->logfilesize,
+ rstart + IOBUFLEN);
+
+ (fptr->Fptr)->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, (fptr->Fptr)->iobuffer + (nbuff * IOBUFLEN), status);
+ (fptr->Fptr)->io_pos = rstart + IOBUFLEN; /* set new IO position */
+ }
+
+ (fptr->Fptr)->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 ((fptr->Fptr)->ageindex[ibuff] == nbuff)
+ break;
+ }
+
+ /* increment the age of all the buffers that were younger than it */
+ for (ibuff++; ibuff < NIOBUF; ibuff++)
+ (fptr->Fptr)->ageindex[ibuff - 1] = (fptr->Fptr)->ageindex[ibuff];
+
+ (fptr->Fptr)->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
+*/
+ return(*nbuff = (fptr->Fptr)->ageindex[0]); /* return oldest 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++)
+ {
+ /* flush modified buffer to disk */
+ if ((fptr->Fptr)->bufrecnum[ii] >= 0 &&(fptr->Fptr)->dirty[ii])
+ ffbfwt(fptr->Fptr, ii, status);
+
+ if (clearbuf)
+ (fptr->Fptr)->bufrecnum[ii] = -1; /* 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 ( (LONGLONG) (fptr->Fptr)->bufrecnum[ii] * IOBUFLEN >= fptr->Fptr->filesize)
+ {
+ (fptr->Fptr)->bufrecnum[ii] = -1; /* set contents of buffer as undefined */
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffbfwt(FITSfile *Fptr, /* I - FITS file pointer */
+ 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.
+*/
+ int ii,ibuff;
+ long jj, irec, minrec, nloop;
+ LONGLONG filepos;
+
+ static char zeros[IOBUFLEN]; /* initialized to zero by default */
+
+ if (!(Fptr->writemode) )
+ {
+ ffpmsg("Error: trying to write to READONLY file.");
+ if (Fptr->driver == 8) { /* gzip compressed file */
+ ffpmsg("Cannot write to a GZIP or COMPRESS compressed file.");
+ }
+ Fptr->dirty[nbuff] = FALSE; /* reset buffer status to prevent later probs */
+ *status = READONLY_FILE;
+ return(*status);
+ }
+
+ filepos = (LONGLONG)Fptr->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, Fptr->iobuffer + (nbuff * IOBUFLEN), status);
+ Fptr->io_pos = filepos + IOBUFLEN;
+
+ if (filepos == Fptr->filesize) /* appended new record? */
+ Fptr->filesize += IOBUFLEN; /* increment the file size */
+
+ Fptr->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 = (long) (Fptr->filesize / IOBUFLEN);
+
+ /* write lowest record beyond the EOF first */
+
+ irec = Fptr->bufrecnum[nbuff]; /* initially point to the requested buffer */
+ ibuff = nbuff;
+
+ for (ii = 0; ii < NIOBUF; ii++)
+ {
+ if (Fptr->bufrecnum[ii] >= minrec &&
+ Fptr->bufrecnum[ii] < irec)
+ {
+ irec = Fptr->bufrecnum[ii]; /* found a lower record */
+ ibuff = ii;
+ }
+ }
+
+ filepos = (LONGLONG)irec * IOBUFLEN; /* byte offset of record in file */
+
+ /* append 1 or more fill records if necessary */
+ if (filepos > Fptr->filesize)
+ {
+ nloop = (long) ((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, Fptr->iobuffer + (ibuff * IOBUFLEN), status);
+ Fptr->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 typecode, bytesperpixel;
+
+ /* 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);
+
+ if ((fptr->Fptr)->hdutype == IMAGE_HDU ) /* calc pixels per buffer size */
+ {
+ /* image pixels are in column 2 of the 'table' */
+ ffgtcl(fptr, 2, &typecode, NULL, NULL, status);
+ bytesperpixel = typecode / 10;
+ *ndata = ((NIOBUF - 1) * IOBUFLEN) / bytesperpixel;
+ }
+ else /* calc number of rows that fit in buffers */
+ {
+ *ndata = (long) (((NIOBUF - 1) * IOBUFLEN) / maxvalue(1,
+ (fptr->Fptr)->rowlength));
+ *ndata = maxvalue(1, *ndata);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtbb(fitsfile *fptr, /* I - FITS file pointer */
+ LONGLONG firstrow, /* I - starting row (1 = first row) */
+ LONGLONG firstchar, /* I - starting byte in row (1=first) */
+ LONGLONG 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.
+*/
+{
+ LONGLONG bytepos, 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 */
+ LONGLONG 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.
+*/
+{
+ LONGLONG 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 */
+ LONGLONG 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.
+*/
+{
+ LONGLONG 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 */
+ LONGLONG 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.
+*/
+{
+ LONGLONG 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 */
+ LONGLONG 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.
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+*/
+{
+ LONGLONG 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 */
+ LONGLONG 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.
+*/
+{
+ LONGLONG 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 */
+ LONGLONG 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.
+*/
+{
+ LONGLONG 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 */
+ LONGLONG firstrow, /* I - starting row (1 = first row) */
+ LONGLONG firstchar, /* I - starting byte in row (1=first) */
+ LONGLONG 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.
+*/
+{
+ LONGLONG bytepos, 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 %.0f new rows in table.",
+ (double) nrows);
+ ffpmsg(message);
+ return(*status);
+ }
+ }
+ else
+ {
+ /* manally update heap starting address */
+ (fptr->Fptr)->heapstart +=
+ ((LONGLONG)(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/vendor/cfitsio/cfileio.c b/vendor/cfitsio/cfileio.c
new file mode 100644
index 00000000..168ff591
--- /dev/null
+++ b/vendor/cfitsio/cfileio.c
@@ -0,0 +1,6965 @@
+/* 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 24 /* 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, LONGLONG size);
+ int (*close)(int drivehandle);
+ int (*remove)(char *filename);
+ int (*size)(int drivehandle, LONGLONG *size);
+ int (*flush)(int drivehandle);
+ int (*seek)(int drivehandle, LONGLONG 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 */
+
+static int pixel_filter_helper(fitsfile **fptr, char *outfile,
+ char *expr, int *status);
+
+
+#ifdef _REENTRANT
+
+pthread_mutex_t Fitsio_InitLock = PTHREAD_MUTEX_INITIALIZER;
+
+#endif
+
+/*--------------------------------------------------------------------------*/
+int fitsio_init_lock(void)
+{
+ static int need_to_init = 1;
+
+#ifdef _REENTRANT
+
+ pthread_mutexattr_t mutex_init;
+
+ FFLOCK1(Fitsio_InitLock);
+
+ if (need_to_init) {
+
+ /* Init the main fitsio lock here since we need a a recursive lock */
+
+ assert(!pthread_mutexattr_init(&mutex_init));
+#ifdef linux
+ assert(!pthread_mutexattr_settype(&mutex_init,
+ PTHREAD_MUTEX_RECURSIVE_NP));
+#else
+ assert(!pthread_mutexattr_settype(&mutex_init,
+ PTHREAD_MUTEX_RECURSIVE));
+#endif
+
+ assert(!pthread_mutex_init(&Fitsio_Lock,&mutex_init));
+ need_to_init = 0;
+ }
+
+ FFUNLOCK1(Fitsio_InitLock);
+
+#endif
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+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 ii, driver, handle, hdutyp, slen, movetotype, extvers, extnum;
+ char extname[FLEN_VALUE];
+ LONGLONG 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 */
+ fits_parse_input_url(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 */
+ FFLOCK; /* lock this while searching for vacant handle */
+ *status = mem_openmem( buffptr, buffsize,deltasize,
+ mem_realloc, &handle);
+ FFUNLOCK;
+
+ 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 = (LONGLONG *) calloc(1001, sizeof(LONGLONG));
+
+ 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);
+ }
+
+ /* mem for file I/O buffers */
+ ((*fptr)->Fptr)->iobuffer = (char *) calloc(NIOBUF, IOBUFLEN);
+
+ if ( !(((*fptr)->Fptr)->iobuffer) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for iobuffer array: (ffomem)");
+ ffpmsg(url);
+ free( ((*fptr)->Fptr)->headstart); /* free memory for headstart array */
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* initialize the ageindex array (relative age of the I/O buffers) */
+ /* and initialize the bufrecnum array as being empty */
+ for (ii = 0; ii < NIOBUF; ii++) {
+ ((*fptr)->Fptr)->ageindex[ii] = ii;
+ ((*fptr)->Fptr)->bufrecnum[ii] = -1;
+ }
+
+ /* 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 ffopentest(double version, /* I - CFITSIO version number, from the */
+ /* application program (fitsio.h file) */
+ 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.
+ First test that the version of fitsio.h used to build the CFITSIO library
+ is the same as the version used in building the application program that
+ links to the library.
+*/
+{
+ if (version != CFITSIO_VERSION)
+ {
+ printf("ERROR: Mismatch in the version of the fitsio.h include file used to build\n");
+ printf("the CFITSIO library, and the version included by the application program:\n");
+ printf(" Version used to build the CFITSIO library = %f\n",CFITSIO_VERSION);
+ printf(" Version included by the application program = %f\n",version);
+
+ *status = FILE_NOT_OPENED;
+ return(*status);
+ }
+
+ /* now call the normal file open routine */
+ ffopen(fptr, name, mode, status);
+ 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.
+*/
+{
+ fitsfile *newptr;
+ int ii, driver, hdutyp, hdunum, slen, writecopy, isopen;
+ LONGLONG filesize;
+ long rownum, nrows, goodrows;
+ int extnum, extvers, handle, movetotype, tstatus = 0, only_one = 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], pixfilter[FLEN_FILENAME];
+ char histfilename[FLEN_FILENAME];
+ char filtfilename[FLEN_FILENAME], compspec[FLEN_FILENAME];
+ char wtcol[FLEN_VALUE];
+ char minname[4][FLEN_VALUE], maxname[4][FLEN_VALUE];
+ char binname[4][FLEN_VALUE];
+
+ 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 */
+
+ if (strlen(url) > FLEN_FILENAME - 1) {
+ ffpmsg("Name of file to open is too long. (ffopen)");
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ strcpy(infile,url);
+ strcpy(urltype, "file://");
+ outfile[0] = '\0';
+ extspec[0] = '\0';
+ binspec[0] = '\0';
+ colspec[0] = '\0';
+ rowfilter[0] = '\0';
+ pixfilter[0] = '\0';
+ compspec[0] = '\0';
+ }
+ else
+ {
+ /* parse the input file specification */
+
+ /* NOTE: This routine tests that all the strings do not */
+ /* overflow the standard buffer sizes (FLEN_FILENAME, etc.) */
+ /* therefore in general we do not have to worry about buffer */
+ /* overflow of any of the returned strings. */
+
+ /* call the newer version of this parsing routine that supports 'compspec' */
+ ffifile2(url, urltype, infile, outfile, extspec,
+ rowfilter, binspec, colspec, pixfilter, compspec, status);
+ }
+
+ if (*status > 0)
+ {
+ ffpmsg("could not parse the input filename: (ffopen)");
+ ffpmsg(url);
+ return(*status);
+ }
+
+ imagecolname[0] = '\0';
+ rowexpress[0] = '\0';
+
+ if (*extspec)
+ {
+ slen = strlen(extspec);
+ if (extspec[slen - 1] == '#') { /* special symbol to mean only copy this extension */
+ extspec[slen - 1] = '\0';
+ only_one = 1;
+ }
+
+ /* 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 || *pixfilter))
+ {
+ /* 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 */
+ /*-------------------------------------------------------------------*/
+
+ FFLOCK;
+ if (fits_already_open(fptr, url, urltype, infile, extspec, rowfilter,
+ binspec, colspec, mode, &isopen, status) > 0)
+ {
+ FFUNLOCK;
+ return(*status);
+ }
+ FFUNLOCK;
+
+ 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:, gsiftp:, 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)
+ {
+ FFLOCK; /* lock this while searching for vacant handle */
+ *status = (*driverTable[driver].open)(infile, mode, &handle);
+ FFUNLOCK;
+ 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 = (LONGLONG *) calloc(1001, sizeof(LONGLONG));
+
+ 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);
+ }
+
+ /* mem for file I/O buffers */
+ ((*fptr)->Fptr)->iobuffer = (char *) calloc(NIOBUF, IOBUFLEN);
+
+ if ( !(((*fptr)->Fptr)->iobuffer) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for iobuffer array: (ffopen)");
+ ffpmsg(url);
+ free( ((*fptr)->Fptr)->headstart); /* free memory for headstart array */
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* initialize the ageindex array (relative age of the I/O buffers) */
+ /* and initialize the bufrecnum array as being empty */
+ for (ii = 0; ii < NIOBUF; ii++) {
+ ((*fptr)->Fptr)->ageindex[ii] = ii;
+ ((*fptr)->Fptr)->bufrecnum[ii] = -1;
+ }
+
+ /* 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 */
+ ((*fptr)->Fptr)->only_one = only_one; /* flag denoting only copy single extension */
+
+ 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 && !(*pixfilter) )
+ 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. */
+
+ /* 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 (fits_copy_cell2image(*fptr, newptr, 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);
+ }
+
+ /* close the original file and set fptr to the new image */
+ ffclos(*fptr, status);
+
+ *fptr = newptr; /* reset the pointer to the new table */
+
+ writecopy = 1; /* we are now dealing with a copy of the original file */
+
+ /* add some HISTORY; fits_copy_image_cell also wrote HISTORY keywords */
+
+/* disable this; leave it up to calling routine to write any 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);
+ }
+ }
+ 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 && !(*pixfilter) )
+ 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. */
+ ffhist2(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);
+ }
+
+ if (*pixfilter)
+ {
+ if (*histfilename)
+ strcpy(outfile, histfilename); /* the original outfile name */
+ else
+ strcpy(outfile, "mem://_4"); /* create in memory */
+ /* if not already copied the file */
+
+ /* Ensure type of HDU is consistent with pixel filtering */
+ fits_get_hdu_type(*fptr, &hdutyp, status); /* get type of HDU */
+ if (hdutyp == IMAGE_HDU) {
+
+ pixel_filter_helper(fptr, outfile, pixfilter, status);
+
+ if (*status > 0) {
+ ffpmsg("pixel filtering of input image failed (ffopen)");
+ ffpmsg(" while trying to execute the following:");
+ ffpmsg(pixfilter);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ return(*status);
+ }
+
+ /* write history records */
+ ffphis(*fptr,
+ "CFITSIO used the following expression to create this image:",
+ status);
+ ffphis(*fptr, name, status);
+ }
+ else
+ {
+ ffpmsg("cannot use pixel filter on non-IMAGE HDU");
+ ffpmsg(pixfilter);
+ ffclos(*fptr, status);
+ *fptr = 0; /* return null file pointer */
+ *status = NOT_IMAGE;
+ return(*status);
+ }
+ }
+
+ /* parse and save image compression specification, if given */
+ if (*compspec) {
+ ffparsecompspec(*fptr, compspec, 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);
+
+ FFLOCK;
+ for (ii = 0; ii < NMAXFILES; ii++) {
+ if (FptrTable[ii] == 0) {
+ FptrTable[ii] = Fptr;
+ break;
+ }
+ }
+ FFUNLOCK;
+ 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;
+
+ FFLOCK;
+ for (ii = 0; ii < NMAXFILES; ii++) {
+ if (FptrTable[ii] == Fptr) {
+ FptrTable[ii] = 0;
+ break;
+ }
+ }
+ FFUNLOCK;
+ 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.
+*/
+
+ /* the input strings must not exceed the standard lengths */
+ /* of FLEN_FILENAME, MAX_PREFIX_LEN, etc. */
+
+ /*
+ 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;
+
+/* When opening a file with readonly access then we simply let
+ the operating system open the file again, instead of using the CFITSIO
+ trick of attaching to the previously opened file. This is required
+ if CFITSIO is running in a multi-threaded environment, because 2 different
+ threads cannot share the same FITSfile pointer.
+
+ If the file is opened/reopened with write access, then the file MUST
+ only be physically opened once..
+*/
+ if (mode == 0)
+ return(*status);
+
+ if(strcasecmp(urltype,"FILE://") == 0)
+ {
+ fits_path2url(infile,tmpinfile,status);
+
+ if(tmpinfile[0] != '/')
+ {
+ fits_get_cwd(cwd,status);
+ strcat(cwd,"/");
+
+ if (strlen(cwd) + strlen(tmpinfile) > FLEN_FILENAME-1) {
+ ffpmsg("File name is too long. (fits_already_open)");
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ 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];
+
+ fits_parse_input_url(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 (!strncmp(urltype, "gsiftp", 6) )
+ iscopy = 1; /* copied file using gsiftp 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 = -1, testnum, deletecol = 0, savecol = 0;
+ int numcols = 0, *colindex = 0, tstatus = 0, inparen;
+ char *cptr, *cptr2, *cptr3, clause[FLEN_FILENAME], keyname[FLEN_KEYWORD];
+ char colname[FLEN_VALUE], oldname[FLEN_VALUE], colformat[FLEN_VALUE];
+ char *file_expr = NULL, testname[FLEN_VALUE], card[FLEN_CARD];
+
+ 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, if the 'only_one' flag is not set */
+ if (!((*fptr)->Fptr)->only_one) {
+ 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);
+ }
+
+
+ } else {
+ /* only copy the primary array and the designated table extension */
+ fits_movabs_hdu(*fptr, 1, NULL, status);
+ fits_copy_hdu(*fptr, newptr, 0, status);
+ fits_movabs_hdu(*fptr, hdunum, NULL, status);
+ fits_copy_hdu(*fptr, newptr, 0, status);
+ if (*status > 0)
+ {
+ ffclos(newptr, status);
+ ffpmsg("failed to copy all HDUs from input file (ffedit_columns)");
+ return(*status);
+ }
+ hdunum = 2;
+ }
+
+ /* 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 */
+
+ /* as of July 2012, the CFITSIO column filter syntax was modified */
+ /* so that commas may be used to separate clauses, as well as semi-colons. */
+ /* This was done because users cannot enter the semi-colon in the HEASARC's */
+ /* Hera on-line data processing system due for computer security reasons. */
+ /* Therefore, we must convert those commas back to semi-colons here, but we */
+ /* must not convert any columns that occur within parenthesies. */
+
+ cptr2 = cptr;
+ inparen = 0; /* flag to indicate we are within a parenthetical clause */
+
+ while (*cptr2) {
+ if (*cptr2 == '(') {
+ inparen++; /* increment the nested-parenthesis counter */
+ } else if (*cptr2 == ')') {
+ inparen--; /* decrement the nested-parenthesis counter */
+ } else if (*cptr2 == ',' && !inparen) {
+ *cptr2 = ';'; /* replace this comma with a semi-colon */
+ }
+ cptr2++;
+ }
+
+ /* 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--;
+ colnum = -1;
+ }
+ else
+ {
+ ffcmsg(); /* clear previous error message from ffgcno */
+ /* 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 this is a keyword of the form
+ #KEYWORD#
+ then transform to the form
+ #KEYWORDn
+ where n is the previously used column number
+ */
+ if (colname[0] == '#' &&
+ strstr(colname+1, "#") == (colname + strlen(colname) - 1))
+ {
+ if (colnum <= 0)
+ {
+ ffpmsg("The keyword name:");
+ ffpmsg(colname);
+ ffpmsg("is invalid unless a column has been previously");
+ ffpmsg("created or editted by a calculator command");
+ return(*status = URL_PARSE_ERROR);
+ }
+ colname[strlen(colname)-1] = '\0';
+ /* Make keyword name and put it in oldname */
+ ffkeyn(colname+1, colnum, oldname, status);
+ if (*status) return (*status);
+ /* Re-copy back into colname */
+ strcpy(colname+1,oldname);
+ }
+ else if (strstr(colname, "#") == (colname + strlen(colname) - 1))
+ {
+ /* colname is of the form "NAME#"; if
+ a) colnum is defined, and
+ b) a column with literal name "NAME#" does not exist, and
+ c) a keyword with name "NAMEn" (where n=colnum) exists, then
+ transfrom the colname string to "NAMEn", otherwise
+ do nothing.
+ */
+ if (colnum > 0) { /* colnum must be defined */
+ tstatus = 0;
+ ffgcno(*fptr, CASEINSEN, colname, &testnum, &tstatus);
+ if (tstatus != 0 && tstatus != COL_NOT_UNIQUE)
+ {
+ /* OK, column doesn't exist, now see if keyword exists */
+ ffcmsg(); /* clear previous error message from ffgcno */
+ strcpy(testname, colname);
+ testname[strlen(testname)-1] = '\0';
+ /* Make keyword name and put it in oldname */
+ ffkeyn(testname, colnum, oldname, status);
+ if (*status) return (*status);
+
+ tstatus = 0;
+ if (!fits_read_card(*fptr, oldname, card, &tstatus)) {
+ /* Keyword does exist; copy real name back into colname */
+ strcpy(colname,oldname);
+ }
+ }
+ }
+ }
+
+ /* 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, &testnum, status);
+
+ while (*status == COL_NOT_UNIQUE)
+ {
+ /* the column name contained wild cards, and it */
+ /* matches more than one column in the table. */
+
+ colnum = testnum;
+
+ /* keep this column in the output file */
+ savecol = 1;
+
+ if (!colindex)
+ colindex = (int *) calloc(999, sizeof(int));
+
+ colindex[colnum - 1] = 1; /* flag this column number */
+
+ /* look for other matching column names */
+ ffgcno(*fptr, CASEINSEN, colname, &testnum, status);
+
+ if (*status == COL_NOT_FOUND)
+ *status = 999; /* temporary status flag value */
+ }
+
+ if (*status <= 0)
+ {
+ colnum = testnum;
+
+ /* keep this column in the output file */
+ savecol = 1;
+
+ if (!colindex)
+ colindex = (int *) 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 = (int *) calloc(999, sizeof(int));
+
+ colindex[colnum - 1] = 1; /* flag this column number */
+ }
+ else
+ {
+ /* try renaming a keyword */
+ ffcmsg(); /* clear error message stack */
+ *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 */
+ if (fits_calculator(*fptr, cptr2, *fptr, oldname, colformat,
+ status) > 0) {
+
+ ffpmsg("Unable to calculate expression");
+ return(*status);
+ }
+
+ /* test if this is a column and not a keyword */
+ tstatus = 0;
+ ffgcno(*fptr, CASEINSEN, oldname, &testnum, &tstatus);
+ if (tstatus == 0)
+ {
+ /* keep this column in the output file */
+ colnum = testnum;
+ savecol = 1;
+
+ if (!colindex)
+ colindex = (int *) calloc(999, sizeof(int));
+
+ colindex[colnum - 1] = 1;
+ if (colnum > numcols)numcols++;
+ }
+ else
+ {
+ ffcmsg(); /* clear the error message stack */
+ }
+ }
+ }
+ }
+ }
+
+ 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_cell2image(
+ fitsfile *fptr, /* I - point to input table */
+ fitsfile *newptr, /* O - existing output file; new image HDU
+ will be appended to it */
+ char *colname, /* I - column name / number containing the image*/
+ long rownum, /* I - number of the row containing the image */
+ int *status) /* IO - error status */
+
+/*
+ Copy a table cell of a given row and column into an image extension.
+ The output file must already have been created. A new image
+ extension will be created in that file.
+
+ This routine was written by Craig Markwardt, GSFC
+*/
+
+{
+ unsigned char buffer[30000];
+ int hdutype, colnum, typecode, bitpix, naxis, maxelem, tstatus;
+ LONGLONG naxes[9], nbytes, firstbyte, ntodo;
+ LONGLONG repeat, startpos, elemnum, rowlen, tnull;
+ long twidth, incre;
+ double scale, zero;
+ char tform[20];
+ char card[FLEN_CARD];
+ char templt[FLEN_CARD] = "";
+
+ /* Table-to-image keyword translation table */
+ /* INPUT OUTPUT */
+ /* 01234567 01234567 */
+ char *patterns[][2] = {{"TSCALn", "BSCALE" }, /* Standard FITS keywords */
+ {"TZEROn", "BZERO" },
+ {"TUNITn", "BUNIT" },
+ {"TNULLn", "BLANK" },
+ {"TDMINn", "DATAMIN" },
+ {"TDMAXn", "DATAMAX" },
+ {"iCTYPn", "CTYPEi" }, /* Coordinate labels */
+ {"iCTYna", "CTYPEia" },
+ {"iCUNIn", "CUNITi" }, /* Coordinate units */
+ {"iCUNna", "CUNITia" },
+ {"iCRVLn", "CRVALi" }, /* WCS keywords */
+ {"iCRVna", "CRVALia" },
+ {"iCDLTn", "CDELTi" },
+ {"iCDEna", "CDELTia" },
+ {"iCRPXn", "CRPIXi" },
+ {"iCRPna", "CRPIXia" },
+ {"ijPCna", "PCi_ja" },
+ {"ijCDna", "CDi_ja" },
+ {"iVn_ma", "PVi_ma" },
+ {"iSn_ma", "PSi_ma" },
+ {"iCRDna", "CRDERia" },
+ {"iCSYna", "CSYERia" },
+ {"iCROTn", "CROTAi" },
+ {"WCAXna", "WCSAXESa"},
+ {"WCSNna", "WCSNAMEa"},
+
+ {"LONPna", "LONPOLEa"},
+ {"LATPna", "LATPOLEa"},
+ {"EQUIna", "EQUINOXa"},
+ {"MJDOBn", "MJD-OBS" },
+ {"MJDAn", "MJD-AVG" },
+ {"RADEna", "RADESYSa"},
+ {"iCNAna", "CNAMEia" },
+ {"DAVGn", "DATE-AVG"},
+
+ /* Delete table keywords related to other columns */
+ {"T????#a", "-" },
+ {"TC??#a", "-" },
+ {"TWCS#a", "-" },
+ {"TDIM#", "-" },
+ {"iCTYPm", "-" },
+ {"iCUNIm", "-" },
+ {"iCRVLm", "-" },
+ {"iCDLTm", "-" },
+ {"iCRPXm", "-" },
+ {"iCTYma", "-" },
+ {"iCUNma", "-" },
+ {"iCRVma", "-" },
+ {"iCDEma", "-" },
+ {"iCRPma", "-" },
+ {"ijPCma", "-" },
+ {"ijCDma", "-" },
+ {"iVm_ma", "-" },
+ {"iSm_ma", "-" },
+ {"iCRDma", "-" },
+ {"iCSYma", "-" },
+ {"iCROTm", "-" },
+ {"WCAXma", "-" },
+ {"WCSNma", "-" },
+
+ {"LONPma", "-" },
+ {"LATPma", "-" },
+ {"EQUIma", "-" },
+ {"MJDOBm", "-" },
+ {"MJDAm", "-" },
+ {"RADEma", "-" },
+ {"iCNAma", "-" },
+ {"DAVGm", "-" },
+
+ {"EXTNAME", "-" }, /* Remove structural keywords*/
+ {"EXTVER", "-" },
+ {"EXTLEVEL","-" },
+ {"CHECKSUM","-" },
+ {"DATASUM", "-" },
+
+ {"*", "+" }}; /* copy all other keywords */
+ int npat;
+
+ 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 ( ffgcprll(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);
+
+ /* get the actual column name, in case a column number was given */
+ ffkeyn("", colnum, templt, &tstatus);
+ ffgcnn(fptr, CASEINSEN, templt, colname, &colnum, &tstatus);
+
+ 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] = repeat;
+ }
+ else
+ {
+ /* get the dimensions of the image */
+ ffgtdmll(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 = repeat;
+ }
+ else if (typecode == TSHORT)
+ {
+ bitpix = SHORT_IMG;
+ nbytes = repeat * 2;
+ }
+ else if (typecode == TLONG)
+ {
+ bitpix = LONG_IMG;
+ nbytes = repeat * 4;
+ }
+ else if (typecode == TFLOAT)
+ {
+ bitpix = FLOAT_IMG;
+ nbytes = repeat * 4;
+ }
+ else if (typecode == TDOUBLE)
+ {
+ bitpix = DOUBLE_IMG;
+ nbytes = repeat * 8;
+ }
+ else if (typecode == TLONGLONG)
+ {
+ bitpix = LONGLONG_IMG;
+ nbytes = repeat * 8;
+ }
+ else if (typecode == TLOGICAL)
+ {
+ bitpix = BYTE_IMG;
+ nbytes = repeat;
+ }
+ 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 image in output file */
+ if (ffcrimll(newptr, bitpix, naxis, naxes, status) > 0)
+ {
+ ffpmsg("failed to write required primary array keywords in the output file");
+ return(*status);
+ }
+
+ npat = sizeof(patterns)/sizeof(patterns[0][0])/2;
+
+ /* skip over the first 8 keywords, starting just after TFIELDS */
+ fits_translate_keywords(fptr, newptr, 9, patterns, npat,
+ colnum, 0, 0, status);
+
+ /* add some HISTORY */
+ sprintf(card,"HISTORY This image was copied from row %ld of column '%s',",
+ rownum, colname);
+/* disable this; leave it up to the caller to write history if needed.
+ ffprec(newptr, card, status);
+*/
+ /* the use of ffread routine, below, requires that any 'dirty' */
+ /* buffers in memory be flushed back to the file first */
+
+ ffflsh(fptr, FALSE, 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(30000, 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(30000, nbytes);
+ ffread((fptr)->Fptr, (long) ntodo, buffer, status);
+ ffptbb(newptr, 1, firstbyte, ntodo, buffer, status);
+ nbytes -= ntodo;
+ firstbyte += ntodo;
+ }
+
+ /* Re-scan the header so that CFITSIO knows about all the new keywords */
+ ffrdef(newptr,status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_copy_image2cell(
+ fitsfile *fptr, /* I - pointer to input image extension */
+ fitsfile *newptr, /* I - pointer to output table */
+ char *colname, /* I - name of column containing the image */
+ long rownum, /* I - number of the row containing the image */
+ int copykeyflag, /* I - controls which keywords to copy */
+ int *status) /* IO - error status */
+
+/*
+ Copy an image extension into a table cell at a given row and
+ column. The table must have already been created. If the "colname"
+ column exists, it will be used, otherwise a new column will be created
+ in the table.
+
+ The "copykeyflag" parameter controls which keywords to copy from the
+ input image to the output table header (with any appropriate translation).
+
+ copykeyflag = 0 -- no keywords will be copied
+ copykeyflag = 1 -- essentially all keywords will be copied
+ copykeyflag = 2 -- copy only the WCS related keywords
+
+ This routine was written by Craig Markwardt, GSFC
+
+*/
+{
+ tcolumn *colptr;
+ unsigned char buffer[30000];
+ int ii, hdutype, colnum, typecode, bitpix, naxis, ncols, hdunum;
+ char tformchar, tform[20], card[FLEN_CARD];
+ LONGLONG imgstart, naxes[9], nbytes, repeat, ntodo,firstbyte;
+ char filename[FLEN_FILENAME+20];
+
+ int npat;
+
+ int naxis1;
+ LONGLONG naxes1[9] = {0,0,0,0,0,0,0,0,0}, repeat1, width1;
+ int typecode1;
+ unsigned char dummy = 0;
+
+ LONGLONG headstart, datastart, dataend;
+
+ /* Image-to-table keyword translation table */
+ /* INPUT OUTPUT */
+ /* 01234567 01234567 */
+ char *patterns[][2] = {{"BSCALE", "TSCALn" }, /* Standard FITS keywords */
+ {"BZERO", "TZEROn" },
+ {"BUNIT", "TUNITn" },
+ {"BLANK", "TNULLn" },
+ {"DATAMIN", "TDMINn" },
+ {"DATAMAX", "TDMAXn" },
+ {"CTYPEi", "iCTYPn" }, /* Coordinate labels */
+ {"CTYPEia", "iCTYna" },
+ {"CUNITi", "iCUNIn" }, /* Coordinate units */
+ {"CUNITia", "iCUNna" },
+ {"CRVALi", "iCRVLn" }, /* WCS keywords */
+ {"CRVALia", "iCRVna" },
+ {"CDELTi", "iCDLTn" },
+ {"CDELTia", "iCDEna" },
+ {"CRPIXj", "jCRPXn" },
+ {"CRPIXja", "jCRPna" },
+ {"PCi_ja", "ijPCna" },
+ {"CDi_ja", "ijCDna" },
+ {"PVi_ma", "iVn_ma" },
+ {"PSi_ma", "iSn_ma" },
+ {"WCSAXESa","WCAXna" },
+ {"WCSNAMEa","WCSNna" },
+ {"CRDERia", "iCRDna" },
+ {"CSYERia", "iCSYna" },
+ {"CROTAi", "iCROTn" },
+
+ {"LONPOLEa","LONPna"},
+ {"LATPOLEa","LATPna"},
+ {"EQUINOXa","EQUIna"},
+ {"MJD-OBS", "MJDOBn" },
+ {"MJD-AVG", "MJDAn" },
+ {"RADESYSa","RADEna"},
+ {"CNAMEia", "iCNAna" },
+ {"DATE-AVG","DAVGn"},
+
+ {"NAXISi", "-" }, /* Remove structural keywords*/
+ {"PCOUNT", "-" },
+ {"GCOUNT", "-" },
+ {"EXTEND", "-" },
+ {"EXTNAME", "-" },
+ {"EXTVER", "-" },
+ {"EXTLEVEL","-" },
+ {"CHECKSUM","-" },
+ {"DATASUM", "-" },
+ {"*", "+" }}; /* copy all other keywords */
+
+
+ if (*status > 0)
+ return(*status);
+
+ if (fptr == 0 || newptr == 0) return (*status = NULL_INPUT_PTR);
+
+ if (ffghdt(fptr, &hdutype, status) > 0) {
+ ffpmsg("could not get input HDU type");
+ return (*status);
+ }
+
+ if (hdutype != IMAGE_HDU) {
+ ffpmsg("The input extension is not an image.");
+ ffpmsg(" Cannot open the image.");
+ return(*status = NOT_IMAGE);
+ }
+
+ if (ffghdt(newptr, &hdutype, status) > 0) {
+ ffpmsg("could not get output HDU type");
+ return (*status);
+ }
+
+ if (hdutype != BINARY_TBL) {
+ ffpmsg("The output extension is not a table.");
+ return(*status = NOT_BTABLE);
+ }
+
+
+ if (ffgiprll(fptr, 9, &bitpix, &naxis, naxes, status) > 0) {
+ ffpmsg("Could not read image parameters.");
+ return (*status);
+ }
+
+ /* Determine total number of pixels in the image */
+ repeat = 1;
+ for (ii = 0; ii < naxis; ii++) repeat *= naxes[ii];
+
+ /* Determine the TFORM value for the table cell */
+ if (bitpix == BYTE_IMG) {
+ typecode = TBYTE;
+ tformchar = 'B';
+ nbytes = repeat;
+ } else if (bitpix == SHORT_IMG) {
+ typecode = TSHORT;
+ tformchar = 'I';
+ nbytes = repeat*2;
+ } else if (bitpix == LONG_IMG) {
+ typecode = TLONG;
+ tformchar = 'J';
+ nbytes = repeat*4;
+ } else if (bitpix == FLOAT_IMG) {
+ typecode = TFLOAT;
+ tformchar = 'E';
+ nbytes = repeat*4;
+ } else if (bitpix == DOUBLE_IMG) {
+ typecode = TDOUBLE;
+ tformchar = 'D';
+ nbytes = repeat*8;
+ } else if (bitpix == LONGLONG_IMG) {
+ typecode = TLONGLONG;
+ tformchar = 'K';
+ nbytes = repeat*8;
+ } else {
+ ffpmsg("Error: the image has an invalid datatype.");
+ return (*status = BAD_BITPIX);
+ }
+
+ /* get column number */
+ ffpmrk();
+ ffgcno(newptr, CASEINSEN, colname, &colnum, status);
+ ffcmrk();
+
+ /* Column does not exist; create it */
+ if (*status) {
+
+ *status = 0;
+ sprintf(tform, "%.0f%c", (double) repeat, tformchar);
+ ffgncl(newptr, &ncols, status);
+ colnum = ncols+1;
+ fficol(newptr, colnum, colname, tform, status);
+ ffptdmll(newptr, colnum, naxis, naxes, status);
+
+ if (*status) {
+ ffpmsg("Could not insert new column into output table.");
+ return *status;
+ }
+
+ } else {
+
+ ffgtdmll(newptr, colnum, 9, &naxis1, naxes1, status);
+ if (*status > 0 || naxis != naxis1) {
+ ffpmsg("Input image dimensions and output table cell dimensions do not match.");
+ return (*status = BAD_DIMEN);
+ }
+ for (ii=0; ii<naxis; ii++) if (naxes[ii] != naxes1[ii]) {
+ ffpmsg("Input image dimensions and output table cell dimensions do not match.");
+ return (*status = BAD_DIMEN);
+ }
+
+ ffgtclll(newptr, colnum, &typecode1, &repeat1, &width1, status);
+ if ((*status > 0) || (typecode1 != typecode) || (repeat1 != repeat)) {
+ ffpmsg("Input image data type does not match output table cell type.");
+ return (*status = BAD_TFORM);
+ }
+ }
+
+ /* copy keywords from input image to output table, if required */
+
+ if (copykeyflag) {
+
+ npat = sizeof(patterns)/sizeof(patterns[0][0])/2;
+
+ if (copykeyflag == 2) { /* copy only the WCS-related keywords */
+ patterns[npat-1][1] = "-";
+ }
+
+ /* The 3rd parameter value = 5 means skip the first 4 keywords in the image */
+ fits_translate_keywords(fptr, newptr, 5, patterns, npat,
+ colnum, 0, 0, status);
+ }
+
+ /* Here is all the code to compute offsets:
+ * * byte offset from start of row to column (dest table)
+ * * byte offset from start of file to image data (source image)
+ */
+
+ /* Force the writing of the row of the table by writing the last byte of
+ the array, which grows the table, and/or shifts following extensions */
+ ffpcl(newptr, TBYTE, colnum, rownum, repeat, 1, &dummy, status);
+
+ /* byte offset within the row to the start of the image column */
+ colptr = (newptr->Fptr)->tableptr; /* point to first column */
+ colptr += (colnum - 1); /* offset to correct column structure */
+ firstbyte = colptr->tbcol + 1;
+
+ /* get starting address of input image to be read */
+ ffghadll(fptr, &headstart, &datastart, &dataend, status);
+ imgstart = datastart;
+
+ sprintf(card, "HISTORY Table column '%s' row %ld copied from image",
+ colname, rownum);
+/*
+ Don't automatically write History keywords; leave this up to the caller.
+ ffprec(newptr, card, status);
+*/
+
+ /* write HISTORY keyword with the file name (this is now disabled)*/
+
+ filename[0] = '\0'; hdunum = 0;
+ strcpy(filename, "HISTORY ");
+ ffflnm(fptr, filename+strlen(filename), status);
+ ffghdn(fptr, &hdunum);
+ sprintf(filename+strlen(filename),"[%d]", hdunum-1);
+/*
+ ffprec(newptr, filename, status);
+*/
+
+ /* the use of ffread routine, below, requires that any 'dirty' */
+ /* buffers in memory be flushed back to the file first */
+
+ ffflsh(fptr, FALSE, status);
+
+ /* move to the first byte of the input image */
+ ffmbyt(fptr, imgstart, TRUE, status);
+
+ ntodo = minvalue(30000L, nbytes);
+ ffgbyt(fptr, ntodo, buffer, status); /* read input image */
+ ffptbb(newptr, rownum, firstbyte, ntodo, buffer, status); /* write to table */
+
+ 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, (long) ntodo, buffer, status);
+ ffptbb(newptr, rownum, firstbyte, ntodo, buffer, status);
+ nbytes -= ntodo;
+ firstbyte += ntodo;
+ }
+
+ /* Re-scan the header so that CFITSIO knows about all the new keywords */
+ ffrdef(newptr,status);
+
+ 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 a new output file.
+ Any HDUs preceding or following the image are also copied to the
+ output file.
+ */
+
+ fitsfile *newptr;
+ int ii, hdunum;
+
+ /* 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, if 'only_one' flag not set */
+ if (!(((*fptr)->Fptr)->only_one)) {
+ 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);
+ }
+
+ if (fits_copy_image_section(*fptr, newptr, expr, status) > 0)
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+
+ /* copy any remaining HDUs to the output file, if 'only_one' flag not set */
+
+ if (!(((*fptr)->Fptr)->only_one)) {
+ 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);
+ }
+ } else {
+ ii = hdunum + 1; /* this value of ii is required below */
+ }
+
+ /* 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_copy_image_section(
+ fitsfile *fptr, /* I - pointer to input image */
+ fitsfile *newptr, /* I - pointer to output image */
+ char *expr, /* I - Image section expression */
+ int *status)
+{
+ /*
+ copies an image section from the input file to a new output HDU
+ */
+
+ int bitpix, naxis, numkeys, nkey;
+ long naxes[] = {1,1,1,1,1,1,1,1,1}, smin, smax, sinc;
+ long fpixels[] = {1,1,1,1,1,1,1,1,1};
+ long lpixels[] = {1,1,1,1,1,1,1,1,1};
+ long incs[] = {1,1,1,1,1,1,1,1,1};
+ char *cptr, keyname[FLEN_KEYWORD], card[FLEN_CARD];
+ int ii, tstatus, anynull;
+ long minrow, maxrow, minslice, maxslice, mincube, maxcube;
+ long firstpix;
+ long ncubeiter, nsliceiter, nrowiter, kiter, jiter, iiter;
+ int klen, kk, jj;
+ long outnaxes[9], outsize, buffsize;
+ double *buffer, crpix, cdelt;
+
+ if (*status > 0)
+ return(*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)
+ return(*status);
+
+ if (naxis < 1 || naxis > 4)
+ {
+ ffpmsg(
+ "Input image either had NAXIS = 0 (NULL image) or has > 4 dimensions");
+ 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 */
+
+ 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);
+ 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);
+ 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;
+
+ /* 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)
+ {
+ for (kk=-1;kk<26; kk++) /* modify any alternate WCS keywords */
+ {
+ /* read the CRPIXn keyword if it exists in the input file */
+ fits_make_keyn("CRPIX", ii + 1, keyname, status);
+
+ if (kk != -1) {
+ klen = strlen(keyname);
+ keyname[klen]='A' + kk;
+ keyname[klen + 1] = '\0';
+ }
+
+ 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])) / incs[ii] + 1.0;
+ /* crpix = (crpix - (fpixels[ii] - 1.0) - .5) / incs[ii] + 0.5; */
+ } else {
+ crpix = (fpixels[ii] - crpix) / incs[ii] + 1.0;
+ /* 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);
+
+ if (kk != -1) {
+ klen = strlen(keyname);
+ keyname[klen]='A' + kk;
+ keyname[klen + 1] = '\0';
+ }
+
+ 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 they exist in the input file */
+
+ fits_make_keyn("CD1_", ii + 1, keyname, status);
+
+ if (kk != -1) {
+ klen = strlen(keyname);
+ keyname[klen]='A' + kk;
+ keyname[klen + 1] = '\0';
+ }
+
+ for (jj=0; jj < 9; jj++) /* look for up to 9 dimensions */
+ {
+ keyname[2] = '1' + jj;
+
+ 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 if (incs[ii]... loop */
+ } /* end of fits_read_key loop */
+ } /* end of for (kk loop */
+ }
+ } /* end of main NAXIS loop */
+
+ if (ffrdef(newptr, status) > 0) /* force the header to be scanned */
+ {
+ return(*status);
+ }
+
+ /* 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);
+
+ /* to reduce memory foot print, just read/write image 1 row at a time */
+
+ outsize = outnaxes[0];
+ buffsize = (abs(bitpix) / 8) * outsize;
+
+ buffer = (double *) malloc(buffsize); /* allocate memory for the image row */
+ if (!buffer)
+ {
+ ffpmsg("fits_copy_image_section: no memory for image section");
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* read the image section then write it to the output file */
+
+ minrow = fpixels[1];
+ maxrow = lpixels[1];
+ if (minrow > maxrow) {
+ nrowiter = (minrow - maxrow + incs[1]) / incs[1];
+ } else {
+ nrowiter = (maxrow - minrow + incs[1]) / incs[1];
+ }
+
+ minslice = fpixels[2];
+ maxslice = lpixels[2];
+ if (minslice > maxslice) {
+ nsliceiter = (minslice - maxslice + incs[2]) / incs[2];
+ } else {
+ nsliceiter = (maxslice - minslice + incs[2]) / incs[2];
+ }
+
+ mincube = fpixels[3];
+ maxcube = lpixels[3];
+ if (mincube > maxcube) {
+ ncubeiter = (mincube - maxcube + incs[3]) / incs[3];
+ } else {
+ ncubeiter = (maxcube - mincube + incs[3]) / incs[3];
+ }
+
+ firstpix = 1;
+ for (kiter = 0; kiter < ncubeiter; kiter++)
+ {
+ if (mincube > maxcube) {
+ fpixels[3] = mincube - (kiter * incs[3]);
+ } else {
+ fpixels[3] = mincube + (kiter * incs[3]);
+ }
+
+ lpixels[3] = fpixels[3];
+
+ for (jiter = 0; jiter < nsliceiter; jiter++)
+ {
+ if (minslice > maxslice) {
+ fpixels[2] = minslice - (jiter * incs[2]);
+ } else {
+ fpixels[2] = minslice + (jiter * incs[2]);
+ }
+
+ lpixels[2] = fpixels[2];
+
+ for (iiter = 0; iiter < nrowiter; iiter++)
+ {
+ if (minrow > maxrow) {
+ fpixels[1] = minrow - (iiter * incs[1]);
+ } else {
+ fpixels[1] = minrow + (iiter * incs[1]);
+ }
+
+ lpixels[1] = fpixels[1];
+
+ if (bitpix == 8)
+ {
+ ffgsvb(fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
+ (unsigned char *) buffer, &anynull, status);
+
+ ffpprb(newptr, 1, firstpix, 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, firstpix, outsize, (short *) buffer, status);
+ }
+ else if (bitpix == 32)
+ {
+ ffgsvk(fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
+ (int *) buffer, &anynull, status);
+
+ ffpprk(newptr, 1, firstpix, outsize, (int *) buffer, status);
+ }
+ else if (bitpix == -32)
+ {
+ ffgsve(fptr, 1, naxis, naxes, fpixels, lpixels, incs, FLOATNULLVALUE,
+ (float *) buffer, &anynull, status);
+
+ ffppne(newptr, 1, firstpix, outsize, (float *) buffer, FLOATNULLVALUE, status);
+ }
+ else if (bitpix == -64)
+ {
+ ffgsvd(fptr, 1, naxis, naxes, fpixels, lpixels, incs, DOUBLENULLVALUE,
+ buffer, &anynull, status);
+
+ ffppnd(newptr, 1, firstpix, outsize, buffer, DOUBLENULLVALUE,
+ status);
+ }
+ else if (bitpix == 64)
+ {
+ ffgsvjj(fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
+ (LONGLONG *) buffer, &anynull, status);
+
+ ffpprjj(newptr, 1, firstpix, outsize, (LONGLONG *) buffer, status);
+ }
+
+ firstpix += outsize;
+ }
+ }
+ }
+
+ free(buffer); /* finished with the memory */
+
+ if (*status > 0)
+ {
+ ffpmsg("fits_copy_image_section: error copying image section");
+ 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 */
+
+ /* support [:2,:2] type syntax, where the leading * is implied */
+ if (slen==0) strcpy(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, if the 'only_one' flag is not set */
+ if (!((*fptr)->Fptr)->only_one) {
+ 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);
+ }
+ }
+ } else {
+ /* just copy the primary array */
+ fits_movabs_hdu(*fptr, 1, NULL, status);
+ if (fits_copy_hdu(*fptr, newptr, 0, status) > 0)
+ {
+ ffclos(newptr, status);
+ return(*status);
+ }
+ }
+
+ fits_movabs_hdu(*fptr, hdunum, NULL, status);
+
+ /* copy all the header keywords from the input to output file */
+ 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 */
+
+ if (!((*fptr)->Fptr)->only_one) {
+ 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);
+ }
+ } else {
+ hdunum = 2;
+ }
+
+ /* 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
+ H = HCOMPRESS
+ HS = HCOMPRESS (with smoothing)
+ B - BZIP2
+ P = PLIO
+
+ myfile.fits[compress TYPE 100,100] - the numbers give the dimensions
+ of the compression tiles. Default
+ is NAXIS1, 1, 1, ...
+
+ other optional parameters may be specified following a semi-colon
+
+ myfile.fits[compress; q 8.0] q specifies the floating point
+ mufile.fits[compress TYPE; q -.0002] quantization level;
+ myfile.fits[compress TYPE 100,100; q 10, s 25] s specifies the HCOMPRESS
+ integer scaling parameter
+
+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, smooth = 0;
+ long tilesize[MAX_COMPRESS_DIM] = {0,1,1,1,1,1};
+ float qlevel = 0.0, scale = 0.;
+
+ 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 == 'b' || *ptr1 == 'B')
+ {
+ compresstype = BZIP2_1;
+ while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
+ ptr1++;
+
+ }
+*/
+ else if (*ptr1 == 'p' || *ptr1 == 'P')
+ {
+ compresstype = PLIO_1;
+ while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
+ ptr1++;
+ }
+ else if (*ptr1 == 'h' || *ptr1 == 'H')
+ {
+ compresstype = HCOMPRESS_1;
+ ptr1++;
+ if (*ptr1 == 's' || *ptr1 == 'S')
+ smooth = 1; /* apply smoothing when uncompressing HCOMPRESSed image */
+
+ 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 semi-colon, followed by other optional parameters */
+ /* ========================================================= */
+
+ if (*ptr1 == ';') {
+ ptr1++;
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ while (*ptr1 != 0) { /* haven't reached end of string yet */
+
+ if (*ptr1 == 's' || *ptr1 == 'S') {
+ /* this should be the HCOMPRESS "scale" parameter; default = 1 */
+
+ ptr1++;
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ scale = (float) strtod(ptr1, &ptr1);
+
+ while (*ptr1 == ' ' || *ptr1 == ',') /* skip over blanks or comma */
+ ptr1++;
+
+ } else if (*ptr1 == 'q' || *ptr1 == 'Q') {
+ /* this should be the floating point quantization parameter */
+
+ ptr1++;
+ while (*ptr1 == ' ') /* ignore leading blanks */
+ ptr1++;
+
+ qlevel = (float) strtod(ptr1, &ptr1);
+
+ while (*ptr1 == ' ' || *ptr1 == ',') /* skip over blanks or comma */
+ ptr1++;
+
+ } else {
+ return(*status = URL_PARSE_ERROR);
+ }
+ }
+ }
+
+ /* ================================= */
+ /* finished parsing; save the values */
+ /* ================================= */
+
+ fits_set_compression_type(fptr, compresstype, status);
+ fits_set_tile_dim(fptr, MAX_COMPRESS_DIM, tilesize, status);
+
+ if (compresstype == HCOMPRESS_1) {
+ fits_set_hcomp_scale (fptr, scale, status);
+ fits_set_hcomp_smooth(fptr, smooth, status);
+ }
+
+ if (qlevel != 0.0)
+ fits_set_quantize_level(fptr, qlevel, status);
+
+ 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 ii, 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)
+ {
+ if (strlen(url) > FLEN_FILENAME - 1)
+ {
+ ffpmsg("Filename is too long. (ffinit)");
+ return(*status = FILE_NOT_CREATED);
+ }
+
+ 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 */
+ /* this routine checks that the strings will not overflow */
+ 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)
+ {
+ FFLOCK; /* lock this while searching for vacant handle */
+ *status = (*driverTable[driver].create)(outfile, &handle);
+ FFUNLOCK;
+ 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 = (LONGLONG *) calloc(1001, sizeof(LONGLONG));
+
+ 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);
+ }
+
+ /* mem for file I/O buffers */
+ ((*fptr)->Fptr)->iobuffer = (char *) calloc(NIOBUF, IOBUFLEN);
+
+ if ( !(((*fptr)->Fptr)->iobuffer) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for iobuffer array: (ffinit)");
+ ffpmsg(url);
+ free( ((*fptr)->Fptr)->headstart); /* free memory for headstart array */
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* initialize the ageindex array (relative age of the I/O buffers) */
+ /* and initialize the bufrecnum array as being empty */
+ for (ii = 0; ii < NIOBUF; ii++) {
+ ((*fptr)->Fptr)->ageindex[ii] = ii;
+ ((*fptr)->Fptr)->bufrecnum[ii] = -1;
+ }
+
+ /* 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 ii, 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 */
+ FFLOCK; /* lock this while searching for vacant handle */
+ *status = mem_openmem( buffptr, buffsize, deltasize,
+ mem_realloc, &handle);
+ FFUNLOCK;
+
+ 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 = (LONGLONG *) calloc(1001, sizeof(LONGLONG));
+
+ if ( !(((*fptr)->Fptr)->headstart) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for headstart array: (ffimem)");
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* mem for file I/O buffers */
+ ((*fptr)->Fptr)->iobuffer = (char *) calloc(NIOBUF, IOBUFLEN);
+
+ if ( !(((*fptr)->Fptr)->iobuffer) )
+ {
+ (*driverTable[driver].close)(handle); /* close the file */
+ ffpmsg("failed to allocate memory for iobuffer array: (ffimem)");
+ free( ((*fptr)->Fptr)->headstart); /* free memory for headstart array */
+ free( ((*fptr)->Fptr)->filename);
+ free((*fptr)->Fptr);
+ free(*fptr);
+ *fptr = 0; /* return null file pointer */
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* initialize the ageindex array (relative age of the I/O buffers) */
+ /* and initialize the bufrecnum array as being empty */
+ for (ii = 0; ii < NIOBUF; ii++) {
+ ((*fptr)->Fptr)->ageindex[ii] = ii;
+ ((*fptr)->Fptr)->bufrecnum[ii] = -1;
+ }
+
+ /* 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;
+
+ fitsio_init_lock();
+
+ FFLOCK; /* lockout other threads while executing this critical */
+ /* section of code */
+
+ if (need_to_initialize == 0) { /* already initialized? */
+ FFUNLOCK;
+ return(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 CFITSIO developers.\n");
+ printf( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ FFUNLOCK;
+ return(1);
+ }
+
+
+ /* test that LONGLONG is an 8 byte integer */
+
+ if (sizeof(LONGLONG) != 8)
+ {
+ printf ("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ printf(" CFITSIO did not find an 8-byte long integer data type.\n");
+ printf(" sizeof(LONGLONG) = %d\n",(int)sizeof(LONGLONG));
+ printf(" Please report this problem to the CFITSIO developers.\n");
+ printf( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ FFUNLOCK;
+ 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)");
+ FFUNLOCK;
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 3--------------input pre-existing memory file driver----------------*/
+ status = fits_register_driver("memkeep://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 4-------------------stdin stream driver----------------------*/
+ /* the stdin stream is copied to memory then opened in memory */
+
+ status = fits_register_driver("stdin://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ 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://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+
+ /* 6-----------------------stdout stream driver------------------*/
+ status = fits_register_driver("stdout://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 7------------------iraf disk file to memory driver -----------*/
+ status = fits_register_driver("irafmem://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 8------------------raw binary file to memory driver -----------*/
+ status = fits_register_driver("rawfile://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 9------------------compressed disk file to memory driver -----------*/
+ status = fits_register_driver("compress://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 10------------------compressed disk file to memory driver -----------*/
+ /* Identical to compress://, except it allows READWRITE access */
+
+ status = fits_register_driver("compressmem://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 11------------------compressed disk file to disk file driver -------*/
+ status = fits_register_driver("compressfile://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 12---create file in memory, then compress it to disk file on close--*/
+ status = fits_register_driver("compressoutfile://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 14--------------------http driver-----------------------*/
+ status = fits_register_driver("http://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 15--------------------http file driver-----------------------*/
+
+ status = fits_register_driver("httpfile://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 16--------------------http memory driver-----------------------*/
+ /* same as http:// driver, except memory file can be opened READWRITE */
+ status = fits_register_driver("httpmem://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 17--------------------httpcompress file driver-----------------------*/
+
+ status = fits_register_driver("httpcompress://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+
+ /* 18--------------------ftp driver-----------------------*/
+ status = fits_register_driver("ftp://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 19--------------------ftp file driver-----------------------*/
+ status = fits_register_driver("ftpfile://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 20--------------------ftp mem driver-----------------------*/
+ /* same as ftp:// driver, except memory file can be opened READWRITE */
+ status = fits_register_driver("ftpmem://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* 21--------------------ftp compressed file driver------------------*/
+ status = fits_register_driver("ftpcompress://",
+ NULL,
+ 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)");
+ FFUNLOCK;
+ 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)");
+ FFUNLOCK;
+ return(status);
+ }
+
+#endif
+/* ==================== END OF SHARED MEMORY DRIVER SECTION ================ */
+
+
+#ifdef HAVE_GSIFTP
+ /* 23--------------------gsiftp driver-----------------------*/
+ status = fits_register_driver("gsiftp://",
+ gsiftp_init,
+ gsiftp_shutdown,
+ gsiftp_setoptions,
+ gsiftp_getoptions,
+ gsiftp_getversion,
+ gsiftp_checkfile,
+ gsiftp_open,
+ gsiftp_create,
+#ifdef HAVE_FTRUNCATE
+ gsiftp_truncate,
+#else
+ NULL,
+#endif
+ gsiftp_close,
+ NULL, /* remove function not yet implemented */
+ gsiftp_size,
+ gsiftp_flush,
+ gsiftp_seek,
+ gsiftp_read,
+ gsiftp_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the gsiftp:// driver (init_cfitsio)");
+ FFUNLOCK;
+ return(status);
+ }
+
+#endif
+
+ /* 24---------------stdin and stdout stream driver-------------------*/
+ status = fits_register_driver("stream://",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ stream_open,
+ stream_create,
+ NULL, /* no stream truncate function */
+ stream_close,
+ NULL, /* no stream remove */
+ stream_size,
+ stream_flush,
+ stream_seek,
+ stream_read,
+ stream_write);
+
+ if (status)
+ {
+ ffpmsg("failed to register the stream:// driver (init_cfitsio)");
+ FFUNLOCK;
+ return(status);
+ }
+
+ /* reset flag. Any other threads will now not need to call this routine */
+ need_to_initialize = 0;
+
+ FFUNLOCK;
+ 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, LONGLONG filesize),
+ int (*close)(int driverhandle),
+ int (*fremove)(char *filename),
+ int (*size)(int driverhandle, LONGLONG *size),
+ int (*flush)(int driverhandle),
+ int (*seek)(int driverhandle, LONGLONG 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 < 0 ) {
+ /* This is bad. looks like memory has been corrupted. */
+ ffpmsg("Vital CFITSIO parameters held in memory have been corrupted!!");
+ ffpmsg("Fatal condition detected in fits_register_driver.");
+ return(TOO_MANY_DRIVERS);
+ }
+
+ if (no_of_drivers + 1 > MAX_DRIVERS)
+ return(TOO_MANY_DRIVERS);
+
+ if (prefix == NULL)
+ return(BAD_URL_PREFIX);
+
+
+ if (init != NULL)
+ {
+ status = (*init)(); /* initialize the driver */
+ 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);
+ }
+/*--------------------------------------------------------------------------*/
+/* fits_parse_input_url */
+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 does not support the pixfilter or compspec components.
+*/
+{
+ return ffifile2(url, urltype, infilex, outfile,
+ extspec, rowfilterx, binspec, colspec, 0, 0, status);
+}
+/*--------------------------------------------------------------------------*/
+/* fits_parse_input_file */
+int ffifile(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 */
+ char *pixfilter, /* pixel filter expression */
+ int *status)
+/*
+ fits_parse_input_filename
+ parse the input URL into its basic components.
+ This routine does not support the compspec component.
+*/
+{
+ return ffifile2(url, urltype, infilex, outfile,
+ extspec, rowfilterx, binspec, colspec, pixfilter, 0, status);
+
+}
+/*--------------------------------------------------------------------------*/
+int ffifile2(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 */
+ char *pixfilter, /* pixel filter expression */
+ char *compspec, /* image compression specification */
+ int *status)
+/*
+ fits_parse_input_filename
+ 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, *ptr4, *tmptr;
+ int hasAt, hasDot, hasOper, followingOper, spaceTerm, rowFilter;
+ int colStart, binStart, pixStart, compStart;
+
+
+ /* 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';
+ if (pixfilter) *pixfilter = '\0';
+ if (compspec) *compspec = '\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, "gsiftp:", 7) )
+ { /* the 2 //'s are optional */
+ if (urltype)
+ strcat(urltype, "gsiftp://");
+ ptr1 += 7;
+ }
+ 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) {
+
+ if (strlen(ptr1) > FLEN_FILENAME - 1) {
+ ffpmsg("Name of file is too long.");
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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) {
+
+ if (ptr1 - ptr2 > FLEN_FILENAME - 1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 */
+ /* --------------------------------------------- */
+
+ ptr4 = strstr(infile, ".imh");
+
+ /* did the infile name end with ".imh" ? */
+ if (ptr4 && (*(ptr4 + 4) == '\0'))
+ {
+ 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) {
+ if (jj - infilelen > FLEN_FILENAME - 1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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)
+ {
+ if (strlen(&infile[ii + 1]) > FLEN_FILENAME - 1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ strcpy(outfile, &infile[ii + 1]);
+ break;
+ }
+ }
+ }
+
+ /* ------------------------------------------ */
+ /* copy strings from local copy to the output */
+ /* ------------------------------------------ */
+ if (infilex) {
+ if (strlen(infile) > FLEN_FILENAME - 1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 a image compression 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)
+ {
+
+ if (strlen(infilex) + strlen(ptr3) > FLEN_FILENAME - 1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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)
+ {
+
+
+ if (strlen(rowfilterx) + strlen(tmptr + 1) > FLEN_FILENAME -1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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")]
+
+ [compress Rice]
+
+ 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;
+ pixStart = 0;
+ compStart = 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, "pix", 3) )
+ pixStart = 1;
+
+ if ( !strncasecmp(tmptr, "compress ", 9) ||
+ !strncasecmp(tmptr, "compress]", 9) )
+ compStart = 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 || pixStart)) )
+ 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 || (pixStart && spaceTerm) ||
+ (hasAt && hasDot) ||
+ hasOper ||
+ compStart ||
+ (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) {
+ if (ptr2 - ptr1 > FLEN_FILENAME - 1) {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+ 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)
+ {
+ if (strlen(ptr1 +1) > FLEN_FILENAME - 1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 */
+ {
+ if (collen > FLEN_FILENAME - 1) {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 */
+ }
+
+ /* --------------------------------------------------------- */
+ /* does the filter contain a pixel filter specification? */
+ /* --------------------------------------------------------- */
+
+ ptr1 = strstr(rowfilter, "[pix");
+ if (!ptr1)
+ {
+ ptr1 = strstr(rowfilter, "[PIX");
+
+ if (!ptr1)
+ ptr1 = strstr(rowfilter, "[Pix");
+ }
+
+ if (ptr1)
+ {
+ ptr2 = ptr1 + 4; /* end of the '[pix' string */
+ if (*ptr2 == 'b' || *ptr2 == 'i' || *ptr2 == 'j' || *ptr2 == 'B' ||
+ *ptr2 == 'I' || *ptr2 == 'J' || *ptr2 == 'r' || *ptr2 == 'd' ||
+ *ptr2 == 'R' || *ptr2 == 'D')
+ ptr2++; /* skip the datatype code letter */
+
+ if (*ptr2 == '1')
+ ptr2++; /* skip the single HDU indicator */
+
+ if ( *ptr2 != ' ')
+ ptr1 = NULL; /* pix string must be followed by space */
+ }
+
+ if (ptr1)
+ { /* find the end of the pixel filter */
+ 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 (pixfilter) /* copy the column specifier to output string */
+ {
+ if (collen > FLEN_FILENAME - 1) {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ strncpy(pixfilter, ptr1 + 1, collen);
+ pixfilter[collen] = '\0';
+
+ while (pixfilter[--collen] == ' ')
+ pixfilter[collen] = '\0'; /* strip trailing blanks */
+ }
+
+ /* delete the pixel filter from the row filter string */
+ strcpy(tmpstr, ptr2 + 1); /* copy any chars after the pixel filter */
+ strcpy(ptr1, tmpstr); /* overwrite binspec */
+ }
+
+ /* ------------------------------------------------------------ */
+ /* does the filter contain an image compression specification? */
+ /* ------------------------------------------------------------ */
+
+ ptr1 = strstr(rowfilter, "[compress");
+
+ if (ptr1)
+ {
+ ptr2 = ptr1 + 9; /* end of the '[compress' string */
+
+ if ( *ptr2 != ' ' && *ptr2 != ']')
+ ptr1 = NULL; /* compress string must be followed by space or ] */
+ }
+
+ if (ptr1)
+ {
+ /* found the compress string */
+ if (compspec)
+ {
+ if (strlen(ptr1 +1) > FLEN_FILENAME - 1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ strcpy(compspec, ptr1 + 1);
+ ptr2 = strchr(compspec, ']');
+
+ 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 compression spec from the row filter string */
+ ptr2 = strchr(ptr1, ']');
+ strcpy(tmpstr, ptr2+1); /* copy any chars after the binspec */
+ 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';
+
+ if (strlen(rowfilter + 1) > FLEN_FILENAME - 1)
+ {
+ free(infile);
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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, gsiftp, 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 */
+ {
+
+ if (ptr2 - ptr1 + 3 > MAX_PREFIX_LEN - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+ 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, "gsiftp:", 7) )
+ { /* the 2 //'s are optional */
+ strcat(urltype, "gsiftp://");
+ ptr1 += 7;
+ }
+ 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 */
+ {
+
+ if (strlen(ptr1) > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ strcat(infile, ptr1);
+ }
+ else if (!ptr3) /* no bracket, so () enclose output file name */
+ {
+
+ if (ptr2 - ptr1 > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 */
+ {
+
+ if (ptr2 - ptr1 > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 */
+ {
+ if (ptr3 - ptr1 > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 */
+ }
+ }
+
+ if (strlen(urltype) + strlen(infile) > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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) {
+ if (ptr2 - ptr1 + 3 > MAX_PREFIX_LEN - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 */
+ if (ptr2 - ptr1 > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ strncat(outfile, ptr1, ptr2 - ptr1);
+ } else if (ptr3) { /* compression was specified */
+ if (ptr3 - ptr1 > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+ strncat(outfile, ptr1, ptr3 - ptr1);
+
+ } else { /* no template file or compression */
+ if (strlen(ptr1) > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+ 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) {
+ if (ptr1 - ptr2 > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+ 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) {
+
+ if (ptr1 - ptr3 > FLEN_FILENAME - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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 */
+ errno = 0; /* reset this prior to calling strtol */
+ *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' && *loc != ';' ) || (errno == ERANGE) )
+ {
+ *extnum = 0;
+ notint = 1; /* no, extname was not a simple integer after all */
+ errno = 0; /* reset error condition flag if it was set */
+ }
+
+ 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 */
+
+ if (slen > FLEN_VALUE - 1)
+ {
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ 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);
+ }
+
+ if (ptr2 - ptr1 > FLEN_FILENAME - 1)
+ {
+ 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);
+ }
+
+ if (ptr1 - ptr2 > FLEN_FILENAME - 1)
+ {
+ 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 */
+ fits_parse_input_url(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 */
+ infile[0] = '\0';
+ strncat(infile, url, FLEN_FILENAME -1);
+
+ 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;
+*/
+{
+ char *loc, tval[73];
+ int slen;
+ double dval;
+
+ *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) /* check if token is a number */
+ {
+ *isanumber = 1;
+
+ if (strchr(token, 'D')) {
+ strcpy(tval, token);
+
+ /* The C language does not support a 'D'; replace with 'E' */
+ if (loc = strchr(tval, 'D')) *loc = 'E';
+
+ dval = strtod(tval, &loc);
+ } else {
+ dval = strtod(token, &loc);
+ }
+
+ /* check for read error, or junk following the value */
+ if (*loc != '\0' && *loc != ' ' ) *isanumber = 0;
+ if (errno == ERANGE) *isanumber = 0;
+ }
+ }
+
+ 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
+
+
+NOTE: This routine is not thread-safe.
+This routine is simply provided as a utility routine for other external
+software. It is not used by any CFITSIO routine.
+
+*/
+ 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)->iobuffer); /* free memory for I/O buffers */
+ 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);
+
+ fits_parse_input_url((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)->iobuffer); /* free memory for I/O buffers */
+ 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 */
+ LONGLONG 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)->io_pos = 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 */
+ LONGLONG 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) )
+ {
+ ffpmsg("Error writing data buffer to file:");
+ ffpmsg(fptr->filename);
+
+ *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)
+ {
+ ffpmsg("Error reading data buffer from file:");
+ ffpmsg(fptr->filename);
+
+ *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);
+
+ /* must reset the PCOUNT keyword to zero in the new output file */
+ if (strncmp(card, "PCOUNT ",8) == 0) { /* the PCOUNT keyword? */
+ if (strncmp(card+25, " 0", 5)) { /* non-zero value? */
+ strncpy(card, "PCOUNT = 0", 30);
+ }
+ }
+
+ 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;
+}
+/*--------------------------------------------------------------------------*/
+int pixel_filter_helper(
+ fitsfile **fptr, /* IO - pointer to input image; on output it */
+ /* points to the new image */
+ char *outfile, /* I - name for output file */
+ char *expr, /* I - Image filter expression */
+ int *status)
+{
+ PixelFilter filter = { 0 };
+ char * DEFAULT_TAG = "X";
+ int ii, hdunum;
+ int singleHDU = 0;
+
+ filter.count = 1;
+ filter.ifptr = fptr;
+ filter.tag = &DEFAULT_TAG;
+
+ /* create new empty file for result */
+ if (ffinit(&filter.ofptr, outfile, status) > 0)
+ {
+ ffpmsg("failed to create output file for pixel filter:");
+ ffpmsg(outfile);
+ return(*status);
+ }
+
+ fits_get_hdu_num(*fptr, &hdunum); /* current HDU number in input file */
+
+ expr += 3; /* skip 'pix' */
+ switch (expr[0]) {
+ case 'b':
+ case 'B': filter.bitpix = BYTE_IMG; break;
+ case 'i':
+ case 'I': filter.bitpix = SHORT_IMG; break;
+ case 'j':
+ case 'J': filter.bitpix = LONG_IMG; break;
+ case 'r':
+ case 'R': filter.bitpix = FLOAT_IMG; break;
+ case 'd':
+ case 'D': filter.bitpix = DOUBLE_IMG; break;
+ }
+ if (filter.bitpix) /* skip bitpix indicator */
+ ++expr;
+
+ if (*expr == '1') {
+ ++expr;
+ singleHDU = 1;
+ }
+
+ if (((*fptr)->Fptr)->only_one)
+ singleHDU = 1;
+
+ if (*expr != ' ') {
+ ffpmsg("pixel filtering expression not space separated:");
+ ffpmsg(expr);
+ }
+ while (*expr == ' ')
+ ++expr;
+
+ /* copy all preceding extensions to the output file */
+ for (ii = 1; !singleHDU && ii < hdunum; ii++)
+ {
+ fits_movabs_hdu(*fptr, ii, NULL, status);
+ if (fits_copy_hdu(*fptr, filter.ofptr, 0, status) > 0)
+ {
+ ffclos(filter.ofptr, status);
+ return(*status);
+ }
+ }
+
+ /* move back to the original HDU position */
+ fits_movabs_hdu(*fptr, hdunum, NULL, status);
+
+ filter.expression = expr;
+ if (fits_pixel_filter(&filter, status)) {
+ ffpmsg("failed to execute image filter:");
+ ffpmsg(expr);
+ ffclos(filter.ofptr, status);
+ return(*status);
+ }
+
+
+ /* copy any remaining HDUs to the output file */
+
+ for (ii = hdunum + 1; !singleHDU; ii++)
+ {
+ if (fits_movabs_hdu(*fptr, ii, NULL, status) > 0)
+ break;
+
+ fits_copy_hdu(*fptr, filter.ofptr, 0, status);
+ }
+
+ if (*status == END_OF_FILE)
+ *status = 0; /* got the expected EOF error; reset = 0 */
+ else if (*status > 0)
+ {
+ ffclos(filter.ofptr, status);
+ return(*status);
+ }
+
+ /* close the original file and return ptr to the new image */
+ ffclos(*fptr, status);
+
+ *fptr = filter.ofptr; /* reset the pointer to the new table */
+
+ /* move back to the image subsection */
+ if (ii - 1 != hdunum)
+ fits_movabs_hdu(*fptr, hdunum, NULL, status);
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/cfitsio.doc b/vendor/cfitsio/cfitsio.doc
new file mode 100644
index 00000000..d22704bf
--- /dev/null
+++ b/vendor/cfitsio/cfitsio.doc
@@ -0,0 +1,9535 @@
+ CFITSIO - An Interface to FITS Format Files for C Programmers
+
+ William D Pence, HEASARC, NASA/GSFC
+ Version 3.0
+
+
+[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: William.D.Pence@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. Acknowledgments
+
+The development of the many 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. Also, in 2009, Bruce O'Neel
+was the key developer of the thread-safe version of CFITSIO.
+
+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.
+
+Giuliano Taffoni and Andrea Barisani, at INAF, University of Trieste,
+Italy, implemented the I/O driver routines for accessing FITS files
+on the computational grids using the gridftp protocol.
+
+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.
+
+Martin Reinecke (Max Planck Institute, Garching)) provided the modifications to
+cfortran.h that are necessary to support 64-bit integer values when calling
+C routines from fortran programs. The cfortran.h macros were originally developed
+by Burkhard Burow (CERN).
+
+Julian Taylor (ESO, Garching) provided the fast byte-swapping algorithms
+that use the SSE2 and SSSE3 machine instructions available on x86\_64 CPUs.
+
+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,
+Rob Seaman, 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.
+
+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."
+
+*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 (not up-to-date):
+-
+ 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] [--enable-reentrant]
+ [--enable-sse2] [--enable-ssse3]
+ > 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 optional --enable-reentrant flag will attempt to configure CFITSIO
+so that it can be used in multi-threaded programs. See the "Using CFITSIO in Multi-threaded Environments" section, below, for more details.
+
+The optional --enable-sse2 and --enable-ssse3 flags will cause configure to
+attempt to build CFITSIO using faster byte-swapping algorithms.
+See the "Optimizing Programs" chapter of this manual for
+more information about these options.
+
+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.
+
+It may not be possible to statically 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\_3xxx\_borland.zip and cfitsiodll\_3xxx\_vcc.zip, where
+'3xxx' 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 or v5.5 compiler
+using older DOS commands.
+
+***4. Macintosh PCs
+
+When building on Mac OS-X, users should follow the Unix instructions,
+above. See the README.MacOS file for instructions on building a Universal
+Binary that supports both Intel and PowerPC CPUs.
+
+**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. Using CFITSIO in Multi-threaded Environments
+
+CFITSIO can be used either with the
+POSIX pthreads interface or the OpenMP interface for multi-threaded
+parallel programs. When used in a multi-threaded environment,
+the CFITSIO library *must* be built using
+the -D\_REENTRANT compiler directive. This can be done using the following
+build commands:
+-
+ >./configure --enable-reentrant
+ > make
+-
+A function called fits\_is\_reentrant is available to test
+whether or not CFITSIO was compiled with the -D\_REENTRANT
+directive. When this feature is enabled, multiple threads can
+call any of the CFITSIO routines
+to simultaneously read or write separate
+FITS files. Multiple threads can also read data from
+the same FITS file simultaneously, as long as the file
+was opened independently by each thread. This relies on
+the operating system to correctly deal with reading the
+same file by multiple processes. Different threads should
+not share the same 'fitsfile' pointer to read an opened
+FITS file, unless locks are placed around the calls to
+the CFITSIO reading routines.
+Different threads should never try to write to the same
+FITS file.
+
+**E. 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.
+
+**F. 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. Six different primary
+data types are supported: Unsigned 8-bit bytes, 16-bit, 32-bit, and 64-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, 64, -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 further 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 LONGLONG_IMG 64 /* 64-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 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 TLONG 41 /* signed long, */
+ #define TLONGLONG 81 /* 64-bit long signed integer 'K' */
+ #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 */
+
+ The following data type code is only for use with fits\_get\_coltype
+ #define TINT32BIT 41 /* signed 32-bit int, 'J' */
+
+
+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
+ #define HCOMPRESS_1 41
+-
+
+**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. Implicit 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 old PC compilers,
+but otherwise it is nearly always 4 bytes long. Some 64-bit
+machines, like the Alpha/OSF, define the `short', `int',
+and `long' integer data types to be 2, 4, and 8 bytes long,
+respectively.
+
+Because there is no universal C compiler standard for the name of the
+8-byte integer datatype, the fitsio.h include file typedef's
+'LONGLONG' to be equivalent to an
+appropriate 8-byte integer data type on each supported platform.
+For maximum software portability it is recommended that
+this LONGLONG datatype be used to define 8-byte integer variables
+rather than using the native data type name on a particular
+platform. On most
+32-bit Unix and Mac OS-X operating systems LONGLONG is equivalent to the
+intrinsic 'long long' 8-byte integer datatype. On 64-bit systems (which currently
+includes Alpha OSF/1, 64-bit Sun Solaris, 64-bit SGI MIPS, and 64-bit
+Itanium and Opteron PC systems), LONGLONG is simply typedef'ed to be
+equivalent to 'long'. Microsoft Visual C++ Version 6.0 does not define
+a 'long long' data type, so LONGLONG is typedef'ed to be equivalent to
+the '\_\_int64' data type on 32-bit windows systems when using Visual C++.
+
+A related issue that affects the portability of software is how to print
+out the value of a 'LONGLONG' variable with printf. Developers may
+find it convenient to use the following preprocessing statements
+in their C programs to handle this in a machine-portable manner:
+
+-
+#if defined(_MSC_VER) /* Microsoft Visual C++ */
+ printf("%I64d", longlongvalue);
+
+#elif (USE_LL_SUFFIX == 1)
+ printf("%lld", longlongvalue);
+
+#else
+ printf("%ld", longlongvalue);
+#endif
+-
+
+Similarly, the name of the C utility routine that converts a character
+string of digits into a 8-byte integer value is platform dependent:
+
+-
+#if defined(_MSC_VER) /* Microsoft Visual C++ */
+ /* VC++ 6.0 does not seem to have an 8-byte conversion routine */
+
+#elif (USE_LL_SUFFIX == 1)
+ longlongvalue = atoll(*string);
+
+#else
+ longlongvalue = atol(*string);
+#endif
+-
+
+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. This is also not
+supported when reading floating-point images that have been compressed
+with the FITS tiled image compression convention that is discussed in
+section 5.6; the pixels values in tile compressed images are
+represented by scaled integers, and a reserved integer value
+(not a NaN) is used to represent undefined pixels.
+
+**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. (CFITSIO also
+supports the experimental 'Q' datatype, which is identical to the 'P' type
+except that is supports is a 64-bit address space and hence much larger
+data structures). 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 row of data 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 and the new data will be
+written to a new area of the heap. The fits\_compress\_heap routine
+is provided to compress the heap and recover any unused space.
+To avoid having to deal with this issue, it is recommended
+that rows in a variable length field should only be written once.
+An exception to
+this general rule occurs when setting elements of an array as
+undefined. It is allowed to 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. 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 of course 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.
+
+Some restriction apply: a FITS file cannot be opened the first time
+with READONLY access, and then opened a second time with READWRITE access,
+because this may be phyically impossible (e.g., if the file resides
+on read-only media such as a CDROM). Also, in multi-threaded environoments,
+one should never open the same file with write access in different threads.
+
+**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.
+
+2. It used to be common for computer systems to only support disk files up
+to 2**31 bytes = 2.1 GB in size, but most systems now support larger files.
+CFITSIO can optionally read and write these so-called 'large files' that
+are greater than 2.1 GB on
+platforms where they are supported, but this
+usually requires that special compiler option flags be specified to turn
+on this option. On linux and solaris systems the compiler flags are
+'-D\_LARGEFILE\_SOURCE' and `-D\_FILE\_OFFSET\_BITS=64'. These flags
+may also work on other platforms but this has not been tested. Starting
+with version 3.0 of CFITSIO, the default Makefile that is distributed
+with CFITSIO will include these 2 compiler flags when building on Solaris
+and Linux PC systems. Users on other platforms will need to add these
+compiler flags manually if they want to support large files. In most
+cases it appears that it is not necessary to include these compiler
+flags when compiling application code that call the CFITSIO library
+routines.
+
+When CFITSIO is built with large file support (e.g., on Solaris and
+Linux PC system by default) then it can read and write FITS data files
+on disk that have any of these conditions:
+
+\begin{itemize}
+\item
+FITS files larger than 2.1 GB in size
+\item
+FITS images containing greater than 2.1 G pixels
+\item
+FITS images that have one dimension with more than 2.1 G pixels
+(as given by one of the NAXISn keyword)
+\item
+FITS tables containing more than 2.1E09 rows (given by the NAXIS2 keyword),
+or with rows that are more than 2.1 GB wide (given by the NAXIS1 keyword)
+\item
+FITS binary tables with a variable-length array heap that is larger
+than 2.1 GB (given by the PCOUNT keyword)
+\end{itemize}
+
+The current maximum FITS file size supported by CFITSIO
+is about 6 terabytes (containing
+2**31 FITS blocks, each 2880 bytes in size). Currently, support for large
+files in CFITSIO has been tested on the Linux, Solaris, and IBM AIX
+operating systems.
+
+Note that when writing application programs that are intended to support
+large files it is important to use 64-bit integer variables
+to store quantities such as the dimensions of images, or the number of
+rows in a table. These programs must also call the special versions
+of some of the CFITSIO routines that have been adapted to
+support 64-bit integers. The names of these routines end in
+'ll' ('el' 'el') to distinguish them from the 32-bit integer
+version (e.g., fits\_get\_num\_rowsll).
+
+
+*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 greater than 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. This returns the
+number of completely defined HDUs in the file. If a new HDU has just been added to
+the FITS file, then that last HDU will only be counted if it has been closed,
+or if data has been written to the HDU.
+> The current HDU remains unchanged by this routine. \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 Write the current HDU in the input FITS file to the
+> output FILE stream (e.g., to stdout). \label{ffwrhdu}
+-
+ int fits_write_hdu / ffwrhdu
+ (fitsfile *infptr, FILE *stream, > int *status)
+-
+>8 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)
+-
+>9 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 searches. 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, TLONGLONG, 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, with any
+ trailing blank characters stripped off. The fourth routine returns
+ the (next) header record that contains the literal string of characters
+ specified by the 'string' argument.
+
+ 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)
+
+ int fits_read_str / ffgstr
+ (fitsfile *fptr, char *string, > 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 (with trailing blanks truncated),
+ while the second routine parses the record and returns the name,
+ value, and comment fields as separate (blank truncated)
+ 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. These routine allocates memory for the returned
+ character array, so the calling program must free the memory when
+ finished. The cleanest way to do this is to
+ call the fits\_free\_memory routine.
+
+ There are 2 related routines: fits\_hdr2str simply concatenates all
+ the existing keywords in the header; fits\_convert\_hdr2str is similar,
+ except that if the CHDU is a tile compressed image (stored in a binary
+ table) then it will first convert that header back to that of the corresponding
+ normal FITS image before concatenating the keywords.
+
+ 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 **exclist parameter. \label{ffhdr2str}
+-
+ int fits_hdr2str / ffhdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+
+ int fits_convert_hdr2str / ffcnvthdr2str
+ (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, TLONGLONG, 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. The third routine deletes the (next) keyword that contains
+ the literal character string specified by the 'string'
+> argument.\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)
+
+ int fits_delete_str / ffdstr
+ (fitsfile *fptr, char *string, > 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 often 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), LONGLONG\_IMG (64),
+ 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_sizell / ffgiszll
+ (fitsfile *fptr, int maxdim, > LONGLONG *naxes, int *status)
+
+ int fits_get_img_param / ffgipr
+ (fitsfile *fptr, int maxdim, > int *bitpix, int *naxis, long *naxes,
+ int *status)
+
+ int fits_get_img_paramll / ffgiprll
+ (fitsfile *fptr, int maxdim, > int *bitpix, int *naxis, LONGLONG *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)
+
+ int fits_create_imgll / ffcrimll
+ ( fitsfile *fptr, int bitpix, int naxis, LONGLONG *naxes, > int *status)
+-
+>4 Copy an n-dimensional image in a particular row and column of a
+ binary table (in a vector column)
+ to or from a primary array or image extension.
+
+ The 'cell2image' routine
+ will append a new image extension (or primary array) to the output file.
+ Any WCS keywords associated with the input column image will be translated
+ into the appropriate form for an image extension. Any other keywords
+ in the table header that are not specifically related to defining the
+ binary table structure or to other columns in the table
+ will also be copied to the header of the output image.
+
+ The 'image2cell' routine will copy the input image into the specified row
+ and column of the current binary table in the output file. The binary table
+ HDU must exist before calling this routine, but it
+ may be empty, with no rows or columns of data. The specified column
+ (and row) will be created if it does not already exist. The 'copykeyflag'
+ parameter controls which keywords are copied from the input
+ image to the header of the output table: 0 = no keywords will be copied,
+ 1 = all keywords will be copied (except those keywords that would be invalid in
+> the table header), and 2 = copy only the WCS keywords. \label{copycell}
+-
+ int fits_copy_cell2image
+ (fitsfile *infptr, fitsfile *outfptr, char *colname, long rownum,
+ > int *status)
+
+ int fits_copy_image2cell
+ (fitsfile *infptr, fitsfile *outfptr, char *colname, long rownum,
+ int copykeyflag > int *status)
+-
+
+>5 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)
+-
+>6 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 pair of routines
+ simply writes the array of pixels to the FITS file (doing data type
+ conversion if necessary) whereas the second routines 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, LONGLONG nelements,
+ DTYPE *array, int *status);
+
+ int fits_write_pixll / ffppxll
+ (fitsfile *fptr, int datatype, LONGLONG *fpixel, LONGLONG nelements,
+ DTYPE *array, int *status);
+
+ int fits_write_pixnull / ffppxn
+ (fitsfile *fptr, int datatype, long *fpixel, LONGLONG nelements,
+ DTYPE *array, DTYPE *nulval, > int *status);
+
+ int fits_write_pixnullll / ffppxnll
+ (fitsfile *fptr, int datatype, LONGLONG *fpixel, LONGLONG nelements,
+ DTYPE *array, DTYPE *nulval, > int *status);
+-
+>7 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, LONGLONG firstelem, LONGLONG nelements, > int *status)
+-
+>8 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)
+-
+>9 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 2 routines 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 2 routines are 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, LONGLONG nelements,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_pixll / ffgpxvll
+ (fitsfile *fptr, int datatype, LONGLONG *fpixel, LONGLONG nelements,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_pixnull / ffgpxf
+ (fitsfile *fptr, int datatype, long *fpixel, LONGLONG nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+
+ int fits_read_pixnullll / ffgpxfll
+ (fitsfile *fptr, int datatype, LONGLONG *fpixel, LONGLONG nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+-
+>10 Copy a rectangular section of an image and write it to a new
+ FITS primary image or image extension. The new image HDU is appended
+ to the end of the output file; all the keywords in the input image
+ will be copied to the output image. The common WCS keywords will
+ be updated if necessary to correspond to the coordinates of the section.
+ The format of the section expression is
+ same as specifying an image section using the extended file name
+ syntax (see "Image Section" in Chapter 10).
+ (Examples: "1:100,1:200", "1:100:2, 1:*:2", "*, -*").
+> \label{ffcpimg}
+-
+ int fits_copy_image_section / ffcpimg
+ (fitsfile *infptr, fitsfile *outfptr, char *section, int *status)
+-
+
+**F. Image Compression
+
+CFITSIO transparently supports the 2 methods of image compression described
+below.
+
+1) The entire FITS file may be externally compressed with the gzip or Unix
+compress utility programs, 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 since all the
+I/O is performed in memory; the main limitation with this technique is that
+there must be enough available memory (or swap space) to hold the entire
+uncompressed FITS file.
+
+2) CFITSIO also supports the FITS tiled image compression convention in
+which the image is subdivided into a grid of rectangular tiles, and each
+tile of pixels is individually compressed. The details of this FITS
+compression convention are described at the FITS Support Office web site at
+http://fits.gsfc.nasa.gov/fits\_registry.html Basically, the compressed
+image tiles are stored in rows of a variable length array column in a FITS
+binary table, however CFITSIO recognizes that this 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
+than simply compressing the image using gzip or compress because it
+approximates the floating point values with scaled integers which can then
+be compressed more efficiently.
+
+Currently CFITSIO supports 3 general purpose compression algorithms plus
+one other special-purpose compression technique that is designed for data
+masks with positive integer pixel values. The 3 general purpose algorithms
+are GZIP, Rice, and HCOMPRESS, and the special purpose algorithm is the
+IRAF pixel list compression technique (PLIO). In principle, any number of
+other compression algorithms could also be supported by the FITS tiled
+image compression convention.
+
+The FITS image can be subdivided into any desired rectangular grid of
+compression tiles. With the GZIP, Rice, and PLIO algorithms, the default
+is to take each row of the image as a tile. The HCOMPRESS algorithm is
+inherently 2-dimensional in nature, so the default in this case is to take
+16 rows of the image per tile. In most cases it makes little difference what
+tiling pattern is used, so the default tiles are usually adequate. In the
+case of very small images, it could be more efficient to compress the whole
+image as a single tile. Note that the image dimensions are not required to
+be an integer multiple of the tile dimensions; if not, then the tiles at the
+edges of the image will be smaller than the other tiles.
+
+The 4 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. In
+addition, the HCOMPRESS algorithm supports a 'lossy' compression mode that
+will produce
+larger amount of image compression. This is achieved by specifying a non-zero
+value for the HCOMPRESS ``scale''
+parameter. Since the amount of compression that is achieved depends directly
+on the RMS noise in the image, it is usually more convention
+to specify the HCOMPRESS scale factor relative to the RMS noise.
+Setting s = 2.5 means use a scale factor that is 2.5 times the calculated RMS noise
+in the image tile. In some cases
+it may be desirable to specify the exact scaling to be used,
+instead of specifying it relative to the calculated noise value. This may
+be done by specifying the negative of desired scale value (typically
+in the range -2 to -100).
+
+Very high compression factors (of 100 or more) can be
+achieved by using large HCOMPRESS scale values, however, this can produce undesirable
+``blocky'' artifacts in the compressed image. A variation of the HCOMPRESS
+algorithm (called HSCOMPRESS) can be used in this case to apply a small
+amount of smoothing of the image when it is uncompressed to help cover up
+these artifacts. This smoothing is purely cosmetic and does not cause any
+significant change to the image pixel values.
+
+Floating point FITS images (which have BITPIX = -32 or -64) usually contain
+too much ``noise'' in the least significant bits of the mantissa of the
+pixel values to be effectively compressed with any lossless algorithm.
+Consequently, floating point images are first quantized into scaled integer
+pixel values (and thus throwing away much of the noise) before being
+compressed with the specified algorithm (either GZIP, Rice, or HCOMPRESS).
+This technique produces much higher compression factors than
+simply using the GZIP utility to externally compress the whole FITS file, but it also
+means that the original floating value pixel values are not exactly
+preserved. When done properly, this integer scaling technique will only
+discard the insignificant noise while still preserving all the real
+information in the image. The amount of precision that is retained in the
+pixel values is controlled by the "quantization level" parameter, q. Larger
+values of q will result in compressed images whose pixels more closely match
+the floating point pixel values, but at the same time the amount of
+compression that is achieved will be reduced. Users should experiment with
+different values for this parameter to determine the optimal value that
+preserves all the useful information in the image, without needlessly
+preserving all the ``noise'' which will hurt the compression efficiency.
+
+The default value for the quantization scale factor is 16., which means that
+scaled integer pixel values will be quantized such that the difference
+between adjacent integer values will be 1/16th of the noise level in the
+image background. CFITSIO uses an optimized algorithm to accurately estimate
+the noise in the image. As an example, if the RMS noise in the background
+pixels of an image = 32.0, then the spacing between adjacent scaled
+integer pixel values will equal 2.0 by default. Note that the RMS noise is
+independently calculated for each tile of the image, so the resulting
+integer scaling factor may fluctuate slightly for each tile. In some cases
+it may be desirable to specify the exact quantization level to be used,
+instead of specifying it relative to the calculated noise value. This may
+be done by specifying the negative of desired quantization level for the
+value of q. In the previous example, one could specify q = -2.0 so that the
+quantized integer levels differ by 2.0. Larger negative values for q means
+that the levels are more coarsely spaced, and will produce higher
+compression factors.
+
+There are 2 methods for specifying all the parameters needed to write a FITS
+image in the tile compressed format. The parameters may either be specified
+at run time as part of the file name of the output compressed FITS file, or
+the writing program may call a set of helper CFITSIO subroutines that are provided
+for specifying the parameter values, as described below:
+
+1) At run time, 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 by enclosing the compression
+parameters in square brackets following the root disk file name
+in the following format:
+-
+ [compress NAME T1,T2; q QLEVEL, s HSCALE]
+-
+where
+-
+ NAME = algorithm name: GZIP, Rice, HCOMPRESS, HSCOMPRSS or PLIO
+ may be abbreviated to the first letter (or HS for HSCOMPRESS)
+ T1,T2 = tile dimension (e.g. 100,100 for square tiles 100 pixels wide)
+ QLEVEL = quantization level for floating point FITS images
+ HSCALE = HCOMPRESS scale factor; default = 0 which is lossless.
+-
+
+Here are a few examples of this extended syntax:
+
+-
+ 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 HCOMP]
+
+ myfile.fit[compress R 100,100] - use Rice and 100 x 100 pixel tiles
+
+ myfile.fit[compress R; q 10.0] - quantization level = (RMS-noise) / 10.
+ myfile.fit[compress HS; s 2.0] - HSCOMPRESS (with smoothing)
+ and scale = 2.0 * RMS-noise
+-
+
+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 routines for specifying
+the various compression parameters and similar 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_quantize_level(fitsfile *fptr, float qlevel, int *status)
+ int fits_set_hcomp_scale(fitsfile *fptr, float scale, int *status)
+ int fits_set_hcomp_smooth(fitsfile *fptr, int smooth, int *status)
+ Set smooth = 1 to apply smoothing when uncompressing the image
+
+ 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_quantize_level(fitsfile *fptr, float *level, int *status)
+ int fits_get_hcomp_scale(fitsfile *fptr, float *scale, int *status)
+ int fits_get_hcomp_smooth(fitsfile *fptr, int *smooth, int *status)
+-
+4 symbolic constants are defined for use as the value of the
+`comptype' parameter: GZIP\_1, RICE\_1, HCOMPRESS\_1 or PLIO\_1.
+Entering NULL for
+comptype will turn off the tile-compression and cause normal FITS
+images to be written.
+
+
+No special action is required by software when read tile-compressed images because
+all the CFITSIO routines that read normal uncompressed FITS images also
+transparently 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.
+
+
+The following 2 routines are available for compressing or
+or decompressing an image:
+-
+ int fits_img_compress(fitsfile *infptr, fitsfile *outfptr, int *status);
+ int fits_img_decompress (fitsfile *infptr, fitsfile *outfptr, int *status);
+-
+Before calling the compression routine, the compression parameters must
+first be defined in one of the 2 way described in the previous paragraphs.
+There is also a routine to determine if the current HDU contains
+a tile compressed image (it returns 1 or 0):
+-
+ int fits_is_compressed_image(fitsfile *fptr, int *status);
+-
+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; q 10.0]'
+
+ This will use the Rice compression algorithm, 100 X 100 pixel
+ tiles, and quantization level = RMSnoise / 10.0 (assuming the
+ input image has a floating point data type).
+
+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 often
+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. \label{ffcrtb}
+-
+ int fits_create_tbl / ffcrtb
+ (fitsfile *fptr, int tbltype, LONGLONG 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_rowsll / ffgnrwll
+ (fitsfile *fptr, > LONGLONG *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.
+> \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
+ CFITSIO 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 TDIMn
+ keyword may also be used to specify the unit string length; The pair
+ of keywords TFORMn = '60A' and TDIMn = '(12,5)' would have the
+ same effect as TFORMn = '60A12'). The number
+ of substrings 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_coltypell / ffgtclll
+ (fitsfile *fptr, int colnum, > int *typecode, LONGLONG *repeat,
+ LONGLONG *width, int *status)
+
+ int fits_get_eqcoltype / ffeqty
+ (fitsfile *fptr, int colnum, > int *typecode, long *repeat,
+ long *width, int *status)
+
+ int fits_get_eqcoltypell / ffeqtyll
+ (fitsfile *fptr, int colnum, > int *typecode, LONGLONG *repeat,
+ LONGLONG *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)
+
+ int fits_read_tdimll / ffgtdmll
+ (fitsfile *fptr, int colnum, int maxdim, > int *naxis,
+ LONGLONG *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)
+
+ int fits_decode_tdimll / ffdtdmll
+ (fitsfile *fptr, char *tdimstr, int colnum, int maxdim, > int *naxis,
+ LONGLONG *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 multidimensional array
+> column in a binary table. \label{ffptdm}
+-
+ int fits_write_tdim / ffptdm
+ (fitsfile *fptr, int colnum, int naxis, long *naxes, > int *status)
+
+ int fits_write_tdimll / ffptdmll
+ (fitsfile *fptr, int colnum, int naxis, LONGLONG *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. Note that it is *not* necessary to insert rows in a table before
+ writing data to those rows (indeed, it would be inefficient to do so).
+ Instead one may simply write data to any row of the table, whether that
+ row of data already exists or not.
+
+ 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, LONGLONG firstrow, LONGLONG nrows, > int *status)
+
+ int fits_delete_rows / ffdrow
+ (fitsfile *fptr, LONGLONG firstrow, LONGLONG 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)
+
+ int fits_delete_rowlistll / ffdrwsll
+ (fitsfile *fptr, LONGLONG *rowlist, LONGLONG 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 Copy 'nrows' consecutive rows from one table to another, beginning
+ with row 'firstrow'. These rows will be appended to any existing
+ rows in the output table.
+> Note that the first row in a table is at row = 1. \label{ffcprw}
+-
+ int fits_copy_rows / ffcprw
+ (fitsfile *infptr, fitsfile *outfptr, LONGLONG firstrow,
+ LONGLONG nrows, > int *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. \label{ffmvec}
+-
+ int fits_modify_vector_len / ffmvec
+ (fitsfile *fptr, int colnum, LONGLONG 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 array in 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 it is *not* necessary to insert rows in a table before
+writing data to those rows (indeed, it would be inefficient to do so).
+Instead, one may simply write data to any row of the table, whether that
+row of data already exists or not.
+
+Individual bits in a binary table 'X' or 'B' column may be read/written
+to/from a *char array by specifying the TBIT datatype. The *char
+array will be interpreted as an array of logical TRUE (1) or FALSE (0)
+values that correspond to the value of each bit in the FITS 'X' or 'B' column.
+Alternatively, the values in a binary table 'X' column may be read/written
+8 bits at a time to/from an array of 8-bit integers by specifying the
+TBYTE datatype.
+
+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 third routine
+ simply writes undefined pixel values to the column. The fourth routine
+ fills every column in the table with null values, in the specified
+ rows (ignoring any columns that do not have a defined null value).
+ \label{ffpcl} \label{ffpcn} \label{ffpclu}
+-
+ int fits_write_col / ffpcl
+ (fitsfile *fptr, int datatype, int colnum, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG nelements, DTYPE *array, > int *status)
+
+ int fits_write_colnull / ffpcn
+ (fitsfile *fptr, int datatype, int colnum, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG nelements, DTYPE *array, DTYPE *nulval,
+ > int *status)
+
+ int fits_write_col_null / ffpclu
+ (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelements, > int *status)
+
+ int fits_write_nullrows / ffprwu
+ (fitsfile *fptr, LONGLONG firstrow, LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelements, DTYPE *nulval, DTYPE *array, int *anynul, int *status)
+
+ int fits_read_colnull / ffgcf
+ (fitsfile *fptr, int datatype, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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.
+ Upon return,
+> *n\_good\_rows contains the number of rows that evaluate to TRUE. \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 output
+table is not empty, then this routine will append the new
+selected rows after the existing rows. 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 dimension and type information
+on the result. The returned dimensions correspond to a single row entry
+of the requested expression, and are equivalent to the result of fits\_read\_tdim().
+Note that strings are considered to be one element regardless of string length.
+>If maxdim == 0, then naxes is optional. \label{fftexp}
+-
+ int fits_test_expr / fftexp
+ (fitsfile *fptr, char *expr, int maxdim > int *datatype, long *nelem, int *naxis,
+ long *naxes, int *status)
+-
+
+***6. Column Binning or Histogramming Routines
+
+The following routines may be useful when performing histogramming operations on
+column(s) of a table to generate an image in a primary array or image extension.
+
+>1 Calculate the histogramming parameters (min, max, and bin size
+for each axis of the histogram, based on a variety of possible input parameters.
+If the input names of the columns to be binned are null, then the routine will first
+look for the CPREF = "NAME1, NAME2, ..." keyword which lists the preferred
+columns. If not present, then the routine will assume the column names X, Y, Z, and T
+for up to 4 axes (as specified by the NAXIS parameter).
+
+MININ and MAXIN are input arrays that give the minimum and maximum value for
+the histogram, along each axis. Alternatively, the name of keywords that give
+the min, max, and binsize may be give with the MINNAME, MAXNAME, and BINNAME
+array parameters. If the value = DOUBLENULLVALUE and no keyword names are
+given, then the routine will use the TLMINn and TLMAXn keywords, if present, or the
+actual min and/or max values in the column.
+
+BINSIZEIN is an array giving the binsize along each axis.
+If the value =
+DOUBLENULLVALUE, and a keyword name is not specified with BINNAME,
+then this routine will first look for the TDBINn keyword, or else will
+use a binsize = 1, or a binsize that produces 10 histogram bins, which ever
+is smaller.
+> \label{calcbinning}
+-
+ int fits_calc_binning
+ Input parameters:
+ (fitsfile *fptr, /* IO - pointer to table to be binned */
+ int naxis, /* I - number of axes/columns in the binned image */
+ char colname[4][FLEN_VALUE], /* I - optional column names */
+ double *minin, /* I - optional lower bound value for each axis */
+ double *maxin, /* I - optional upper bound value, for each axis */
+ double *binsizein, /* I - optional 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 */
+ Output parameters:
+ int *colnum, /* O - column numbers, to be binned */
+ long *naxes, /* O - number of bins in each histogram axis */
+ float *amin, /* O - lower bound of the histogram axes */
+ float *amax, /* O - upper bound of the histogram axes */
+ float *binsize, /* O - width of histogram bins/pixels on each axis */
+ int *status)
+-
+
+>2 Copy the relevant keywords from the header of the table that is being
+binned, to the the header of the output histogram image. This will not
+copy the table structure keywords (e.g., NAXIS, TFORMn, TTYPEn, etc.) nor
+will it copy the keywords that apply to other columns of the table that are
+not used to create the histogram. This routine will translate the names of
+the World Coordinate System (WCS) keywords for the binned columns into the
+form that is need for a FITS image (e.g., the TCTYPn table keyword will
+be translated to the CTYPEn image keyword).
+> \label{copypixlist2image}
+-
+ int fits_copy_pixlist2image
+ (fitsfile *infptr, /* I - pointer to input HDU */
+ fitsfile *outfptr, /* I - pointer to output HDU */
+ int firstkey, /* I - first HDU keyword to start with */
+ int naxis, /* I - number of axes in the image */
+ int *colnum, /* I - numbers of the columns to be binned */
+ int *status) /* IO - error status */
+-
+
+>3 Write a set of default WCS keywords to the histogram header, IF the
+WCS keywords do not already exist. This will create a linear WCS where
+the coordinate types are equal to the original column names.
+> \label{writekeyshisto}
+-
+ int fits_write_keys_histo
+ (fitsfile *fptr, /* I - pointer to table to be binned */
+ fitsfile *histptr, /* I - pointer to output histogram image HDU */
+ int naxis, /* I - number of axes in the histogram image */
+ int *colnum, /* I - column numbers of the binned columns */
+ int *status)
+-
+
+>4 Update the WCS keywords in a histogram image header that give the location
+of the reference pixel (CRPIXn), and the pixel size (CDELTn), in the binned
+image.
+> \label{rebinwcs}
+-
+ int fits_rebin_wcs
+ (fitsfile *fptr, /* I - pointer to table to be binned */
+ int naxis, /* I - number of axes in the histogram image */
+ float *amin, /* I - first pixel include in each axis */
+ float *binsize, /* I - binning factor for each axis */
+ int *status)
+-
+
+>5 Bin the values in the input table columns, and write the histogram
+array to the output FITS image (histptr).
+> \label{makehist}
+-
+ int fits_make_hist
+ (fitsfile *fptr, /* I - pointer to table with X and Y cols; */
+ fitsfile *histptr, /* I - pointer to output FITS image */
+ int bitpix, /* I - datatype for image: 16, 32, -32, etc */
+ int naxis, /* I - number of axes in the histogram image */
+ long *naxes, /* I - size of axes in the histogram image */
+ int *colnum, /* I - column numbers (array length = naxis) */
+ float *amin, /* I - minimum histogram value, for each axis */
+ float *amax, /* I - maximum histogram value, for each axis */
+ float *binsize, /* I - bin size along each axis */
+ float weight, /* I - binning weighting factor (FLOATNULLVALUE */
+ /* for no weighting) */
+ int wtcolnum, /* I - keyword or col for weight (or NULL) */
+ int recip, /* I - use reciprocal of the weight? 0 or 1 */
+ 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)
+-
+
+
+**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. The '\#' character will match any consecutive string
+ of decimal digits (0 - 9). 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 Determine the integer data type of an integer keyword value string.
+ The returned datatype value is the minimum integer datatype (starting
+ from top of the following list and working down) required
+> to store the integer value:
+-
+ Data Type Range
+ TSBYTE: -128 to 127
+ TBYTE: 128 to 255
+ TSHORT: -32768 to 32767
+ TUSHORT: 32768 to 65535
+ TINT -2147483648 to 2147483647
+ TUINT 2147483648 to 4294967295
+ TLONGLONG -9223372036854775808 to 9223372036854775807
+-
+> The *neg parameter returns 1 if the input value is
+> negative and returns 0 if it is non-negative.\label{ffinttyp}
+-
+ int fits_get_inttype / ffinttyp
+ (char *value, > int *datatype, int *neg, int *status)
+-
+>14 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 WCS keywords defined in the the WCS papers, including:
+ 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, DATE-OBS
+ 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)
+-
+>15 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)
+
+ int fits_binary_tformll / ffbnfmll
+ (char *tform, > int *typecode, LONGLONG *repeat, long *width,
+ int *status)
+-
+>16 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)
+-
+>17 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)
+-
+>18 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.
+ If the value token is a character string that contains 1 or more
+ embedded blank space characters or slash ('/') characters then the
+> entire character string must be enclosed in single quotes.
+
+>- The COMMENT token is optional, but if present must be separated from
+> the VALUE token by a blank space or 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
+-
+>19 Translate a keyword name into a new name, based on a set of patterns.
+This routine is useful for translating keywords in cases such as
+adding or deleting columns in
+a table, or copying a column from one table to another, or extracting
+an array from a cell in a binary table column into an image extension. In
+these cases, it is necessary to translate the names of the keywords associated
+with the original table column(s) into the appropriate keyword name in the final
+file. For example, if column 2 is deleted from a table,
+then the value of 'n' in all the
+TFORMn and TTYPEn keywords for columns 3 and higher must be decremented
+by 1. Even more complex translations are sometimes needed to convert the
+WCS keywords when extracting an image out of a table column cell into
+a separate image extension.
+
+The user passes an array of patterns to be matched. Input pattern
+number i is pattern[i][0], and output pattern number i is
+pattern[i][1]. Keywords are matched against the input patterns. If a
+match is found then the keyword is re-written according to the output
+pattern.
+
+Order is important. The first match is accepted. The fastest match
+will be made when templates with the same first character are grouped
+together.
+
+Several characters have special meanings:
+-
+ i,j - single digits, preserved in output template
+ n - column number of one or more digits, preserved in output template
+ m - generic number of one or more digits, preserved in output template
+ a - coordinate designator, preserved in output template
+ # - number of one or more digits
+ ? - any character
+ * - only allowed in first character position, to match all
+ keywords; only useful as last pattern in the list
+-
+i, j, n, and m are returned by the routine.
+
+For example, the input pattern "iCTYPn" will match "1CTYP5" (if n\_value
+is 5); the output pattern "CTYPEi" will be re-written as "CTYPE1".
+Notice that "i" is preserved.
+
+The following output patterns are special:
+
+ "-" - do not copy a keyword that matches the corresponding input pattern
+
+ "+" - copy the input unchanged
+
+The inrec string could be just the 8-char keyword name, or the entire
+80-char header record. Characters 9 - 80 in the input string simply get
+appended to the translated keyword name.
+
+If n\_range = 0, then only keywords with 'n' equal to n\_value will be
+considered as a pattern match. If n\_range = +1, then all values of
+'n' greater than or equal to n\_value will be a match, and if -1,
+>then values of 'n' less than or equal to n\_value will match.\label{translatekey}
+-
+int fits_translate_keyword(
+ char *inrec, /* I - input string */
+ char *outrec, /* O - output converted string, or */
+ /* a null string if input does not */
+ /* match any of the patterns */
+ char *patterns[][2],/* I - pointer to input / output string */
+ /* templates */
+ int npat, /* I - number of templates passed */
+ int n_value, /* I - base 'n' template value of interest */
+ int n_offset, /* I - offset to be applied to the 'n' */
+ /* value in the output string */
+ int n_range, /* I - controls range of 'n' template */
+ /* values of interest (-1,0, or +1) */
+ int *pat_num, /* O - matched pattern number (0 based) or -1 */
+ int *i, /* O - value of i, if any, else 0 */
+ int *j, /* O - value of j, if any, else 0 */
+ int *m, /* O - value of m, if any, else 0 */
+ int *n, /* O - value of n, if any, else 0 */
+ int *status) /* IO - error status */
+-
+> Here is an example of some of the patterns used to convert the keywords associated
+with an image in a cell of a table column into the keywords appropriate for
+>an IMAGE extension:
+-
+ char *patterns[][2] = {{"TSCALn", "BSCALE" }, /* Standard FITS keywords */
+ {"TZEROn", "BZERO" },
+ {"TUNITn", "BUNIT" },
+ {"TNULLn", "BLANK" },
+ {"TDMINn", "DATAMIN" },
+ {"TDMAXn", "DATAMAX" },
+ {"iCTYPn", "CTYPEi" }, /* Coordinate labels */
+ {"iCTYna", "CTYPEia" },
+ {"iCUNIn", "CUNITi" }, /* Coordinate units */
+ {"iCUNna", "CUNITia" },
+ {"iCRVLn", "CRVALi" }, /* WCS keywords */
+ {"iCRVna", "CRVALia" },
+ {"iCDLTn", "CDELTi" },
+ {"iCDEna", "CDELTia" },
+ {"iCRPXn", "CRPIXi" },
+ {"iCRPna", "CRPIXia" },
+ {"ijPCna", "PCi_ja" },
+ {"ijCDna", "CDi_ja" },
+ {"iVn_ma", "PVi_ma" },
+ {"iSn_ma", "PSi_ma" },
+ {"iCRDna", "CRDERia" },
+ {"iCSYna", "CSYERia" },
+ {"iCROTn", "CROTAi" },
+ {"WCAXna", "WCSAXESa"},
+ {"WCSNna", "WCSNAMEa"}};
+-
+>20 Translate the keywords in the input HDU into the keywords that are
+appropriate for the output HDU. This is a driver routine that calls
+>the previously described routine.
+-
+int fits_translate_keywords(
+ fitsfile *infptr, /* I - pointer to input HDU */
+ fitsfile *outfptr, /* I - pointer to output HDU */
+ int firstkey, /* I - first HDU record number to start with */
+ char *patterns[][2],/* I - pointer to input / output keyword templates */
+ int npat, /* I - number of templates passed */
+ int n_value, /* I - base 'n' template value of interest */
+ int n_offset, /* I - offset to be applied to the 'n' */
+ /* value in the output string */
+ int n_range, /* I - controls range of 'n' template */
+ /* values of interest (-1,0, or +1) */
+ int *status) /* IO - error status */
+-
+
+>21 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, LONGLONG maxrows, int maxranges, >
+ int *numranges, long *rangemin, long *rangemax, int *status)
+
+ int fits_parse_rangell / ffrwrgll(char *rowlist, LONGLONG maxrows, int maxranges, >
+ int *numranges, LONGLONG *rangemin, LONGLONG *rangemax, int *status)
+-
+>22 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)
+-
+>23 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)
+-
+>24 Estimate the root-mean-squared (RMS) noise in an image.
+These routines are mainly for use with the Hcompress image compression
+algorithm. They return an estimate of the RMS noise in the background
+pixels of the image. This robust algorithm (written by Richard
+White, STScI) first attempts to estimate the RMS value
+as 1.68 times the median of the absolute differences between successive
+pixels in the image. If the median = 0, then the
+algorithm falls back to computing the RMS of the difference between successive
+pixels, after several N-sigma rejection cycles to remove
+extreme values. The input parameters are: the array of image pixel values
+(either float or short values), the number of values in the array,
+the value that is used to represent null pixels (enter a very
+>large number if there are no null pixels). \label{imageRMS}
+-
+ int fits_rms_float (float fdata[], int npix, float in_null_value,
+ > double *rms, int *status)
+ int fits_rms_short (short fdata[], int npix, short in_null_value,
+ > double *rms, int *status)
+-
+>25 Was CFITSIO compiled with the -D\_REENTRANT directive
+so that it may be safely used in multi-threaded environments?
+The following function returns 1 if yes, 0 if no. Note, however,
+that even if the -D\_REENTRANT directive was specified, this does
+not guarantee that the CFITSIO routines are thread-safe, because
+>some compilers may not support this feature.\label{reentrant}
+-
+int fits_is_reentrant(void)
+-
+
+*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 repeatedly 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. World 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 a few 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 keywords contained in the FITS file headers.
+One convenient way to pass this information to the external 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., the 'wcspih' routine in the WCSLIB
+library and the 'astFitsChan' and 'astPutCards' functions in the 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.
+
+ There are 2 related routines: fits\_hdr2str simply concatenates all
+ the existing keywords in the header; fits\_convert\_hdr2str is similar,
+ except that if the CHDU is a tile compressed image (stored in a binary
+ table) then it will first convert that header back to that of a
+ normal FITS image before concatenating the keywords.
+
+ 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 **exclist parameter. \label{hdr2str}
+-
+ int fits_hdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+
+ int fits_convert_hdr2str / ffcnvthdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+-
+
+>2 The following CFITSIO routine is specifically designed for use
+in conjunction with the WCSLIB library. It is not expected that
+applications programmers will call this routine directly, but it
+is documented here for completeness. This routine extracts arrays
+from a binary table that contain WCS information using the -TAB table
+lookup convention. See the documentation provided with the WCSLIB
+> library for more information. \label{wcstab}
+-
+ int fits_read_wcstab
+ (fitsfile *fptr, int nwtb, wtbarr *wtb, 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.
+
+ The first routine (ffgics) returns
+ the primary WCS, whereas the second routine returns the particular
+ version of the WCS specified by the 'version' parameter, which much
+ be a character ranging from 'A' to 'Z' (or a blank character, which is
+ equivalent to calling ffgics).
+
+ 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)
+
+ int fits_read_img_coord_version / ffgicsa
+ (fitsfile *fptr, char version, > 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://fits.gsfc.nasa.gov/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. Note that values of the memptr and memsize pointers will be updated
+by CFITSIO if the location or size of the FITS file in memory
+>should change as a result of allocating more memory. \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. Note that values of the memptr and memsize pointers will be updated
+by CFITSIO if the location or size of the FITS file in memory
+>should change as a result of allocating more memory. \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, namely:
+\begin{itemize}
+\item
+the file type (file://, ftp://, http://, etc),
+\item
+the base input file name,
+\item
+the name of the output file that the input file is to be copied to prior
+to opening,
+\item
+the HDU or extension specification,
+\item
+the filtering specifier,
+\item
+the binning specifier,
+\item
+the column specifier,
+\item
+and the
+image pixel filtering specifier.
+\end{itemize}
+A null pointer (0) may be be specified for any of the output string arguments
+that are not needed. Null strings will be returned for any components that are not
+present in the input file name. The calling routine must allocate sufficient
+memory to hold the returned character strings. Allocating the string lengths
+equal to FLEN\_FILENAME is guaranteed to be safe.
+These routines are mainly for internal use
+>by other CFITSIO routines. \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)
+
+ int fits_parse_input_filename / ffifile
+ (char *filename, > char *filetype, char *infile, char *outfile, char
+ *extspec, char *filter, char *binspec, char *colspec, char *pixspec,
+ 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. The calling routine must allocate sufficient
+memory to hold the returned rootname character string. Allocating the length
+equal to FLEN\_FILENAME is guaranteed to be safe.
+> \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. \label{ffghad}
+-
+ int fits_get_hduaddr / ffghad (only supports files up to 2.1 GB in size)
+ (fitsfile *fptr, > long *headstart, long *datastart, long *dataend,
+ int *status)
+
+ int fits_get_hduaddrll / ffghadll (supports large files)
+ (fitsfile *fptr, > LONGLONG *headstart, LONGLONG *datastart,
+ LONGLONG *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)
+
+ int fits_insert_imgll / ffiimgll
+ (fitsfile *fptr, int bitpix, int naxis, LONGLONG *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. Under normal circumstances,
+ the nrows
+ paramenter should have a value of 0; CFITSIO will automatically update
+ the number of rows as data is written to the table. 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, LONGLONG rowlen, LONGLONG nrows, int tfields, char *ttype[],
+ long *tbcol, char *tform[], char *tunit[], char *extname, > int *status)
+
+ int fits_insert_btbl / ffibin
+ (fitsfile *fptr, LONGLONG 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)
+
+ int fits_resize_imgll / ffrsimll
+ (fitsfile *fptr, int bitpix, int naxis, LONGLONG *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 Read or write a specified number of bytes starting at the specified byte
+ offset from the start of the extension data unit. These low
+ level routine are intended mainly for accessing the data in
+ non-standard, conforming extensions, and should not be used for standard
+> IMAGE, TABLE, or BINTABLE extensions. \label{ffgextn}
+-
+ int fits_read_ext / ffgextn
+ (fitsfile *fptr, LONGLONG offset, LONGLONG nbytes, void *buffer)
+ int fits_write_ext / ffpextn
+ (fitsfile *fptr, LONGLONG offset, LONGLONG nbytes, void *buffer)
+-
+>8 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 required extension header keywords into the CHU.
+ These routines are not required, and instead the appropriate
+ header may be constructed by writing each individual keyword in the
+ proper sequence.
+
+ 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. The general fits\_write\_exthdr routine
+ may be used to write the header of any conforming FITS
+> extension. \label{ffphpr} \label{ffphps}
+-
+ int fits_write_imghdr / ffphps
+ (fitsfile *fptr, int bitpix, int naxis, long *naxes, > int *status)
+
+ int fits_write_imghdrll / ffphpsll
+ (fitsfile *fptr, int bitpix, int naxis, LONGLONG *naxes, > int *status)
+
+ int fits_write_grphdr / ffphpr
+ (fitsfile *fptr, int simple, int bitpix, int naxis, long *naxes,
+ LONGLONG pcount, LONGLONG gcount, int extend, > int *status)
+
+ int fits_write_grphdrll / ffphprll
+ (fitsfile *fptr, int simple, int bitpix, int naxis, LONGLONG *naxes,
+ LONGLONG pcount, LONGLONG gcount, int extend, > int *status)
+
+ int fits_write_exthdr /ffphext
+ (fitsfile *fptr, char *xtension, int bitpix, int naxis, long *naxes,
+ LONGLONG pcount, LONGLONG gcount, > 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, LONGLONG rowlen, LONGLONG 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, LONGLONG nrows, int tfields, char **ttype,
+ char **tform, char **tunit, char *extname, LONGLONG 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_imghdrll / ffghprll
+ (fitsfile *fptr, int maxdim, > int *simple, int *bitpix, int *naxis,
+ LONGLONG *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, LONGLONG *tbcol, char **tform, char **tunit,
+ char *extname, int *status)
+
+ int fits_read_atblhdrll / ffghtbll
+ (fitsfile *fptr,int maxdim, > LONGLONG *rowlen, LONGLONG *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)
+
+ int fits_read_btblhdrll / ffghbnll
+ (fitsfile *fptr, int maxdim, > LONGLONG *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, > int *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 or
+ call fits_free_memory.
+
+ int fits_read_key_longstr / ffgkls
+ (fitsfile *fptr, char *keyname, > char **longstr, char *comment,
+ int *status)
+
+ int fits_free_memory / fffree
+ (char *longstr, int *status);
+
+ int fits_read_key_[log, lng, flt, dbl, cmp, dblcmp] / ffgky[ljedcm]
+ (fitsfile *fptr, char *keyname, > DTYPE *numval, char *comment,
+ int *status)
+
+ int fits_read_key_lnglng / ffgkyjj
+ (fitsfile *fptr, char *keyname, > LONGLONG *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, LONGLONG 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, LONGLONG 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 specifically
+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, LONGLONG firstelem, LONGLONG 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, LONGLONG firstelem, LONGLONG nelements,
+ DTYPE *array, > int *status);
+
+ int fits_write_imgnull / ffppn
+ (fitsfile *fptr, int datatype, LONGLONG firstelem, LONGLONG 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, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstelem, LONGLONG 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, LONGLONG dim1, LONGLONG naxis1,
+ LONGLONG 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, LONGLONG dim1, LONGLONG dim2, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG 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, LONGLONG dim1, LONGLONG naxis1,
+ LONGLONG 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, LONGLONG dim1,
+ LONGLONG dim2, LONGLONG naxis1, LONGLONG naxis2, LONGLONG 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)
+
+ int fits_get_bcolparmsll / ffgbclll
+ (fitsfile *fptr, int colnum, > char *ttype, char *tunit,
+ char *typechar, LONGLONG *repeat, double *scale, double *zero,
+ LONGLONG *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, > LONGLONG *heapsize, LONGLONG *unused, LONGLONG *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, LONGLONG firstrow, LONGLONG firstchar, LONGLONG nchars,
+ > unsigned char *values, int *status)
+
+ int fits_write_tblbytes / ffptbb
+ (fitsfile *fptr, LONGLONG firstrow, LONGLONG firstchar, LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG 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. \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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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. \label{ffpcns}
+-
+ int fits_write_colnull_str / ffpcns
+ (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG 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, LONGLONG rownum, LONGLONG repeat,
+ LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG 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, LONGLONG firstrow, LONGLONG firstbit,
+ LONGLONG 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, LONGLONG firstrow, LONGLONG, 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 pair of routine returns a single descriptor whereas the second
+ pair of routine
+ returns the descriptors for a range of rows in the table. The only
+ difference between the 2 routines in each pair is that one returns
+ the parameters as 'long' integers, whereas the other returns the values
+ as 64-bit 'LONGLONG' integers.
+> \label{ffgdes}
+-
+ int fits_read_descript / ffgdes
+ (fitsfile *fptr, int colnum, LONGLONG rownum, > long *repeat,
+ long *offset, int *status)
+
+ int fits_read_descriptll / ffgdesll
+ (fitsfile *fptr, int colnum, LONGLONG rownum, > LONGLONG *repeat,
+ LONGLONG *offset, int *status)
+
+ int fits_read_descripts / ffgdess
+ (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG nrows
+ > long *repeat, long *offset, int *status)
+
+ int fits_read_descriptsll / ffgdessll
+ (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG nrows
+ > LONGLONG *repeat, LONGLONG *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. See also the stream:// driver which provides a
+more efficient, but more restricted method of reading or writing to
+the stdin or stdout streams.
+
+\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][pixFilter]
+
+When opening an existing table HDU:
+ filetype://BaseFilename(outName)[HDUlocation][colFilter][rowFilter][binSpec]
+-
+The filetype, BaseFilename, outName, HDUlocation, ImageSection, and pixFilter
+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
+ supports username:password just like the ftp driver.
+ Proxy HTTP servers are supported using the http_proxy
+ environment variable (see following note).
+ stream:// - special driver to read an input FITS file from the stdin
+ stream, and/or write an output FITS file to the stdout
+ stream. This driver is fragile and has limited
+ functionality (see the following note).
+ gsiftp:// - access files on a computational grid using the gridftp
+ protocol in the Globus toolkit (see following note).
+ root:// - uses the CERN root protocol for writing as well as
+ reading files over the network (see following note).
+ shmem:// - opens or creates a file which persists in the computer's
+ shared memory (see following note).
+ 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 stream filetype driver
+
+The stream driver can be used to efficiently read a FITS file from the stdin
+file stream or write a FITS to the stdout file stream. However, because these
+input and output streams must be accessed sequentially, the FITS file reading or
+writing application must also read and write the file sequentially, at least
+within the tolerances described below.
+
+CFITSIO supports 2 different methods for accessing FITS files on the stdin and
+stdout streams. The original method, which is invoked by specifying a dash
+character, "-", as the name of the file when opening or creating it, works by
+storing a complete copy of the entire FITS file in memory. In this case, when
+reading from stdin, CFITSIO will copy the entire stream into memory before doing
+any processing of the file. Similarly, when writing to stdout, CFITSIO will
+create a copy of the entire FITS file in memory, before finally flushing it out
+to the stdout stream when the FITS file is closed. Buffering the entire FITS
+file in this way allows the application to randomly access any part of the FITS
+file, in any order, but it also requires that the user have sufficient available
+memory (or virtual memory) to store the entire file, which may not be possible
+in the case of very large files.
+
+The newer stream filetype provides a more memory-efficient method of accessing
+FITS files on the stdin or stdout streams. Instead of storing a copy of the
+entire FITS file in memory, CFITSIO only uses a set of internal buffer which by
+default can store 40 FITS blocks, or about 100K bytes of the FITS file. The
+application program must process the FITS file sequentially from beginning to
+end, within this 100K buffer. Generally speaking the application program must
+conform to the following restrictions:
+
+\begin{itemize}
+\item
+The program must finish reading or writing the header keywords
+before reading or writing any data in the HDU.
+\item
+The HDU can contain at most about 1400 header keywords. This is the
+maximum that can fit in the nominal 40 FITS block buffer. In principle,
+this limit could be increased by recompiling CFITSIO with a larger
+buffer limit, which is set by the NIOBUF parameter in fitsio2.h.
+\item
+The program must read or write the data in a sequential manner from the
+beginning to the end of the HDU. Note that CFITSIO's internal
+100K buffer allows a little latitude in meeting this requirement.
+\item
+The program cannot move back to a previous HDU in the FITS file.
+\item
+Reading or writing of variable length array columns in binary tables is not
+supported on streams, because this requires moving back and forth between the
+fixed-length portion of the binary table and the following heap area where the
+arrays are actually stored.
+\item
+Reading or writing of tile-compressed images is not supported on streams,
+because the images are internally stored using variable length arrays.
+\end{itemize}
+
+***3. Notes about the gsiftp filetype
+
+DEPENDENCIES: Globus toolkit (2.4.3 or higher) (GT) should be installed.
+There are two different ways to install GT:
+
+1) goto the globus toolkit web page www.globus.org and follow the
+ download and compilation instructions;
+
+2) goto the Virtual Data Toolkit web page http://vdt.cs.wisc.edu/
+ and follow the instructions (STRONGLY SUGGESTED);
+
+Once a globus client has been installed in your system with a specific flavour
+it is possible to compile and install the CFITSIO libraries.
+Specific configuration flags must be used:
+
+1) --with-gsiftp[[=PATH]] Enable Globus Toolkit gsiftp protocol support
+ PATH=GLOBUS\_LOCATION i.e. the location of your globus installation
+
+2) --with-gsiftp-flavour[[=PATH] defines the specific Globus flavour
+ ex. gcc32
+
+Both the flags must be used and it is mandatory to set both the PATH and the
+flavour.
+
+USAGE: To access files on a gridftp server it is necessary to use a gsiftp prefix:
+
+example: gsiftp://remote\_server\_fqhn/directory/filename
+
+The gridftp driver uses a local buffer on a temporary file the file is located
+in the /tmp directory. If you have special permissions on /tmp or you do not have a /tmp
+directory, it is possible to force another location setting the GSIFTP\_TMPFILE environment
+variable (ex. export GSIFTP\_TMPFILE=/your/location/yourtmpfile).
+
+Grid FTP supports multi channel transfer. By default a single channel transmission is
+available. However, it is possible to modify this behavior setting the GSIFTP\_STREAMS
+environment variable (ex. export GSIFTP\_STREAMS=8).
+
+
+***4. 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.
+
+***5. 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.
+
+An optional pound sign character ("\#") may be appended to the extension
+name or number to signify that any other extensions in the file should
+be ignored during any subsequent file filtering operations. For example,
+when doing row filtering operations on a table extension, CFITSIO normally
+creates a copy of the filtered table in memory, along with a verbatim
+copy of all the other extensions in the input FITS file. If the pound
+sign is appended to the table extension name, then only that extension,
+and none of the other extensions in the file, will by copied to memory,
+as in the following example:
+-
+ myfile.fit[events#][TIME > 10000]
+-
+
+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. (If a `\#' character is appended to the name or number of the
+image HDU, as in "myfile.fits[1\#][1:200,1:200]", then the other
+HDUs in the input file will not be copied into memory).
+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. Image Transform Filters
+
+CFITSIO can apply a user-specified mathematical function to the value
+of every pixel in a FITS image, thus creating a new virtual image
+in computer memory that is then opened and read by the application
+program. The original FITS image is not modified by this process.
+
+The image transformation specifier is appended to the input
+FITS file name and is enclosed in square brackets. It begins with the
+letters 'PIX' to distinguish it from other types of FITS file filters
+that are recognized by CFITSIO. The image transforming function may
+use any of the mathematical operators listed in the following
+'Row Filtering Specification' section of this document.
+Some examples of image transform filters are:
+-
+ [pix X * 2.0] - multiply each pixel by 2.0
+ [pix sqrt(X)] - take the square root of each pixel
+ [pix X + #ZEROPT - add the value of the ZEROPT keyword
+ [pix X>0 ? log10(X) : -99.] - if the pixel value is greater
+ than 0, compute the base 10 log,
+ else set the pixel = -99.
+-
+Use the letter 'X' in the expression to represent the current pixel value
+in the image. The expression is evaluated
+independently for each pixel in the image and may be a function of 1) the
+original pixel value, 2) the value of other pixels in the image at
+a given relative offset from the position of the pixel that is being
+evaluated, and 3) the value of
+any header keywords. Header keyword values are represented
+by the name of the keyword preceded by the '\#' sign.
+
+
+To access the the value of adjacent pixels in the image,
+specify the (1-D) offset from the current pixel in curly brackets.
+For example
+-
+ [pix (x{-1} + x + x{+1}) / 3]
+-
+will replace each pixel value with the running mean of the values of that
+pixel and it's 2 neighboring pixels. Note that in this notation the image
+is treated as a 1-D array, where each row of the image (or higher dimensional
+cube) is appended one after another in one long array of pixels.
+It is possible to refer to pixels
+in the rows above or below the current pixel by using the value of the
+NAXIS1 header keyword. For example
+-
+ [pix (x{-#NAXIS1} + x + x{#NAXIS1}) / 3]
+-
+will compute the mean of each image pixel and the pixels immediately
+above and below it in the adjacent rows of the image.
+The following more complex example
+creates a smoothed virtual image where each pixel
+is a 3 x 3 boxcar average of the input image pixels:
+-
+ [pix (X + X{-1} + X{+1}
+ + X{-#NAXIS1} + X{-#NAXIS1 - 1} + X{-#NAXIS1 + 1}
+ + X{#NAXIS1} + X{#NAXIS1 - 1} + X{#NAXIS1 + 1}) / 9.]
+-
+If the pixel offset
+extends beyond the first or last pixel in the image, the function will
+evaluate to undefined, or NULL.
+
+For complex or commonly used image filtering operations,
+one can write the expression into an external text file and
+then import it into the
+filter using the syntax '[pix @filename.txt]'. The mathematical
+expression can
+extend over multiple lines of text in 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.
+
+By default, the datatype of the resulting image will be the same as
+the original image, but one may force a different datatype by appended
+a code letter to the 'pix' keyword:
+-
+ pixb - 8-bit byte image with BITPIX = 8
+ pixi - 16-bit integer image with BITPIX = 16
+ pixj - 32-bit integer image with BITPIX = 32
+ pixr - 32-bit float image with BITPIX = -32
+ pixd - 64-bit float image with BITPIX = -64
+-
+Also by default, any other HDUs in the input file will be copied without
+change to the
+output virtual FITS file, but one may discard the other HDUs by adding
+the number '1' to the 'pix' keyword (and following any optional datatype code
+letter). For example:
+-
+ myfile.fits[3][pixr1 sqrt(X)]
+-
+will create a virtual FITS file containing only a primary array image
+with 32-bit floating point pixels that have a value equal to the square
+root of the pixels in the image that is in the 3rd extension
+of the 'myfile.fits' file.
+
+
+**I. 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. (If a `\#' character is appended to the name
+or number of the
+table HDU then only the primary array, and none of the other
+HDUs in the input file will be copied into memory).
+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 commas or 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). If the keyword name ends with a
+pound sign '\#', then cfitsio will substitute the number of the
+most recently referenced column for the \# character .
+This is especially useful when writing
+a column-related keyword like TUNITn for a newly created column,
+as shown in the following examples.
+
+\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. If no columns to be deleted are specified, then only the
+columns that are explicitly listed will be included in the filtered
+output table. To include all the columns, add the '*' wildcard
+specifier at the end of the list, as shown in the examples.
+
+For complex or commonly used operations, one can 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; #TUNIT#(column units) = 'counts';*]
+ - creates new PI column from PHA values
+ and also writes the TUNITn keyword
+ for the new column. The final '*'
+ expression means preserve all the
+ columns in the input table in the
+ virtual output table; without the '*'
+ the output table would only contain
+ the single 'PI' column.
+
+ [col rate = rate/exposure; TUNIT#(&) = 'counts/s';*]
+ - recomputes the rate column by dividing
+ it by the EXPOSURE keyword value. This
+ also modifies the value of the TUNITn
+ keyword for this column. The use of the
+ '&' character for the keyword comment
+ string means preserve the existing
+ comment string for that keyword. The
+ final '*' preserves all the columns
+ in the input table in the virtual
+ output table.
+-
+
+**J. 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.
+(If a `\#' character is appended to the name
+or number of the
+table HDU then only the primary array, and none of the other
+HDUs in the input file will be copied into 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 enclose 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(y,x)
+ "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" x % y "random # [0.0,1.0)" random()
+ "random Gaussian" randomn() "random Poisson" randomp(x)
+ "minimum" min(x,y) "maximum" max(x,y)
+ "cumulative sum" accum(x) "sequential difference" seqdiff(x)
+ "if-then-else" b?x:y
+ "angular separation" angsep(ra1,dec1,ra2,de2) (all in degrees)
+ "substring" strmid(s,p,n) "string search" strstr(s,r)
+-
+Three different random number functions are provided: random(), with
+no arguments, produces a uniform random deviate between 0 and 1;
+randomn(), also with no arguments, produces a normal (Gaussian) random
+deviate with zero mean and unit standard deviation; randomp(x)
+produces a Poisson random deviate whose expected number of counts is
+X. X may be any positive real number of expected counts, including
+fractional values, but the return value is an integer.
+
+When the random functions are used in a vector expression, by default
+the same random value will be used when evaluating each element of the vector.
+If different random numbers are desired, then the name of a vector
+column should be supplied as the single argument to the random
+function (e.g., "flux + 0.1 * random(flux)", where "flux' is the
+name of a vector column). This will create a vector of
+random numbers that will be used in sequence when evaluating each
+element of the vector expression.
+
+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.
+
+In the if-then-else expression, "b?x:y", b is an explicit boolean
+value or expression. There is no automatic type conversion from
+numeric to boolean values, so one needs to use "iVal!=0" instead of
+merely "iVal" as the boolean argument. x and y can be any scalar data
+type (including string).
+
+The angsep function computes the angular separation in degrees
+between 2 celestial positions, where the first 2 parameters
+give the RA-like and Dec-like coordinates (in decimal degrees)
+of the first position, and the 3rd and 4th parameters give the
+coordinates of the second position.
+
+The substring function strmid(S,P,N) extracts a substring from S,
+starting at string position P, with a substring length N. The first
+character position in S is labeled as 1. If P is 0, or refers to a
+position beyond the end of S, then the extracted substring will be
+NULL. S, P, and N may be functions of other columns.
+
+The string search function strstr(S,R) searches for the first occurrence
+of the substring R in S. The result is an integer, indicating the
+character position of the first match (where 1 is the first character
+position of S). If no match is found, then strstr() returns a NULL
+value.
+
+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.
+
+ 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)
+ "summation" 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 STDDEV() function computes the sample
+ standard deviation, i.e. it is proportional to 1/SQRT(N-1) instead
+ of 1/SQRT(N), where N is NVALID(V).
+
+ 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. There are 2 supported formats for the
+ region file: ASCII file or FITS binary table. The region file
+ 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. The FITS region file format is defined in a document
+ available from the FITS Support Office at
+ http://fits.gsfc.nasa.gov/ registry/ region.html
+
+ In its simplest 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 low-level functions that are primarily for use with
+ regfilter function, but they can be called directly. They
+ return a boolean true or false depending on whether a two
+ dimensional point is in the region or not. The positional coordinates
+ must be given in pixel units:
+-
+ "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 supports reading and writing FITS images or table columns containing
+64-bit integer data values. Support for 64-bit integers was added to the
+official FITS Standard in December 2005.
+ FITS 64-bit images have BITPIX =
+64, and the 64-bit binary table columns have TFORMn = 'K'. CFITSIO also
+supports the 'Q' variable-length array table column format which is
+analogous to the 'P' column format except that the array descriptor
+is stored as a pair of 64-bit integers.
+
+For the convenience of C programmers, the fitsio.h include file
+defines (with a typedef statement) the 'LONGLONG' datatype to be
+equivalent to an appropriate 64-bit integer datatype on each platform.
+Since there is currently no universal standard
+for the name of the 64-bit integer datatype (it might be defined as
+'long long', 'long', or '\_\_int64' depending on the platform)
+C programmers may prefer to use the 'LONGLONG' datatype when
+declaring or allocating 64-bit integer quantities when writing
+code which needs to run on multiple platforms.
+Note that CFITSIO will implicitly convert the datatype when reading
+or writing FITS 64-bit integer images and columns with data arrays of
+a different integer or floating point datatype, but there is an
+increased risk of loss of numerical precision or
+numerical overflow in this case.
+
+**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
+
+CFITSIO supports 2 ways to specify that a character column in a binary
+table contains an array of fixed-length strings. The first way, which
+is officially supported by the FITS Standard document, uses the TDIMn keyword.
+For example, if TFORMn = '60A' and TDIMn = '(12,5)' then that
+column will be interpreted as containing an array of 5 strings, each 12
+characters long.
+
+CFITSIO also supports 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 (except the default with the HCOMPRESS algorithm is to
+compress the whole 2D image as a single tile). 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. Because the data in FITS files is always stored in "big-endian" byte order,
+where the first byte of numeric values contains the most significant bits and the
+last byte contains the least significant bits, CFITSIO must swap the order of the bytes
+when reading or writing FITS files when running on little-endian machines (e.g.,
+Linux and Microsoft Windows operating systems running on PCs with x86 CPUs).
+
+On fairly new CPUs that support "SSSE3" machine instructions
+(e.g., starting with Intel Core 2 CPUs in 2007, and in AMD CPUs
+beginning in 2011) significantly faster 4-byte and 8-byte swapping
+algorithms are available. These faster byte swapping functions are
+not used by default in CFITSIO (because of the potential code
+portablility issues), but users can enable them on supported
+platforms by adding the appropriate compiler flags (-mssse3 with gcc
+or icc on linux) when compiling the swapproc.c source file, which will
+allow the compiler to generate code using the SSSE3 instruction set.
+A convenient way to do this is to configure the CFITSIO library
+with the following command:
+-
+ > ./configure --enable-ssse3
+-
+Note, however, that a binary executable file that is
+created using these faster functions will only run on
+machines that support the SSSE3 machine instructions. It will
+crash on machines that do not support them.
+
+For faster 2-byte swaps on virtually all x86-64 CPUs (even those that
+do not support SSSE3), a variant using only SSE2 instructions exists.
+SSE2 is enabled by default on x86\_64 CPUs with 64-bit operating systems
+(and is also automatically enabled by the --enable-ssse3 flag).
+When running on x86\_64 CPUs with 32-bit operating systems, these faster
+2-byte swapping algorithms are not used by default in CFITSIO, but can be
+enabled explicitly with:
+-
+./configure --enable-sse2
+-
+Preliminary testing indicates that these SSSE3 and SSE2 based
+byte-swapping algorithms can boost the CFITSIO performance when
+reading or writing FITS images by 20\% - 30\% or more.
+It is important to note, however, that compiler optimization must be
+turned on (e.g., by using the -O1 or -O2 flags in gcc) when building
+programs that use these fast byte-swapping algorithms in order
+to reap the full benefit of the SSSE3 and SSE2 instructions; without
+optimization, the code may actually run slower than when using
+more traditional byte-swapping techniques.
+
+2. 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.
+
+3. 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 and on the number of IO
+buffers that have been allocated in CFITSIO. 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 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.
+
+4. 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.
+
+5. 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 that have the same information content.
+
+6. 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 relatively fast and it makes
+little difference which order they are accessed.
+
+7. 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.
+
+8. 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.
+
+9. 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.
+
+10. 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. In practice, this is probably not a significant efficiency issue.
+
+11. 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.
+
+12. 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?).
+
+13. Finally, external factors such as the speed of the data storage device,
+the size of the data cache, 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, the entire hardware
+and software system should be reviewed 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\_binning & \pageref{calcbinning} \\
+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\_convert\_hdr2str & \pageref{ffhdr2str}, \pageref{hdr2str} \\
+fits\_copy\_cell2image & \pageref{copycell} \\
+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\_image2cell & \pageref{copycell} \\
+fits\_copy\_image\_section & \pageref{ffcpimg} \\
+fits\_copy\_key & \pageref{ffcpky} \\
+fits\_copy\_member & \pageref{ffgmcp} \\
+fits\_copy\_pixlist2image & \pageref{copypixlist2image} \\
+fits\_copy\_rows & \pageref{ffcprw} \\
+fits\_create\_diskfile & \pageref{ffinit} \\
+fits\_create\_file & \pageref{ffinit} \\
+fits\_create\_group & \pageref{ffgtcr} \\
+fits\_create\_hdu & \pageref{ffcrhd} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+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} \\
+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\_delete\_str & \pageref{ffdkey} \\
+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\_free\_memory & \pageref{ffgkls} \\
+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} \\
+\end{tabular}
+\begin{tabular}{lr}
+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} \\
+fits\_get\_hduaddrll & \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\_inttype & \pageref{ffinttyp} \\
+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} \\
+\end{tabular}
+\newpage
+\begin{tabular}{lr}
+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\_is\_reentrant & \pageref{reentrant} \\
+fits\_iterate\_data & \pageref{ffiter} \\
+fits\_make\_hist & \pageref{makehist} \\
+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\_filename & \pageref{ffiurl} \\
+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} \\
+\end{tabular}
+\begin{tabular}{lr}
+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\_ext & \pageref{ffgextn} \\
+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} \\
+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\_str & \pageref{ffgcrd} \\
+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\_read\_wcstab & \pageref{wcstab} \\
+fits\_rebin\_wcs & \pageref{rebinwcs} \\
+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\_rms\_float & \pageref{imageRMS} \\
+fits\_rms\_short & \pageref{imageRMS} \\
+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} \\
+\end{tabular}
+\begin{tabular}{lr}
+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\_translate\_keyword & \pageref{translatekey} \\
+fits\_update\_card & \pageref{ffucrd} \\
+fits\_update\_chksum & \pageref{ffupck} \\
+fits\_update\_key & \pageref{ffuky} \\
+fits\_update\_key\_longstr & \pageref{ffukyx} \\
+fits\_update\_key\_null & \pageref{ffukyu} \\
+fits\_update\_key\_TYP & \pageref{ffukyx} \\
+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\_ext & \pageref{ffgextn} \\
+fits\_write\_exthdr & \pageref{ffphps} \\
+fits\_write\_grphdr & \pageref{ffphpr} \\
+fits\_write\_grppar\_TYP & \pageref{ffpgpx} \\
+fits\_write\_hdu & \pageref{ffwrhdu} \\
+fits\_write\_history & \pageref{ffphis} \\
+fits\_write\_img & \pageref{ffppr} \\
+\end{tabular}
+\newpage
+\begin{tabular}{lr}
+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\_keys\_histo & \pageref{writekeyshisto} \\
+fits\_write\_null\_img & \pageref{ffpprn} \\
+fits\_write\_nullrows & \pageref{ffpclu} \\
+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} \\
+ffcpimg & \pageref{ffcpimg} \\
+ffcpky & \pageref{ffcpky} \\
+ffcprw & \pageref{ffcprw} \\
+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} \\
+ffdstr & \pageref{ffdkey} \\
+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} \\
+fffree & \pageref{ffgkls} \\
+fffrow & \pageref{fffrow} \\
+\end{tabular}
+\begin{tabular}{lr}
+ffg2d\_ & \pageref{ffg2dx} \\
+ffg3d\_ & \pageref{ffg3dx} \\
+ffgabc & \pageref{ffgabc} \\
+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} \\
+ffgextn & \pageref{ffgextn} \\
+ffggp\_ & \pageref{ffggpx} \\
+ffghad & \pageref{ffghad} \\
+ffghbn & \pageref{ffghbn} \\
+ffghdn & \pageref{ffghdn} \\
+ffghdt & \pageref{ffghdt} \\
+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} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+ffgmtf & \pageref{ffgmtf} \\
+ffgncl & \pageref{ffgnrw} \\
+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} \\
+ffgstr & \pageref{ffgcrd} \\
+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} \\
+ffifile & \pageref{ffiurl} \\
+ffiimg & \pageref{ffiimg} \\
+ffikls & \pageref{ffikyx} \\
+ffikyu & \pageref{ffikyu} \\
+ffiky\_ & \pageref{ffikyx} \\
+ffimem & \pageref{ffimem} \\
+ffinit & \pageref{ffinit} \\
+ffinttyp & \pageref{ffinttyp} \\
+ffiopn & \pageref{ffopen} \\
+ffirec & \pageref{ffirec} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+
+ffirow & \pageref{ffirow} \\
+ffitab & \pageref{ffitab} \\
+ffiter & \pageref{ffiter} \\
+ffiurl & \pageref{ffiurl} \\
+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} \\
+ffpextn & \pageref{ffgextn} \\
+ffpgp\_ & \pageref{ffpgpx} \\
+ffphbn & \pageref{ffphbn} \\
+ffphext & \pageref{ffphpr} \\
+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} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+
+ffpmrk & \pageref{ffpmrk} \\
+ffpmsg & \pageref{ffpmsg} \\
+ffpnul & \pageref{ffpnul} \\
+ffppn & \pageref{ffppn} \\
+ffppn\_ & \pageref{ffppnx} \\
+ffppr & \pageref{ffppr} \\
+ffpprn & \pageref{ffpprn} \\
+ffppru & \pageref{ffppru} \\
+ffppr\_ & \pageref{ffpprx} \\
+ffppx & \pageref{ffppx} \\
+ffppxn & \pageref{ffppxn} \\
+ffprec & \pageref{ffprec} \\
+ffprwu & \pageref{ffpclu} \\
+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} \\
+
+\end{tabular}
+\newpage
+\begin{tabular}{lr}
+
+ffurlt & \pageref{ffurlt} \\
+ffvcks & \pageref{ffvcks} \\
+ffvers & \pageref{ffvers} \\
+ffwldp & \pageref{ffwldp} \\
+ffwrhdu & \pageref{ffwrhdu} \\
+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, HCOMPRESS_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 - HDU type: IMAGE_HDU (0), ASCII_TBL (1), BINARY_TBL (2), ANY_HDU (-1)
+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
+nbytes - number of bytes or characters to read or write
+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 or data unit 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!)
+section - section of image to be copied (e.g. 21:80,101:200)
+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 (same as TLONG)
+ long long integer, K 81 TLONGLONG
+ real, E 42 TFLOAT
+ double precision, D 82 TDOUBLE
+ complex, C 83 TCOMPLEX
+ double complex, M 163 TDBLCOMPLEX
+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_INDEX_KEY 206 illegal indexed keyword name (e.g. 'TFORM1000')
+ 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/vendor/cfitsio/cfitsio.pc b/vendor/cfitsio/cfitsio.pc
new file mode 100644
index 00000000..5d19907b
--- /dev/null
+++ b/vendor/cfitsio/cfitsio.pc
@@ -0,0 +1,11 @@
+prefix=/d1/build.v216/iraf
+exec_prefix=/d1/build.v216/iraf
+libdir=/d1/build.v216/iraf/bin
+includedir=${prefix}/include
+
+Name: cfitsio
+Description: FITS File Subroutine Library
+Version: 3.31
+Libs: -L${libdir} -lcfitsio
+Libs.private: -lm
+Cflags: -I${includedir}
diff --git a/vendor/cfitsio/cfitsio.pc.in b/vendor/cfitsio/cfitsio.pc.in
new file mode 100644
index 00000000..5dab97ac
--- /dev/null
+++ b/vendor/cfitsio/cfitsio.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: cfitsio
+Description: FITS File Subroutine Library
+Version: 3.31
+Libs: -L${libdir} -lcfitsio @LIBS@
+Libs.private: -lm
+Cflags: -I${includedir}
diff --git a/vendor/cfitsio/cfitsio.pdf b/vendor/cfitsio/cfitsio.pdf
new file mode 100644
index 00000000..712a0381
--- /dev/null
+++ b/vendor/cfitsio/cfitsio.pdf
Binary files differ
diff --git a/vendor/cfitsio/cfitsio.ps b/vendor/cfitsio/cfitsio.ps
new file mode 100644
index 00000000..44d8a1f0
--- /dev/null
+++ b/vendor/cfitsio/cfitsio.ps
@@ -0,0 +1,15233 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.96.1 Copyright 2007 Radical Eye Software
+%%Title: cfitsio.dvi
+%%CreationDate: Wed Jul 18 13:51:13 2012
+%%Pages: 188
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 612 792
+%%DocumentFonts: CMBX12 CMR12 CMR10 CMBX10 CMSL10 CMTT10 CMSY10 CMMI10
+%%+ CMTI10
+%%DocumentPaperSizes: Letter
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -o cfitsio.ps cfitsio.dvi
+%DVIPSParameters: dpi=600
+%DVIPSSource: TeX output 2012.07.18:1350
+%%BeginProcSet: tex.pro 0 0
+%!
+/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/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]{Ci}imagemask
+restore}B/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
+%%BeginProcSet: texps.pro 0 0
+%!
+TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2
+index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll
+exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]FontType 0
+ne{/Metrics exch def dict begin Encoding{exch dup type/integertype ne{
+pop pop 1 sub dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get
+div def}ifelse}forall Metrics/Metrics currentdict end def}{{1 index type
+/nametype eq{exit}if exch pop}loop}ifelse[2 index currentdict end
+definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{dup
+sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1 roll
+mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def dup[
+exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}if}
+forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}def
+end
+
+%%EndProcSet
+%%BeginFont: CMTI10
+%!PS-AdobeFont-1.1: CMTI10 1.00B
+%%CreationDate: 1992 Feb 19 19:56:16
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.00B) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMTI10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle -14.04 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMTI10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 68 /D put
+dup 72 /H put
+dup 85 /U put
+dup 97 /a put
+dup 98 /b put
+dup 101 /e put
+dup 103 /g put
+dup 105 /i put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+readonly def
+/FontBBox{-163 -250 1146 969}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE
+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B
+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470
+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B
+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE
+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958
+9E3948FFB0B4E70F212EC976D65099D84E0D37A7A771C3101D6AD26A0513378F
+21EC3643079EECE0C9AB54B4772E5DCA82D0D4ACC7F42FB493AA04A3BF4A1BD6
+06ECE186315DBE9CFDCB1A0303E8D3E83027CD3AFA8F0BD466A8E8CA0E7164CF
+55B332FAD43482748DD4A1CB3F40CB1F5E67192B8216A0D8FE30F9F05BF016F5
+B5CC130A4B0796EE065495422FBA55BEE9BFD99D04464D987AC4D237C208FA86
+0B112E55CE7B3782A34BC22E3DE31755D9AFF19E490C8E43B85E17ECE87FA8B9
+1485831624D24F37C39BF9972D74E6EC4784727AC00B9C4A3AD3DA1C22BD6961
+7E0ADAF55422F22ACA5E4DCD4DF9FCD187A566B7FB661D0530454D0DD6C6C50A
+7A3875C6CBF8EC7769F32A1F3F7FC1C072BADEC97794D4E90E0035282A170402
+356E5A9CD9ABD80AC4342A5283E458A7269252F4541CBB6452B39ED54D336D0B
+19928E9CD1AB26AD83EB209E2EC75011A2643813053B5DBB0246097C4821B5F2
+C92554E9140BE35B2DBFCD98809A8EC9FC910FDE9E0D86457C70ACB056EBF90F
+244DC0A5BBD455E15D6E3180311D52CF50B0BF7D0A7F64F3A1821E0AEDBC2E7B
+AEB549FE1D51088C153799C6E089B5D5D65E1C4E2D2B430CDF1FFA23CCB25D95
+5C43C8942435D0AAA3D9055FF808F2C3C887A3C469BBD98F026D0A59E26BA9F9
+C2144CFE49A9AD892D4D31764F0AE3A10644AE3966B0A790684B14D11FA49785
+EC5565D2B2E584CBFD85125F3FAC133338DE35361943DCE9AF05FCF2840CE512
+998D42CBEC52B57B79DD63F00985881E8463396ADA47189A94DDF951A78866F0
+B8A3D9197E39335277EF2294308DA70065D910943A34F7D5F2090FB4AA42ED70
+CBA469A9F64B95A6FBA4BC89DBC93765E3AE4723162DF3F9D6BDE77DD5870ADE
+C8900D6346957B84C3CE88A8F9A12D46B8FCA50DF4433B0B8AED6A63B3DA102B
+6DF94E62408E24154BAAC66B2B249C695BC0FA37A28699D9C0F3EE94AA32E3C5
+8F8D7F803B5D25014D43A353D719B14B247A87898A960DF68C0C0BAF70C83917
+6E9F7B3ACC64DBAEF3FDCD3A80C0AB907EE342E543D607556CBE5A9089B86D1D
+E768F27D74A613F3ABF883222A8596B542EBF54E9DCE327B5682AEE5F6BCC38A
+2A052EC4018AE3189DC1963BA39ACDED8F0C60C83F8873FBBF0302010956C520
+A7F3F8ECD0F177EDF5F4D5522C5984A3678FF32EEEB570B69C142AB89467641F
+917155D646DAF3352E27BF2AA0746E062E48532256AF364EFC0F0AAE3766F75C
+5219ABA60BDFF177558536E000DE3263A4A6EAAA669F9F4E94BAB336391AF5FB
+280A5B39995483E788CE4820EF77AECD73B1AE89DAC3F13E333F2628CDBA431D
+2A5E547D4225E6BE13119660BEBC155823A51477647F7E07A23D7D24353F584B
+2B311C4529E0E408B4E89A467BC03794CF4E7AA0A717A8247D5B60F438417D01
+8155F17E09D4C4FECED18CE574D6849640E5E0592D771F026BCB0CE66FD13BC9
+5A89D07EE26021FD5DF14B96AEDC02AEC3E099088C1DAE4FCA2AE841B17F5C4A
+D251FB56462CF050AD3CA84DA12DC1D17F80301CCFDE6C35C81FA538A389E0B6
+8BFF0DDC4B97D49B485E8C6AF47F951C042D2C750748B4084B3F4AC18488EEC2
+900A9672A6CA2B06A0F091E8DD9DFE504A5C6DF1537AE7F54DCFD94EF5CC663A
+A80E1C64CF1CD751D28858CDACA6F7CD0463A86619E87B9C03C9448B44537E78
+5E60A25045FBDBEE678737FA45F029D92908443C7BB9FC87B7B280C314F39A96
+B5287BA21CB3EBCF7816BC0900095F3F9F11D7774BC1D1D4A7F8098C610E3FB2
+C2E2E9D9DAAA6CD1EE4F35CE854B7C79DF8318CCC10C52DE36E4AC5D75ED7D8A
+DD4E8A3B827DC8A7D437DD38B782929EA60CAC4930F9711087DDC18574B472FA
+B40DEFFED99BE0C0CA85E9FA2028152C8B6423CB94E797E3651043BE9636109E
+87B70592852FD5198A7D340C0E1C419D0EBAEAF483300E41A6F6B1DFEAB071CD
+A4E0A596509369A4EDB66ABC883443FC615AFFA74C672922D263B5F64E861C6D
+C44E9C0BBBBA305C9AB04FAEB77E0C25C0D67F77639F6022D028847E796879D2
+B6C4AB4313FF3568E407784F1E00503A5875DC68464A720C8E55BCD80269B4DE
+B3C05D49DD15B581554B61E9D6313D47C39991582BECB1EF6E959CC64167DA7E
+F98EB7F130EE821FF04BB4842D3B8F23E81C4DB8C4B340EC9807DA0CC2627ABE
+9F1505EDA580A499BDC35E348CA6A15FB197597A5A3E519DF0B4749D5DC67B8E
+2D93EA98498CA6129C0993C0A6945A5137CB4A1B4B38A008B1559D719681E6AC
+09FAA1D2337E266FDC02D77AE822DC13724A0620C5ABFDA9402D3DD4DCB80CA5
+28F875133862164328A59F7E58E36CA06F23E651D8BBAA490D145F3788A30BA9
+C5389826A4B2F17E2B301BE89C464D9888C1E798744E815C44E68B94BABB8FC4
+2872E1AFBB63CA489FB1504926C84C5F8AC7E6A93942C3B0C3250EEFAFF70449
+3734AA4932BBF7B098C8287D8DD2F0E75F0F7B184BE5A24A6C9EF1C7CE86D58E
+1018668396EF8842609FD4C207CF3D818DA21AB4FB96EDEDF11905E15153D319
+93EF1A3297FB71AC25E9FEE544D66A2E6D94D147408033B1784D060EA8BD6807
+1A2194884CBEFD552D52B7B8B63A2A9A1DE5C4B437262091089497D10E4C1678
+52664B16F1FA71371BDF96D038FF88F695A02B7057DB4D97CC9AF8534518BE9E
+FCE87619AD6BDAFBE6EE8FDDE427D3CCD32E4143AB09B27F559E7727CEF7F39F
+DFB7E07E86E3512757E64C82D0FA29EB1E00E4F213B12679E2307BA8A363BBF6
+B3411F4C50A8E51A11D6716CB5431B6B941B5548FCA3C85B3829F7EC05D881DE
+4D2E994F6C815589CB4F5188A581FD9BE70E9D01E8F36BFBB5732F89DA7651FE
+9F20A732F94035BDAB79728D559647EBC1A386F7BB3489D59BCB048910AB9D2F
+38F9B3B9C0648A9AFA41B4089CE3EF93E7E8E5140532EFD745AE3F000502344B
+5030FC71BAC616EF9349D5C8B336FA9A3624E1D2DDBE5C596702F778FD9FA98F
+5899447510DDCDE2599939667F9831B6D06ED3CE3167D15F9C502EB035A05B86
+D4AA82D68A8511BFD3312250273545C5C4355629DFEE31B5A1B078BC2C805305
+22A3F4865F9C978C6E71A5F5C858E21CBA36053277190DB9D89A4B985FB916D8
+DEC338E997F3226EAFA917AA18C1C9B055BB82DDDD50FFE00B93DA5C9C662760
+7326F16E661443A6EDCCC04FF913605AD63E022EB96C7C9A7FA60E185073E163
+0A61ADC0E39B114BE69EAA874209C8713E765D017A8D727648B0340295D56C13
+34A95D3D2F40CF4CD2BBE527C433E09F00BC1BD5C7425E4DB2A17204F0B8DBA2
+82CA3F37C424FC07B69C89635DFB3971894E946D928802471C2B1C40F49701FB
+485186D20A803C0BA76DFED4ECB2446FF25258118E593CD1EBC8ACA718B5C9D6
+C4F5AC941B28716B10B283FED21A16C94E92C431BFB9C8AC3D3F1EF7DC46ACCC
+A82ACCE510A3F687AAEDC6839800F48AC96A5B81A97FE4F37CAA586969AB3D58
+001C8134BE160EEEDB79A780D2AA57BEEBD2FBCD9A453066B6642C459A679A84
+5E3FB8F50F7C00EFDE6049D2C01893750C5F60F2DC98FC36F2E656774123DFF3
+E4EEE44D085083365124889B3103DFA03F5A5648446BDDAC9FA40C69D83D2D4D
+0D6017D7D840A4F7CD97EFF126F48B331CAF5DE0856F689FD0FC450005793C8A
+74EC6BEF32FF405AA2F4F6ADF624E0C72CEF916ABD6BDB7C0AEECEA855F07AA7
+E5BE6F7DCCE459F4F390965C9350A3060825CE22CC25905FEEE40E4973C0189E
+5021FF9FC2EAB4301790F255B617638A2C44F4D71A74EE96DA5178A9296D388C
+0D43CD188C0F78D9A57D78EBE390A2BCCD0AC3087AF4A1273443795EF08D0F11
+ABEA3A173746C05E538D88FBC0A3A1DC82A762F951E63A135F63BC3B7E05B8E6
+B89DF17BD32E871FE1C967B5DA4FCB9187747B6A30B551B9C4FE920C34E40A8B
+E268ED41382AD1DED7E79D18469F58305CE1275C4AFBE4770BCD87D06D7101F7
+5EBF74D9F3AFF9608BE5736BF1B2B33B4B3E3C8CFD3A91CECDFCD7E0A4A586FC
+699EE79D7756E49DD686C65451A58BEDCF0FEED1B23EB408845391FEE74A3628
+11837485BDE72131D0EF7D0EDA3E23BCEFAFF9DC2616CBC8E52523EA157DF140
+9498280EB11F1C42B05BA5281F7ACE1BF40F74F3D5D61A6B852461013F773915
+0BA29094461022A1F1AD4B62CD619E6BDE7CA645914ABDFE87758C039B3C3848
+04BAF878C215BBC35A1D259B2CC21AA2B7C7B43165398CF37779B31190DC8526
+41E02F9361CA8E7750A39478DEAA823069009007B53FCBABBA40A98C90E603F0
+C76E3383938422548A9A49CD8D9CABEFEC5D9DB27F60303DE67AAC2E79EBE12E
+48A2D6B687A720D73169236DFE597514C656AACF348201B76008714FEB551241
+5F2C86E06820109386E5588A7E67651C1EA9422DE9307BEEED35E87B6B61F0DE
+3EE5C5B7FD94350FBB081378191539122C6A73939BA7D47AF08E54C5CC4553DA
+420E9680BA4B954D9BBE82A8FC559C86861760F9B24103493A26FB55E2DC7880
+5ABD36590011431ED606491093B769CA74AA6F8B91076D6D8368BB39D4C7B435
+CC461A9E9FBDB28772E51AC2C563DD42C4A87F7A544C8B6D10D5D2504F9A4BBD
+D4F1A5A6DF8278AB6F3B10214AD75FEB1B5E32801D2631983E2735BE149FAFA1
+560E57087EAEC3E45526DF9C748F42E6540CCB14DE6DD11509F3F1BD6D5B3BFD
+3D59D2EDB6235DEEE1A893F522497EC38CEED07774E8B23AFC381D6432B87015
+A586224B9EC36C4498624E5CF2E9BE61FBFF52F479F4CD12A717C0FCC19182B5
+A5A9F8D415472F4C61E8965AE972EDAC4A17776B6EC1132CE29D6396D2B01B6D
+BEBA1ABD3273C62B3475E2DB8B57E61208AC63BFF8CCE2BA085321FE0C9F874C
+A645C234812D75E9C5C02D0B0E13D57725D105724BB2C5A916F6E82D57D005F3
+9F6B1F041A2B9675AF901B171E6E896F5B8FC545BC88E183AC5E5F1B2288CC5C
+7351BAD140CBFA03F2FD18298551BDB15024BCBE844B418B067208EA0A13B731
+58747D1B90BB00E37FD7DF9FFAAC80DBDD92E1301DDF1ADE62ACBF169FBFD927
+AA84D56E00D02D5B8A34FE3D2B1AAC470336AA02062F42F2C958307142F7C6E7
+BD440AC8D8C6A46DFB2B42A32BFA4255A47F3CB3F0733F294EB47AA59DD26A03
+C81A4BD18162EFCB77F3BBEC3E8B225E76BA51DE178468B529D146A544180542
+6EAE3A451781F5E38DF15BB377C9FE92096E976AFC14DADD11581D29222948F9
+FE23D981CEE4E5013025FF3E69E479D32A7A8D25A842FB288A0EC63E23E297E0
+168D22FEC35E333A2D67A37A4EED7B59A06F21F44DC6831CAFA473E48A66EDB5
+00FEC1D5399A06F51A8A67A6803FE34C1B1F2E4CA8D7EA3CFA8BD046D477777A
+D283296A8F181D671CBA5B9793DE178BFAF807A6F71E4FC6D69CE7CFEF11D0B6
+F8B23221E627475226706C19EF519D19B80633DDBF4A1AD9E271E547CCC846B3
+859CD96E495D12E3D5557A309F12949ACF5F373A29C0FD4A6456C737E6F08BDE
+0A0C692D66BCE059ADB9B91F8F81975308ECB3313B34093E06462C9DA76A4BB2
+1D8DEB5E4526CF73DA4D9D5CC7148E5FBABDF1D45F024469B6D84BB607BA975F
+1F6EE627044A93D108427B6C14528B5C6D1568E65F3450D7F4A37EE34D619138
+8B7914C63A362737025C0E57F928AB5741CB79D137249914A3CEEC0DECFF639C
+0F6B8125C643EDA71F2945FC7DB555E4ED2896C49E83D4515B0DA9A72764C792
+9D6A72F18F15C71BB655DD64E421EFF712865D45D2642C7E63501F3289D589FB
+B983626C60523142AFBEADD4019BB3C4D9C6ADD66012D0CA6AAB374FCB7FF77E
+89BF30C153007F48E06EE2278BFF6F0C9AD9BCE6AF9A9171A58EA65CBA2A6A82
+E35D45980D84DE7D9199344686C8F08090DF43D0051C15C4E19A9D1C76E4686D
+7412DAE7F6EF4E86230C43187D1997E98010F6C8E5E8941DC837C6E73E9C0947
+AD2B9E8333BE73BF30D56C31E2B76DE3F6C841F42B109270CBE04D10A9D64CE9
+0FB722EC4FCC3F1EB7CCAA2C6C6B3D285D786DAC189F440F32057CFC882A6257
+3068C55D4470801D8E2D6B5972D30B54C54E
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMMI10
+%!PS-AdobeFont-1.1: CMMI10 1.100
+%%CreationDate: 1996 Jul 23 07:53:57
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.100) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMMI10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle -14.04 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMMI10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 62 /greater put
+readonly def
+/FontBBox{-32 -250 1048 750}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE
+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B
+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470
+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B
+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE
+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958
+9E394A533A081C36D456A09920001A3D2199583EB9B84B4DEE08E3D12939E321
+990CD249827D9648574955F61BAAA11263A91B6C3D47A5190165B0C25ABF6D3E
+6EC187E4B05182126BB0D0323D943170B795255260F9FD25F2248D04F45DFBFB
+DEF7FF8B19BFEF637B210018AE02572B389B3F76282BEB29CC301905D388C721
+59616893E774413F48DE0B408BC66DCE3FE17CB9F84D205839D58014D6A88823
+D9320AE93AF96D97A02C4D5A2BB2B8C7925C4578003959C46E3CE1A2F0EAC4BF
+8B9B325E46435BDE60BC54D72BC8ACB5C0A34413AC87045DC7B84646A324B808
+6FD8E34217213E131C3B1510415CE45420688ED9C1D27890EC68BD7C1235FAF9
+1DAB3A369DD2FC3BE5CF9655C7B7EDA7361D7E05E5831B6B8E2EEC542A7B38EE
+03BE4BAC6079D038ACB3C7C916279764547C2D51976BABA94BA9866D79F13909
+95AA39B0F03103A07CBDF441B8C5669F729020AF284B7FF52A29C6255FCAACF1
+74109050FBA2602E72593FBCBFC26E726EE4AEF97B7632BC4F5F353B5C67FED2
+3EA752A4A57B8F7FEFF1D7341D895F0A3A0BE1D8E3391970457A967EFF84F6D8
+47750B1145B8CC5BD96EE7AA99DDC9E06939E383BDA41175233D58AD263EBF19
+AFC0E2F840512D321166547B306C592B8A01E1FA2564B9A26DAC14256414E4C8
+42616728D918C74D13C349F4186EC7B9708B86467425A6FDB3A396562F7EE4D8
+40B43621744CF8A23A6E532649B66C2A0002DD04F8F39618E4F572819DD34837
+B5A08E643FDCA1505AF6A1FA3DDFD1FA758013CAED8ACDDBBB334D664DFF5B53
+9560176676ABB71BBD0EE56B4CC492C0652750227CEC7B86E4740EB7B8775564
+332769DD30794E501BBB0E4E5CB665F3628E10B1137CC8BC5C0A64A310B5E27E
+5FD6E3B04DA3914C15987E638A72790AF4073CE9CDBF6E3C749CB4DFF9C54951
+A58C386C54BC4E98B102B5E91E8567D2EEEF048F2CBD5D243701D20909290B4B
+A3083F632D8552D42DEE0C69A4B14D8B15AA082DECC12B2ECAE6F663E6D09F81
+EE2979EF41FBF12C9D8BF23B77E0A20088EBD107C5BF9DD6F03FFC3AB65B69A7
+54953327E1D4AEF5A146273392BBDB321D4CC9A8FFFCFE5C515B466E21546CC7
+C6209E5A76F916B03DB98BC6CED334F33E7B373D42761696F5A876CA6F93F16E
+15A07E2E102148CA4F62A99C
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMSY10
+%!PS-AdobeFont-1.1: CMSY10 1.0
+%%CreationDate: 1991 Aug 15 07:20:57
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.0) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMSY10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle -14.035 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMSY10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 15 /bullet put
+dup 102 /braceleft put
+dup 103 /braceright put
+dup 106 /bar put
+readonly def
+/FontBBox{-29 -960 1116 775}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052F09F9C8ADE9D907C058B87E9B6964
+7D53359E51216774A4EAA1E2B58EC3176BD1184A633B951372B4198D4E8C5EF4
+A213ACB58AA0A658908035BF2ED8531779838A960DFE2B27EA49C37156989C85
+E21B3ABF72E39A89232CD9F4237FC80C9E64E8425AA3BEF7DED60B122A52922A
+221A37D9A807DD01161779DDE7D31FF2B87F97C73D63EECDDA4C49501773468A
+27D1663E0B62F461F6E40A5D6676D1D12B51E641C1D4E8E2771864FC104F8CBF
+5B78EC1D88228725F1C453A678F58A7E1B7BD7CA700717D288EB8DA1F57C4F09
+0ABF1D42C5DDD0C384C7E22F8F8047BE1D4C1CC8E33368FB1AC82B4E96146730
+DE3302B2E6B819CB6AE455B1AF3187FFE8071AA57EF8A6616B9CB7941D44EC7A
+71A7BB3DF755178D7D2E4BB69859EFA4BBC30BD6BB1531133FD4D9438FF99F09
+4ECC068A324D75B5F696B8688EEB2F17E5ED34CCD6D047A4E3806D000C199D7C
+515DB70A8D4F6146FE068DC1E5DE8BC57030ACE57A0A31C99BEDB251A0ECAD78
+253AB321023D15FF7F55A3CE81514C1E7E76240C1FB36CD4874DDB761CC325F5
+D588700B294849D690F93526EF438A42B9B5B0508584EA3766D35F5B8D51C458
+ECB9FBD23A49576EAB06BACB7EA6D300985500835F4FE597D4A1110C8EABE6FC
+CE3E1F95CFD3A42446F25355381D476B2FFB6EF247BF58A6FFC5EC0E4CC207BE
+46485F8E07350B37DCA8C1864E62614332A1D3C9DEDDD6492181949A2C3498C9
+EC2A81C1F4FF989A4654E375F509D24D969B97D2A9940FAF43BBB286E08559C0
+F8D9674B0A294B36D3A050F7DED8C80E1D230812F6B8387B17948FD29FF050E2
+AAC5EBE5D96AFD0879534E2F4BB81613A1571750F9CF4215199F93813D815B5D
+1C79E11A0FCBB627CDE569F88C741CD502627777BB058ECAC09B6ACCFACA69B9
+8F8168B0B5A1A6EB13E884B348FBB2ACF9EB180F6E27D57F8503710CE037A34A
+F8B157201657C825E2A4B4A7696B58B7A988C05E43E66F0FF277A7694C555C54
+AFB1D32F6DE102136FC810E1F3B5CEA42476EAC7AAFB390E3252B2169DCDEE6E
+328507BD0E24734A85AAA263E0D2F64BE1607455BC855785BC27F8B30FE917B4
+23AB3C812975355942E955501AF85A3C0CE836911AF679EA44AD6A7D042A6549
+0C471FE294E8490024D93ADCADED460FAB7FBCDC29EFEBD2A9A127E11869E659
+961B29206CE63944B6FA4B9315BCC528EB1E0223CE94C795A5D5231A7FC8545D
+6B287B965F8EEDDB67A6774129DD01D5A21694ABE320BB2553043D4C42ACFF91
+1009372CB03381035BEEEEFD05631E026A0980A72A67B3703323A4E7C94FFCEE
+8D0B7407F9CCC043D3D184BEA4728385D6AB2FB0641DD8F5BA7E04035D30D628
+7E97D31C1486DFD5B1D076B84B4ABA4829ED4310321F1F24B847C44E00185A69
+37711A
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMBX12
+%!PS-AdobeFont-1.1: CMBX12 1.0
+%%CreationDate: 1991 Aug 20 16:34:54
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.0) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMBX12) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Bold) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMBX12 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 11 /ff put
+dup 12 /fi put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 113 /q put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+readonly def
+/FontBBox{-53 -251 1139 750}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5F0364CD5660F74BEE96790DE35AFA90CCF712
+B1805DA88AE375A04D99598EADFC625BDC1F9C315B6CF28C9BD427F32C745C99
+AEBE70DAAED49EA45AF94F081934AA47894A370D698ABABDA4215500B190AF26
+7FCFB7DDA2BC68605A4EF61ECCA3D61C684B47FFB5887A3BEDE0B4D30E8EBABF
+20980C23312618EB0EAF289B2924FF4A334B85D98FD68545FDADB47F991E7390
+B10EE86A46A5AF8866C010225024D5E5862D49DEB5D8ECCB95D94283C50A363D
+68A49071445610F03CE3600945118A6BC0B3AA4593104E727261C68C4A47F809
+D77E4CF27B3681F6B6F3AC498E45361BF9E01FAF5527F5E3CC790D3084674B3E
+26296F3E03321B5C555D2458578A89E72D3166A3C5D740B3ABB127CF420C316D
+F957873DA04CF0DB25A73574A4DE2E4F2D5D4E8E0B430654CF7F341A1BDB3E26
+77C194764EAD58C585F49EF10843FE020F9FDFD9008D660DE50B9BD7A2A87299
+BC319E66D781101BB956E30643A19B93C8967E1AE4719F300BFE5866F0D6DA5E
+C55E171A24D3B707EFA325D47F473764E99BC8B1108D815CF2ACADFA6C4663E8
+30855D673CE98AB78F5F829F7FA226AB57F07B3E7D4E7CE30ED3B7EB0D3035C5
+148DA8D9FA34483414FDA8E3DC9E6C479E3EEE9A11A0547FC9085FA4631AD19C
+E936E0598E3197207FA7BB6E55CFD5EF72AEC12D9A9675241C7A71316B2E148D
+E2A1732B3627109EA446CB320EBBE2E78281CDF0890E2E72B6711335857F1E23
+337C75E729701E93D5BEC0630CDC7F4E957233EC09F917E5CA703C7E93841598
+0E73843FC6619DE017C8473A6D1B2BE5142DEBA285B98FA1CC5E64D2ADB981E6
+472971848451A245DDF6AA3B8225E9AC8E4630B0FF32D679EC27ACAD85C6394E
+A6F71023B660EE883D8B676837E9EBA4E42BA8F365433A900F1DC3A9F0E88A26
+30F7B5CE2041568C18D8F66D36C31B003C916EC14620F67D695D846F2EF97CB8
+0D569CB47D8939FE3C0009749B48D0D9856FA050F2D1BEBE2DD68DDBFEAFC2ED
+7A7BA881DF4859A0F43EF10EF5DC41B5E82C630F2E3E435E37DCD10B63D3C96A
+38C0C5AAE886D864E24FDD862D6957C084CC4A39623629F00DA0F035DACFEF70
+4D8DF7C197095975D874B919691A7E03C56534645AB63E6B829038B435E1D2AC
+2ACA8A5E4C2DBD300F7C786A9C196539C8BE8A6FFCC109193E97455DBB0B9E55
+941992A110EA4BC1B01B59EA538E6AE0749C24D452C351F13B1F64EF2D199563
+F88F92BB8C6C8EF4ADC5ECDA3C2BD22CCF84431E43BC5A630332184CE06454E5
+0F3A369D5B7B134E0CF54E4804F28162048BA9B8A03FD837E2C37D146EB0F14E
+7DD93363EA5C819AC95F2C1501909E9F4B3A09CCF2C609F0A6EE86D340A19408
+6F985E999EAE40D936E3B0BF5D646941E5CE26E1AFAE1EF59329EA2E24EDBE17
+8B9F15CEC308AB6169A683CB3D56DE572DA21974D80181D7BCC09E8E08FFE441
+0F93897DC162D782209CC451E553232680F997451B1CB2D8AA0CBF5DBB7EF923
+1C7AA87DDE43C47B188B502C42FD3F47D73811469BC954267ADDAA9CD18D49D3
+2FB55FC5555338B4522F0A7309E487DBAE445E3FB3489EF7E396835B3FED2044
+5CCCAC17D69B0A1434958B658891E8AB16A992B77357BD4BD58A9251F50AB71C
+B930D4652578C79C77D9083C420C895C83660D7FE13611BC7ABE5014C7CB5E37
+62E71B7D3E215A8A7E51F9E4F3AAAB983FF93E49CBC1EFBBB2FD7150FA3E4745
+5F8FC1DFD4A245586A56DE187584046746119E1F5770D83B0785427BDA36111A
+881107BD4CDA253D2972687F010989B6FA7EED5836B377EA92906BFF453EA308
+B4BF3287D966E98262724C896177F042966FA9666CD0C628C648AD6D8CBD23B6
+6124005200490FB59E771E158055E93489A2D4D2447AF36988086AD21E8737E7
+37B21FF521B78B92B5DAB8685B1249B8E82915B06DE48E1979EAEB8E02952345
+53EA9181FD43C6F136FEE9286525F50ACC9236F602B542A36B51D511CE03EA9D
+7F4E668FE9B7BB18A828DDD511C9AD2AF80B1D2F3D895D262C5FB883B36A4407
+671EDDD228337CCE4DEEB68FFF6D46D9C87F577F60445962A97BD61549A5F2B4
+F70E95DCCE8DA63DFB836F5A7901110B51B950872C8AFEC0495F51691B13DB31
+B84E89B8C7E6D0132A26A348C2804887685803DB72B8C3223AB655830BCBAC24
+2A3E989E13C38FD950B03977C2DE7BC27392A24DB30AD71D26E0969AE9D637C4
+4247FF262AA189818067A8D3FE7F042E4DC47CF6D21504A9F06E440F79851826
+ACDC43F89F482C220786BD85AF276D394B8D523C7675F57BE80E28F29A81EA0C
+9875EE70C69D47EAF98963FC3DD370FC270A606BBD9FC16DC1B93B1179D810AC
+F634883A2661B3B2DD26E0C24A6D8B3AD223FDC7251296A614D88F8860EE5031
+7E5CFCC7233D3397830A27DE6E5306EB074FA6698087E86A8E1F144F43FD3937
+0006B492CB5455EBEF58A9AA34FE66F5FF36B04A7CFAFE68F490854E2ED08EC3
+1E5DA648A76CF178AFC6C05813E88E1C84D9AF826DC9583A04EFEEBFCC351B65
+1C79FF12BD7D2879D8F4521E448757B3B2B9E7265FCD9D57D24A633E04676DAB
+AC9B44A4406714856791692D23208139BC39147D57E4B1A9CC0CAFDBE4F2F6F8
+87315413CC58B8ADA31B15A17226AE0AC8F047F7C7D9550D820B23994438FACB
+CC4C65A302F033D1ABF788848EE63E6DF1590B586DF40050A800AB7E535963A9
+18CD7F6DA52414A4EBBEBC24B83F824C0B85C3BD21401722E16307553617B597
+0DBDEFE85B9086F522FDA0C43FB27C14CB9621C75D8254B05E24C87D754B347C
+C9BEA9F2BCA71B37E3F6A67B0879BD67E8509B5786DBB025AE6159A7CE5143C8
+0903EB0D6E6E40C36474093076EA17C554021D4C95A9B1AB6FDC30F5BAB2DC99
+CF5699757E036207867F75F7FF2266A806E6581724493EF360694831C58925BB
+E271C8202068A9B9EECEFF854DB4D744102A902B913A1770A2A628B9B85048AF
+697CB3CBEEF4F8064DC93E093A6D9637179265FD5ACDD5E3A9C406E8BE70F30D
+EDAF394FCB91BDA810D1C5E4B472F60E900DFEB45AAF82983A714E860548B737
+BBE318EEBEE76B2063CEF47D7FA895A0237BA314DBF4E3A589B0DA21BD79F475
+52E5F674985E38B21D07175B9CADCD3B5FF64E5A4ABC1D21D9E50B6C33A1828A
+05E23D11398E7B56C1F8C5636575AB08CAD336F2DC2F9418BB0FBCC0166C5D85
+FC062E82DC0E55C41C6C682ED75A78195C6FB552B19637B53467429726264132
+943CA57A8C30D1E31A67387B679827443A52C4557DB9DD719D9FEC539CA09D07
+47495060C8BFF195E7770D0B2F4DA353D7E755C853A7B9E9DDE5AED20A7DBECE
+8569A8D9E5AF4D15388D65A10D055DE7EBC2E295073A86D082C2FFB2CCA7206A
+7577BFD6E506D29F19452C3B2AF45D5531C0E1419B434F30ED32657A9DEE4C73
+604C3E5F239137F49958F5CA638964DB763BBDE618818BD4EB23E57F1B250D11
+B185093107056D2D4B6D53AD2BA245E121E3E206770CC01D0E07DDB5D00CF858
+48F23AD1CCC23C42DD9F25AEDF3029ECFD31821A734F83B7C9F94AF3E6EBDEB5
+686B484475F0AA7350856F9BFAFA0EEB9BFFA02E5CD0D8FDD562909539F89BA4
+505A45D79CD2E7587EFC5E579EDFAD3661ABA956C7AABC46DED840EE00370EEF
+87C3C48F109BF3FE0CCDD17E2B9974F817A08A8BEC4CDDEBC43F32F685F33D20
+F3106584C83714D82D494C4721400FB88D7E5FACB331DFAA524553B401184571
+E7F2C4F954D586D03F4685CA6ADC774B8E24FFCEF33094842A5F226E7D681B27
+330F84BE13747EACEC6CA5D94F7A2C2E9C47EDD05B163A1A25FF78361F3FEB44
+20D6BD2DE10AD0F093365AF1C00CC88D15443A21EEAC4EAF1F50D5ACA6ADCD81
+D39D91A142999F33FCE4DC572BE9FBEA9F0BFA142976F2BCA7A6897135AC6E7E
+D0435DABB724E2193489F87A87D54384B3CBA6395E7DE36AF07DB326C77AC61B
+C9CD52C77A5A82A27C19D32D18B6FC17C1E6D38044A9DB4BCEFD8E05C1B5042B
+4697173EA5ADCE6780871152B742AA7CEE0220663CC5C3AC3292C660FFF93286
+1E50DB297296156955D18DA85931CCC9AB9E0BE2157ADC1343066050C7B735FE
+130364B736F6521BC4560D44437C0D45427C207AB54F70E2FB9A0C2EA2436191
+0F87B91BD3596F690335206069FA66A6BB08DE89C799966DA5C9857AC2F1339E
+E6EFF63FCAF48D50CC130AA95B9B1EDE2DE8E19A98E9A8C93E2EBF60889081E2
+5C5D4C9AB8F800A784F1174595874A39239E74F3F5F8816E024F631CAF136E99
+39FF5D4F7FB5A4CDE1B57DA67AEABD4A41FFFA0AA4B210351EC5EEC22B857397
+9CC04CDAEA7D7FF4BB3C3D771AF80E630D7AB58097BDD1A037E40194452DDCD7
+376AE54B39206F76767460B9AD86530743BC63884C46F4577ADC62F19D38232F
+1D80EC752DA6B4C8455A26574DF01D2D9686B7E75F19BE1A5A8758AB7B827ACF
+0F8D395E6C18A6D591E01863DDB7BB7179FAB3F2C82D24F46151CFB8AE22F53F
+4177189C80B26FA893E006321BBC6D9AC9817A1FBE4918F8A1B8658C35AC32D5
+335531F4F907143CF7F190991DB7E243F4CE9199E6E46F26F16E00325C395670
+330829D5AEDEA76337D4A9AD1C3A30AA28E56B40019C0836B4FC6BC22097FE3E
+86175F36C3A5A879B9C700C50FFFFB6B7BE1361211E1D3F3BEB39A2267875463
+CDD79C44BEE54CC30F78BD48BC1D2B3C96C6D2D1D2A8484703C4727657E6C544
+C27C4ECFCB7090EC465D3E0C34BED015A0B017EA94FE7903C021580B83AA25A8
+307E13BE4FE137FD505749F447C2FF77F3039DDDFC476D9553BE3D3884E81C4C
+03123E78FFAE5151D3CBB0473CDB4F083AA5FB0B1BA99A3AD5F49AA87B73282B
+5084873CA47BAA9D1E0385C9D4EA3498AACECDF6A6A0EC09EE0520C9FDE792C3
+07FABCBCEC2B7474A6241099D6362C9436F32FBAF1D6CC11D933D4A64E0CB9E2
+0943E082F4335F23E7E2C719ABFB70D7C9F48C6B88E980CA8A980958A308E898
+BCC7C4E085167F33BC36349C0CC23B004C805DF196581DB0C551C2B53C82E948
+EFFC164541AD80E6014A723760ED548F3FB0C47F4459D855211824B04D28D3DC
+18E204F3A43C5F8D489920CAEBE3FB9800061827656FEC3C43BAA4219978FBFF
+85507FF60CD5020365D73914861254547B36171070053498052CA13E1CCE5C70
+B9ED44737D747DC28DA6FBB7791082C572BF8362C3D3E34FFB285AAFFBC1311B
+ADF12AF9444E47D85B0169E851C2C35D8D089A5ACF6A2E9C94085ACDE361FAD2
+B54B901EF8ADD09B1835B37CC6A5509872AE193541685EEA1EEA3770A1FD6318
+DD7328E8CC51F099858659BFAA708541AB9E21CF1632458164B5E8659F6C23C6
+88C0FFE47B820388404D0E9FE6CB06195BF2B2444582D4B7B38F45E18B604639
+A0750219065C18492E2CDEF4BF96E2222A5D11DA68C6765565F9DBDED8F95F3E
+7F2EB79DCE1C679D0743C5BDB832AD24C9B747AC4FA27D1279419E732DEEB543
+BEE45F538A500AE50151C16C81346B88AC63D707E50958536C3CAE834A27E77B
+AD95CEBDCE16FAB65DF308A0D34EF798078BF8FB0D03DFC782449C0BEDBC4AD2
+5FDDF493FBDA5CA3641F4392487887D324A047904B1E033027143232A40D5014
+DE1EB3E58C535A317733EA1D93C33A252CF750A9EEAEDF6313B9CE44373A288C
+EA8DF423F248E3DAE7DC96A211659305C9B97946AFDB3ACFA2B79F05CCD03E05
+2E372943C4F676BB72472D3EA1B0F566757FC5CFFF8F81F128995EEF12CBA8C3
+5C0450BFF4B9C68E93C1638A70509FB6BD34ABFD2C0B7C0A238E98FD8FBEACC1
+2539AA00D2B64D7C19AA45C3F1B17B9050546D751B2B346E19DE3359F02F5F1A
+893148BA91ED8BD68A0BD5657F0001DB75E71F2A0160A7DDC39C773EBFB10458
+A1BA0DA0CF4976AA41063B2FBE875FF0DA96FBAFD6AF0DF9652AA0EEBC1AA768
+087B8CDD4883A044694186BBA78043EF79007FFCBCCA9606B0C132BBCF835ED5
+2A7F459264147B460E5C9A487911146939166679E6A193A4AC979653DD2B8522
+F6EB14CDED27F108C47D32E25D40FCCDA830D38B4AAEC9C6CDB212A1D8012AD8
+17BDFEEDEA83194DB3369B8E0FF2BC5BF2FB83EDD20248820FEFB41278A7DC96
+D47B40E6EE3F85FF38642B9C52CFA1F85FEF0DE3637BEBB66C1BDB2A8ACACB97
+9CDABA4F994E1656812B0321D999339A2384E07D19388ACB8FB4A86FC98A2E73
+3809461D8681C619766696A02A9099445CF756A6BD1ED778A4909D36839F7E91
+153C0BC25297495E3EC490B189AA7C7B64480362764F6B89753B0EFEF35C86F4
+65122B04CB43675EBE03A3026F4212D521AD81FC3E2D3575B1C6BBDF35E54199
+0FAA02480892DAE8DEB52A4E1C8E5995A67D2B3652CAFC5FB0BB108A40019896
+664ED1974AD21CABA4279BCC7D2E3DBFE7A70087CCBEA75FC65218C5ADF0D174
+436BB02AAD79BF172589C03D0C1D4DECCD14F98AE90A86B4A7BEEC0F1CDF724E
+0912CCC14AEDB5EC8E297CE357ECFAA0CE69B16F93EF2B214AA9BE98DED441D8
+8DF022DD63C0AB8143A082073AE8FDD50DC7DD5BFF35F9BECE79C5188BF11056
+D8D61F9D5FB03CAEFB421682269D8F6DC6637F277E0C97D7639553644B59FA30
+DB3DF2B7B6633BA02AF683654FC048412F29BBA8872987BBF26FE15E4AAFD133
+E2A61425C364F7A22C201039D5D765C1B14A06C1FB3C2BDC517FD2D0CD1280DE
+6973B6365CB32BA2D5B60E1CA37398A37B7951E74D201140CC5DAE4FC0D66418
+751EDA5A7D77D6CC9B4ED206B36A8CD4061E848500B284F1EFC5BC73CA717354
+5F1C96C3B176937070F8DEDAC70ACA1504A0557C7BCE23A8FCD4E179AE4C3375
+2A3099C9FAB588A0A47FA213030117F9455907169F00302E592A6B2D97CDF3F0
+E0441B0DB0FF1324F99FCF21119336CB7570B488B31A0F8FD3DB110733DDDAC0
+C9C994BD2AA5D5F4B3ED418205D8803C3EB6C591F7A5C34E00388A9E88DD8727
+C76F347D5B35F5D59EAAA48B62D575ED3CE9F3F61170A376AAEB825ECA1A20A7
+82C69F6BB354CA870717815F083067B7662A8950B85F64F693D58E17F1E35A39
+44E491D46C73775BA837DE6498334594C554C7FDFECC828E3728057E3AD3FFC0
+A1E63E94532B09CB28F5E50919A00A5AC50B0C6856A3697847314D8B9B8CCB52
+76E4A1FD2A075CB2E9B9929D1EC55F5EF9518437738BEC7B300C19038AD2DD8C
+6AC399A0D71867B943B1B197E884B9DA58D5C175E1AE398EBC0B5AEBCF2AB1FD
+A960D13F12E423B2DC17C8DA6DDD431219A0427EC28E1E4D708B4DB0C90B8A87
+738A2E4C6B8C49BE14091797A5CCE7A081485EBB8B2C629842DCBE25F5EAD1A0
+D546F57455B532A9DE145CDE4841B08B2DA52906FF16F53180FE42B2C53066DC
+0926AE1BAEF441FEEFA91F722FE6CF5E0B2A0875F71DD42095DFEB5851C82792
+C5574EA07DDBD8D702B6AC0C82311A0490D5B57463389672933EC83FE646DAE6
+AE8BEBD6B5CBA53FA936F88A4E4F556CBC56B47B8393457C9D5E9FD8BBF800E9
+87CBC0C77CDDD9EE7768EA4A23E2B92ADB37BE882CD842D55EF629F6AB8E9C80
+13BB6E37014B2DA56FC65071B345789BA7D3C193D3579C6FD98DF997D8F1903E
+D53670E6030D2ABA91DB82DA54B97D0D8D3C56E08A3C21DFC15FCC12DAF6CECF
+6D085C337F6CDCD044EB3E7F1D4C29344DE105C7CBA03E211E3244C2365A4ABA
+88D9E17389FE2161A6D9A2BFB14554B0071614A301741D6F604EC3788236D782
+152E3F41F8ACF4B04156EBA71CA125126C31FEDF066A474CCB8A76083B67EFA5
+9C34E8BC213AA01B1862D866CA2C7F9CA3444464EAF496186CBAF607A0E7A60E
+4D8959DE9DD6B42E3995F0D92A7AEF7C6E5C3BD7DB1DBCB1E6EA19B10709F709
+40DC949106E454D9225606EEC9231D1694F71E350B8A8895016AAE4B44367EDA
+F9E9FE18A201A08368AC00409F5FAFCE72DF38D27462875F0586E8631ECC090F
+CE3DDB814193A5C154DDBCC1CCAAC3658BC4BE562DD1A5C3098BB32EA36D01E0
+345A00F76E722736BE3762177A1EBC5390457316FC105A26440011C3A3505DAD
+DF4586C826B71A7E08291F1864BB50A422DCB42C15CC6EA2B93C5C8312EF4EAC
+025AE0A87C6E8C824D6E0564037A3F2DF3507923D31501B9B8FDEE3A06761DA8
+25D1F3E7E4BFB11DC9C1981C0B1E878DEECDA57A367FCDE89B88707A07F1017C
+CA88CB190F02CFD3541F27DE81A644E5B4318543740DF9D69CFA10EBAE0C487E
+577ABD2155ADBAE841DA9C2FD0CB6D3FB4C8A109B7862A04B9976FE920B94318
+21B7D6DF66D1812E0D07257A5E354946D59E9F162FA611B1CDC737E2B60D52B3
+C82ADEAAC401B6C2D6DB473992B9E45B08A20744D53FC385E3F6D30C997F3FBB
+7847C5B1ABB7AE53FD6616D7F23393E0AD34490AAFF9027168B5492145F5071F
+DE0E6DD8E31277B3D3588B36372E4EA4F0107CC391DD3D0D5FE8970AD5FC5789
+17DCE9CA706164456BB7A18A68638403621251B60213B46971CE3434C70487E0
+6CA529999AEF89CCEA57A711290764C6E168E75EB756E0337081EDD6CC70FFB2
+9632D22FB3A400774642B85F576F1B73CA52E7F5A23591229C0B0AE6408059E1
+0427DA5122C7BAAFABE4ACAEDF7F5BDC3FE21909E7B474A52EEF3D98BF267FF2
+B3803AEE0D1392F5418E84759FCE4310048C9124824A5976B09B56F8BED6EC68
+D640A56126260FB5BD6D5AC13BFD5D0B0AEF252CD5FC1FA48A926F55885C6382
+99B48123231F416C19CC5FF196D13371DD5D33CDB23ECE5256EE5760471EDCE4
+26AF7FA95D468F2609FD64C6DE142E4961EC3156ACE3DC207C04CB4019CDB4AC
+CE6013FD84D5B6887390A6C46F0F1A43FC0B1BA6AA6B5B44F23C9C360A20A1EF
+E94366DA2A92098D60AEBDACB8D7B4736E4E17C4818DBD5398D8384CBE7CC1D4
+A28B28BA328202F087E841206B35D89E26C2FDEA77DA957A5759CDEA30AAEE94
+F6F5FFC1B3820C5E907CD6587295DDE110226E4DB1E46BA8DAA93EA2D135B635
+23F6B1A98F3F165C0EA13B809CCE4D64B942137BD1D3F98EC2AD678F26CAB779
+D9F8291DD64A677011B4B9604B8E4AC1F22B96A98760DB2FF1F47EEFB880814F
+1200A077279EDF1BE39867C45DEC3596E4ACBDB1E200C27126AEC4366CB1A354
+F4660DF153B940679229990358B4942D6DFC7625273857445C967C24FC51C804
+3EDA0EDE8841235AF5F78B50368F80B3497E39F3EB0094F139D42BAA0831D6A4
+200538253A922BD5CD0FA548C2241F1442C1E35636014F7CE5C1D2294AEB4502
+F5248606EDEF0F33F998D05D95196AAF94039803898A673AFBB9873A1CC11045
+A01D174F8CCB0482F6EEF5D5879C16A4D7B573D84FD0CD5960672E6515CA1BC1
+BA40AF1D76501C06548399DA7D2662A61D03BC3BD75D012B30621D0C6A052213
+B3390976661462DA6E60DB0CEB9CA555AD3785E99AB8AEED42E70305BF90ABFC
+C56C390EFA417FBE2FB82E9AEA03B36811B408CD5F90D706EF81DE9A75ED5B15
+6D726DCB2AFCE0E855DE25D23DF8E5D4EAA5364EBFF47C12481747F97B4826EA
+2D639E00F037551E7A5EA6421BE789D54E1D5D30370196A35E65DF159E2C7FB3
+8057ACF28035C9EFFD9907D566937228062B07CAE8E2B199512529B71EA8AC90
+600AA84AEE684DD0EEB00CCE2355D089F6DFA6C0F18D138A7907615496D8A998
+5974A956A524FD8EE5E6A82798C7FA1B71FB68271A0C0FB71CA17036064CA597
+19F882FEE87C727ADF36872A0C05BA8D9FE0424CFFB637B1E85AA99B9572BEC8
+031F44D8E24FCAD7833E27372F06233E805B8FA976FF30CBE858F5FE88FC54EA
+CD09B4F56E6A0A48049D84C1A124028072A0C6A1AD032F0D8194F5191F53DB6B
+07B65F9EF3A59248C055EC60A2CF7CBEE5CFAD31E6C0B26937E7AD0991A1F0E1
+EAE9EF6F0D70E6C8649C460161EF09754C7246658454E44337119681342D7CCC
+6438CBDA49130D072E2F49F1ED66B3A3BE6FDC93E573DF56748FD2F12E031DCF
+2B0AD2F85D92AA9F31CA398D81572A05198E18DFDA86B817CB5F244AAB2A0039
+6FE7ABFD61675119D606D8432B84010B80ACFBD917782C45787C3F6E20616FA0
+301164B4386BC5A0D43732238A26553222C130A5981415B8DFF4467AF95C9605
+CF63D0DFAF6D7E2D05DB0FD260E5C28838B3D8AD910DFE029F3B1BF9D43C38F4
+5A6E3FE7DF3C1467C1D5C902EF9123C05F46EAAA8F17C380DF04B3F164C2180D
+EA4EDE36FCF64AE318D8D13D0B307F668E3160A052639174F266116D4C6005C1
+4588F003B07A68BEEA3B5719F331A58BC4DFAF393B487599A0307A37235D83AE
+DFC96552E2238FD4D4F1AC215A8ABD6F928C96EA7E1437230F12E7D6B0EC4B62
+40494113CFC38EF265418F4495020007B8F997875368D2F7EF8446CB30D370EE
+DE8F36D195727C4A381F48F29B42AB70CC5211272822827868E958351B6E98F5
+26576770A833A726586A6FA59A42D2780FFE5AC3DE9358953261B31DE9FE468F
+CC8DB501C0F41B8A218076D77579B4C437C564534EE5646151ECC37C58E1B32A
+6BD702518C4A0BAD79B5CF825CAE60104D0838A4F15FB9E005507BAABABDDC2D
+F0E67F620F9920A83890DDF699308ED3BE657C51214DBDA6412EAB1906DAD9AD
+0422DC9DE4648D9E106990EC08FCB54A09A931A7A91121C7E5AC976D56907E84
+30B361DC13E62AA8CE37D255BA04EF9A2FC2D47484516B15C48BAF399DC489BA
+68D0B7E973734FF9B17EF07AF4D5C93143EBE3E439717816F998A2AF4F7C684D
+3CC1F9181C458A1D947F8A34C266882E62358F106EE81E02007C08C1A4F278A9
+8AD244A30F74B17408244FB69ECD2238705F5C2927C51C8698AC10B593C4A651
+04D5B601AB872D51288B5397165992E4CCB67B43F19E572472B6F804B309BA9A
+1891C775EBC866CAE897FCBAA0DDB72469C51775E6C68EAEB4A0E0046F22013B
+2E01213E604F9DE2DCE26273351A572C6408C264387CCEF8BE1CDE9DFA4E7F37
+55B7BD1ACAFE9422AFC886D6A27C8F9BECFDD6612C29DDD4F45DE8C9C0582C8A
+0406CA4253ABFD29307E143CD843C666B567AEFFB5D9B0FAD58AC3F7D1545075
+8BFB2881035407A347E2CA572B4DF2266610A05B6FA34B59A54E0AD74A143F66
+64B35A58DFE2A5351683243FBEE5CC314995BCD1F918F581304CBD363EF21C91
+193428EB1CF98430D8BEB8D11E55E7A577B23BFA8609DA01593A6E53DB8756E6
+8C3645521BA08AF58442946E70A655DF2D7A9C1CC40060F7D413D73B751D48E0
+6D583969C3EA48526FC009311209D1600D9BEFCDC2F1A3F783D2A01B92F9F3DA
+1BA6847BCE41847E6A991F54FEDE9D76DDF63E7D8312FDC6B308A6F5A1375EA2
+2280F3C1480E3CB9C38CFC536FFFA3A357AAE845B00EF45230EA00CEC2FF06B3
+670A87AC8CF3624898E4E240130AC15B8C573DCFB0B92E07D33B36CB5FFE70E1
+9E14DE5562F968CDEBEA75721B8B087C698F009454DFCA91DD29C261D60871DC
+FF6142EB798849E9166F3D61E021CC30D4B5DF371400A697BDCB9A78ED973DB7
+8D8EB2DD13995F13C8653BC197F7D37F80F81C441DBF046E9CFA444CC1E189F5
+494BD128B24BFFC8F517A12CDC18846958B8C69D41FFCFBD2F5A09AD965EE8B1
+9E542E5AC2F5ADAB6A2C6EF31485D656CFD0B50720C5F3DFA642BCC1667BC298
+A76FAF7DB441D6877A8B53A450ABDD299B9315EBAD0DD48A933867DC86811DDE
+0B5EED686655AB00EF4A6DF7B0EE644D578C6DEF011D47AFB8E8C9B8715BEA1A
+20EFAC19F11808A6CF93074686496830676CDE3EF843A2D3EF68CB004C3CB472
+99E4DA5F2733B314FF90701AEA65130D1A18FADC67424526368158AE2D82079A
+7E8078D9CE0C77AB16E582C16D0E5ACD1E12CF70A4A20689E33F9045781111AC
+EDE1E3C25313D7DF52DBCC09303A0B2704C05CBB8F8C7226822F391C802BF293
+106D58D1C37D35CF48F3518B25EDD50CFF51055D22778A7FC5FD0C62E9EF6B4A
+C43B814B5E0A12A49AAF20BE95F6FE037277FC4860A60714BC367D28C9B237FC
+87E58A07AB03E869B9FA79989733DC3E929BF36ED0B71DD9A9D2614299426E5F
+4EE3F63BF07C3186FE7FCF2E8041C0F685D01D7BC5CF84661899EA0AE20CB1A9
+3E37F28A6366D87B43FA2B9D256528A3E3442FC1F4AC3EDF8F074F8DDA4DA417
+4F7D9F14ECE3D16771406CBE27E7379B4DA0C2BEFB217BF112735F94E3A543FF
+F21CF6BE56DA34313D637F19FFDE7E1C9E84A4F24541307575D6C1B13A9BA39A
+619A67E81A1B09B02D1BEA936EA12FC8F11247235211060F9F076DD604D307AB
+3DA4D7A02A2E8443EB55EE6205DA626E163C51945990C2CE68D8DB41F361A2A4
+1125C5C3CB75E039253C68EABD01F42012DEC2098B98EA479B510BE89967B61A
+4AB9A5488A0FE103DA30872FF137B1D18DE85E083BF6D923D69A25FB315D432D
+FA0F0A283231B5FD23FCF4EFE5EAF45EAEE63FD98132D68779943FA2D1A45576
+1118A3210CA455BE0CE81CD9BFF04B3D9B2DDFDC5A239757FBAB6A4FEE94ADEB
+F0466FE94E22680A09CC0A81D4CFCD3B9BBC91E4ED0A4AB0BAE58EAB103A6074
+D0DA9D52DCE4931DDDD9451C1CB5B1669E518795C430C0AEFA33CB169692BBAA
+4024E40CB5911215B4717530D9B2B937E8F86AB146A6C58B89F53403704ABA91
+C860CE9916AB4CD468D10EE5ACDCCC8E75C8AFF0AEEEFDCA43682480BAD0DD2D
+B7D3DFAA55C59CDF224977840A8A7881FC89332DA667CA62C3804116E4E541C1
+1F7889D1CF79277EA29712531AB02D539B1FE27206F688765EB81716C41A3799
+FF72F5DAA298AB30152954822C77F3B66FC54A51D6BC7AB6AEFF7CD93FA94ED5
+66F0124F219ECEA72E6AEB15D5DD7EAA366128A54E43350B006CF47642900E0B
+B4577DD12358BDF9C8E4C2C93444B9A29D442FEC36E40BF684D64594951EF807
+D587786C2E636CBCC165B63D8DDE01A0EEA0FBE2DCA45C4EAA1A1CB164B05A3D
+4B594249D0A0BF0CB2AEA95A71A483A179E77A11A49B73CA88C81F763950C6CB
+C4702FF7F4A58665C23D73F00F55C48527464B453150CA6E5B99D1BA08D3DDFB
+B5B304DE4E6CABFF791CF2FB9912908029A383E8EE39F7EA2CCEFE949B536D90
+BC0D4D791582743075C21E37625DCD219364A71FB21476A2E559A9711F662F48
+AEEEE7E73B1DDF6BBA199A66C60CC2166FF9B4C4309D096C0B13C011D3ED30B9
+374210DC96CB26FB201EA9CDDF94DD9FAFF39732B4B6A71E86611FBDC8742D4A
+C7E661E18DDE503C94DE0E6DADBB1AD6C7771D1AF783D504F2513FFB87C4B3B3
+90AFE5B8A8969CEDD65B59085A2C2D11E826D1AE484253E4B31EEE0C6583DFE4
+D482EAF253505DF691DE72EC54913AB5EAD1F051204DAFC9C6720157B67D883E
+0D04B4D7412F0F854EC44CC4D83F8EA2A7DBE940F580DF77FC0B7F1687EA5FF6
+DC8AC26C07052E011A10738CC7FA1104FCC60AF85B66D2294484B391267CCACD
+9F50661526250FAF134A8C487B1BE57F01D08E06AB5E1689CA9ECC8B6062B568
+0E43EDCB4C74EAADDFC3BB1D309C2BF166BA3E2E3F276E99A288D291630EA951
+E63D256587E54FC0E731E43AEEBF68ED71BD85D95C957FE1C2D78EB5CE3A2FC3
+B31F528FEE1B2B9EABF43AB591749CDEDDE9D83C2238E5541061E88C5B3E56D6
+3B5E1EDABC2C238682705B8BD673B383284AA5E8B4AFE1B05913D1BBE8ECE2AF
+E5B96CB431D77065D35AF5EA0FF1B84B47655A45286E4D6EEA94D0C7C1BA6BD7
+9DD1943B5CA1D503CB10FC3F51FFC53E556893D280B1384F81599249F32BE524
+9439734EA7DAD4A6C7C0CE41FBA832EC6D4B3E54EDF0AF02AC694949F425BE49
+DAB43F2930D321A349023FBD4CFA05D9C8E1399E48F9EE7E3C61EF5833E89159
+423F3A8155FE9441C9172E51C9552ADEEF047312BADE124C8BD0A0FD2A2E0DD1
+A6F3D338598A3836AD46BEC0966499F558053D5DF15585DECA93339718037518
+DD8DB8E9D7303BFFDE3AE50902CD27A97388460424CB79BB1348D2C0E6DD71DC
+0147D980E94B4DD28F3BFFBFC356EDE6220076D2E0F9286D7E6E0ADFB03FD673
+9095CB3696F5AB10F9CD2036CE9B88F51A3DE177DD9C6A82AD0D45DD6EA8B8AB
+D8B7D1D5AB032EE378E5FB62E5C967F170590B0A9AD94E038C621902C674F43E
+FC637BAD1B9EAC2206A29F6C7FD4448442BE438F688584192FDB60BB7524DEDF
+0541CA37DC5E70A1776D62D5261425E17671E98C45070852192211D947627E8D
+26195090547FAAC5D8763FA76353934B64DED4B01BB73A72131F60036CD7B86B
+15B593959F997F7CB38189F00FD5BF1E90E7F419D163A57CEC5AF1ED84115741
+3C176C863F8D53C6AB667E141B13B4D07C822D461840C8F7F8D2C46EF4D10F12
+359C7C9EE4B4D7802C857544E4CCDEE30947593A474A87C81902983062345748
+370F307C3D91785239E17215291863C565D2F737E4B1C2E44E85E098EACEAB72
+0E31F40655E97175DF31035E66C73DD753561EB2F91FBAD13A4E1035775A4AA8
+6E2994505069A011CB338779D4C3859CCB24EB8F787435C959AB36D83F04EEA6
+50308A38CD3688C04A146DD15D2FE97716304CB6FECE9B748F9A5053DE280366
+A94C14C0D642D169AB4185673C97C2F1D864E72C18A44D8D7D5498D3BD1F17D9
+94A56AA314BB0BE57ACFEB16AE42FAA2DCD563CD67A9890B9AC072818838DB0A
+F4A099C2DD
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMTT10
+%!PS-AdobeFont-1.1: CMTT10 1.00B
+%%CreationDate: 1992 Apr 26 10:42:42
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.00B) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMTT10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle 0 def
+/isFixedPitch true def
+end readonly def
+/FontName /CMTT10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 33 /exclam put
+dup 34 /quotedbl put
+dup 35 /numbersign put
+dup 36 /dollar put
+dup 37 /percent put
+dup 38 /ampersand put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 42 /asterisk put
+dup 43 /plus put
+dup 44 /comma put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 59 /semicolon put
+dup 60 /less put
+dup 61 /equal put
+dup 62 /greater put
+dup 63 /question put
+dup 64 /at put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 74 /J put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 81 /Q put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+dup 91 /bracketleft put
+dup 92 /backslash put
+dup 93 /bracketright put
+dup 94 /asciicircum put
+dup 95 /underscore put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 106 /j put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 113 /q put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+dup 123 /braceleft put
+dup 124 /bar put
+dup 125 /braceright put
+dup 126 /asciitilde put
+readonly def
+/FontBBox{-4 -235 731 800}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5F00F963068B8232429ED8B7CF6A3D879A2D19
+38DD5C4467F9DD8C5D1A2000B3A6BF2F25629BAEC199AE8BD4BA6ED9BBF7DABF
+D0E153BAB1C17900D4FCE209622ACD19E7C74C2807D0397357ED07AB460D5204
+EB3A45B7AC4D106B7303AD8348853032A745F417943F9B4FED652B835AA49727
+A8B4117AFF1D4BCE831EB510B6851796D0BE6982B76620CB3CE0C22CACDD4593
+F244C14EEC0E5A7C4AC42392F81C01BC4257FE12AF33F4BFEA9108FF11CF9714
+4DD6EC70A2C4C1E4F328A1EB25E43525FB1E16C07E28CC359DF61F426B7D41EA
+6A0C84DD63275395A503AAE908E1C82D389FD12A21E86999799E7F24A994472E
+A10EAE77096709BE0D11AAD24A30D96E15A51D720AFB3B10D2E0AC8DC1A1204B
+E8725E00D7E3A96F9978BC19377034D93D080C4391E579C34FF9FC2379CB119F
+1E5BBEA91AE20F343C6420BE1E2BD0636B04FCCC0BEE0DC2D56D66F06DB22438
+452822CBEAF03EE9EAA8398F276EC0D92A7FB978C17805DB2F4A7DFBA56FD6AF
+8670EB364F01DE8FCAFBAF657D68C3A03112915736CEABAA8BA5C0AC25288369
+5D49BD891FABEFE8699A0AE3ED85B48ACB22229E15623399C93DE7D935734ADA
+DA7A1462C111D44AD53EA35B57E5D0B5FC0B481820E43222DB8EFCD5D30E15F9
+BA304FA879392EE0BCC0E1A61E74B3A1FC3A3D170218D7244580C7AA0DC65D19
+741FA5FE6F8CBF60250ACC27454BBF0897CA4B909C83A56672958752ED4B5E79
+E18660764F155E86F09EFA9F7685F2F5027EC85A775287B30E2069DE4E4D5712
+E7D033481A53A2702BA7542C71062173039030CF28D8B9C63B5596A9B42B33E7
+D922944A38713383D3648A4AF160A3B0C8F3379BA4372BE2E7EA49AABA75AEEE
+C5DDE1D8BF68483C3D21271280ABB91D54CC819680322EAB72E1250A760BC8DA
+726405EFE420635B5B7F0B48752C06083E92BDE06401C42A2C528C8A60381227
+CEBEF0C9440DC034DAD9C19FB27DB399BDAEE22053591D6538587C768C1B7B0B
+7D1E222D2D8AF3A6473CC4C0D6C3E0DB49068CEB8C9BD1C5CD486A50DAA10BC7
+7D6286142355E3F21DD254E27C00C442728A0BAEC9D3F17AE9CE320D365152E9
+EB0D5E3874F2BCEDA98521D23FCFC30B4B69DAD2ADBE80E5964ED0ABEF6C73B6
+DAD30E2C5061E3747FE536E1A5D190D028F2130AF608F5DDF9DDDF1E77DC8437
+ECB3EC93B33505DF47884DDBD1DC6BBE4098DF04A29AF6FA3AE344600D0AAB53
+B3820DD7ECB600A3B8001C51AF2CA7A39AE1485A087FD1752DF68F55B52B4DA7
+48030F2AA7E570B3D56C4EAD367B9B73FBC0A7356253233006178B9A6BC19081
+B815B5988AE76FE6FAFD7AC239072B1106A3F509381AAEE79B2F2154CAC4727B
+D199CDC8B4D05DF4BA006982512ABD7539E28D937B0F87FF79A3F84C29ECF943
+A8DCB8BDF8EA9E7A0E7CD60BC2308C96B3E889C797D0FF28FF4847016B3DA141
+E76FC6BE78A6EE9CE07E651FF86E720A1A1F075972D36E5C55162E3FE26BCE3A
+814BFEB12D4C5FD24340CFFED499C7CA183E57EC4F12CFFBE3291D43F7270575
+C6C3306F832EF182ADD0AA14C4D8669A17C09F632406AFA195F90C4DDC39779E
+EC0A77E590211592D6EE19563963225C06C2F13265EBB5A6CFB7C17D9E77650D
+11958305727AF662AE73AD0E3ED5F7E7086C5A0C3548A8129575980B06C715AF
+DD55C8DF869BED0A7883491030B1A7E82C5EB04E5A7D952E716DD8F2EF6275EE
+087614CFAB55FCE2BBECD7E8D9C90FD8359E929D5E0A416A23BD58158318B4FF
+87B095EB63F7F052B3A77F136FD66EB2C52BD46CD7DB3091A4B78A607112B12C
+4D171B2A00B78B0E1C44B0D90C20D9244281F5123DC1F6063F91E9E3E48DE78B
+C862D848BAD073A4FCB5EEC9FF54B5AB8E234CCC3C7439C62ABC4A13EF1B8897
+ABBF21F900C564C9A305FC36FC7224932F766E6E72C2EBB55953DFE2AFC2E3FD
+33A0C6F0FDFF086E9FD796E7242596AE85B877223532667625E371D2156E4C04
+0D7FFCD3337B93DF066CB6FE1E13960719EB7CB409EE805C08ACD2C06303ED9C
+E34C898787A43C1B428B896551C6FEB50A831C6F8CE2073EFC662EC286CB7555
+A3B42E58772E82FEE206948B8C439FEC5E4ECB9E11DC3A4CBC7611E30890E408
+637A01A2118441B4F9467A98BB2A1B03BB2F5D8E3DB7D1D15C188D9E856088EC
+B762F07B1C06024F7EF53A2FBD60C0A1F4C0275D07164545250ECEEF8CB15B04
+A2D8AC44DDE818C4E3CBD2A5FA0FE49750886CD7CFAAF8B780255F89DF7F4F5C
+BB594FE7C1597DA71813C2952AD3E811524459EB71D29696B450C924B6A5C843
+8F36A0F1D7DFE796FB9564333666D74AE614D0D698FAFF20F83C86524C894BB0
+272221C060544F3B653CB0E4E4F82B20D7530B3806E6A5830852C58070177815
+E287C847F19F64E854F1463C23DDD80093D6FEB8BAA22C5F05C21F99FBA7193A
+EB7CD49CFDF4308C6C68CC955A45FCFB54FCADA9A3BFBDE086B057DE88BE335D
+280F5338D7E66AD39FD08F9B55884F1F377FB6869FBABE3EAA4B7ACCD85BE672
+724B4B8F236B0889B6E7049CBA558A89F17863E82DF145DB8C7ED1F36332DE23
+3C0053B74E850FA14F9EC9EFC23AF18E153CC96FB0FFD910347370E57F0D81E9
+4A83E2D189EE5635E85A2BEAB5B1CB974546BFB2FC2ABA1E15DC0EC1BB3AF1DB
+B2F93538B92F504CBD7AAFE36F5F3AD45EB16378F169B17869FE81464CB826CB
+400D2F5441A496B6C60A4F15FD20ECCAC1F8F91015E7E1C1A10B7992A1554E52
+9FBEE905A3005336E49CB04BA7223F1674C0BBDFA06ACA34F7BFDA56906E04A7
+4DD79EC7E79B021A5008F3B1E04712D689366F520B0FA66A558F957011992728
+561BF4B75C2BE07C4024C172085E51CCC5CFA439F570297154CDDBB3AA25CD6A
+3004B936488851BA1E814260C06CD5479DCAB1A6AE21A5F4563024F973D738B4
+0DDB6C6DD2E3AC21B4F6D95CF9AACA782919F5D3E613D61F3224A982AF485C8D
+EA0037410EB70AB7D3EC174C6D5DE5C9C5A1220EF7C2B74499ADCEEFF077D1D3
+50C1124535F88C3C3F66477E42F1932665AD323E06B398D2805B9CEA632F5B1E
+50FA587B102A35E2F15EC22DD66E4DF06A3F4BB717A3ED7FBBE2458EB4D896DD
+AF00D1BC71FE1CCA27890ECBF9F0AF01D3E65CAA29427FAF06B3BE1E640522E0
+73B213D04491B93DB29113EF72211E31F4C5A7FD58451946CFC15FD805112FE2
+547D1131A46710DFB75659A33695FFAF3CDD40AE5260AD6766DA81DAB0A6E96B
+E89D57AAEF32B5EDBBE9F7CC033BB2595CA3FEDA2ABAC8E5395EBC35BC112FE9
+67EAF1F123228538091483050847F8FB5194203609502D3A09CDE811EADC18B9
+F039593782C27EFA7697182D6367E88E326AD5622C5A457FE2644FEADA88615D
+9DE3E483BFD9329667953CDB86F9D2F0D4F02DAB8A98FDEB1D17CAAED9B6E2E6
+0C55C1FEE25AB98FF59FC235876029CE03E4A713B75B3163BE3B2DC0D4472DBC
+473E10400C0F57E627AE97FD0C1CB0F78FD8E2FA831A3D2B1C2BB3F2D4E812A4
+194C8732B0C525361DC8480CB27C30CD4DCFF01318D2EB4F5234B4A42EA8C23E
+7B3EECA41B8E4F54D5458B37EF0FB2F49EB19F4EA8AD2B53820FA36E93DD309E
+48847F5C01B1118ECE7D0186E6B8953344EB775D655AAAD7BCDA642EA2E39A15
+855C027CBC0E3FA752900EEB464E2D39404D1B85072B40834748C6F9C74C5B6C
+3CEDE988343FD984CFE4B856A481E60E2E65D3BB41BAF2FA80AC0BFE381071C4
+573C6ED65C524FF777F34D82E9661E4A75E3878CC77BC59218244612219C5A92
+E95B90EC2C38614665550026F1730D11162F19D841681C04C401E102C047541B
+97B9264D86F47E25A347696AE5EF0FF3ECD9BA32C92901DEDD816F7D73ED1216
+0A98771892472CD625A8F7F19DEFCF5CA2AE57F8AD3898F2C1005B187DEC6F2A
+A31C32720EBC934178E0E9979013B3C9AEDA4051DF63D8C903A399DC88F83DCB
+A73F1B2083819D1BBEA5235F8FE1D098F32A2BA6274424A99A4975FE4BFD59AD
+79B40A8003CC0AA728EA79D6BDCBBD73DF45B7918BC099C5BE4A068BF64A30B1
+C39442CED98AAE1BD495F6CA32D564A72E3BF753B49E4178927E4BBC0F06048F
+96DE7C30AF580B0BFFDB330B3B87D7F6532A24F403680BD9F15E758CDF04EB94
+E83C7E644FDE5BEE7CE73EFAC75669E41BDFB20A5B8ADE1137378DD8102A0DBE
+19499A623770417CBF5211395A6BA9F4490F4707A46F1F9B3FBE642DEA0CA053
+9ABC307B1E71DC2B069DDDBB4EAE378BCC75AD61DA900AF8BA6DF0E27A8D2258
+DC80205305AB6ABFE3726703E60869BFAFF1874F3C0E05FAD9C05D7D89ECECA9
+DD2AF5F777D7514208697E712B52448B364D3ECEFD8127043DDC9D0757B7CC37
+5CDE8001D007A6E961EA24D7FFC92410F3B13A32946F12A50DFFA256249BC8D7
+C1842FB84AD51B41008EC4604F6B70990510EE13E6DA34F864A572D99A13FFC7
+3609EF2BB1FCDEDF37A6018248C545E086EAD1BA1143E74AC60B684E755E59E7
+36557B915F92EF78FC177621D49F777A2AF39F3C2AA6EC74750AAAE08BCC21CA
+A71CCDC91DD45E6050D83ABA49ECE425B55EEE137C55619037F1C30530BD0A6E
+CD2004B6A040405064D7E87C55536680364E09248BFAA3FDF95CDA0708E55F4C
+F7D0A92A93DEE0C7B69638F171B28B7F854CCC6EBC6AEE14864BF5144EA36D46
+A9C297225AB0325E28EF6BD06D7E40E3A724EA1E50C4C6163B195CFFD5DD291D
+D7BBE9AF4324A69394117EFD62F08D6BA6A8F0AC3E2353492999AF28FBA758C3
+A50B6840CC72054355E6CBDBD86F683537A4115049BC1616BA35C2B0B6F5CC32
+3F6831DE4E6029310738DE23D36D2C6E82F04EB675FB89789F74AFE3B8854250
+51812FBEFBCF162947554324FADAB765C74B6DA89F60A734076D44BBE45263B1
+3FEFEEA90EC7948F23F34D4049087AF6563692417DDBCDD5A9552A373C2528F8
+0318D3C0669279F292127CBA40B0ABE08A1476BC9EBFA8BD5D622BC5CE7DBA20
+C689BDAF50D5B1EAA89E296787CC53845DB2BA54FDE363DCC98A7BA256663869
+E9E02E09077884DF1A2A41AA698B7EDE8DAFA621B552DDA91AD1E671D636FB36
+91C62B4D2D4112F2C169E0023EB7521F570CECC54ECA5EBA462049AABBE2ADEF
+E3234BFD71B26DFDD9D34DFA69E5E80FD90406E6505A6798F030A4B5172A7BC2
+C9B765A86ED55C0590E0432719BCD7BDE7CCC7F6B33BD467063D886276C8879D
+E04897A4623111C14A1EDBBF69E2FEDDFEAEB2A785C6D2F0711DF4B93AAA291E
+7F4E0CF9CC3FF0D31953C594DAD014097DA02CBD5AE8828C7E7B5BDA09188B05
+0D7263F164E1E78CC430ACAD1E8FA71001E9BCEFAE47C79846916A5F819CA366
+5734089BCDD458CA1A9E8E17BFF357A91F9A7A8A6E1DEFB121353AA80F1906A5
+AF7CD2E59EE6776FC0DA6574DA0DE522918CAC4E566F13FB9B64EFE79F3A3BC0
+689E3B0676741C90FF3BF85C7A0FA9716F4ED0E329512B66BFB8AEB56C3DD6B2
+24F8D6E23751A8485F7EB46719E9D22618FEE86D5E01ECCF4C6E74368A8E9B49
+245D80E7484DFBC916FB2447852B36EF3F99A82B6C106F786707D7689DCD7AEC
+A0C51AC1A3F67034C16B74994403FAE7743BF02149BEBEF554814BEF31B79184
+3FAB4D2C887E1BEE81B465D12DCDDAD03DE5ABE9E763C440B2CFD42FD16D96EB
+C21FE788C8C2688F79F148AA7090BE64B0EA710D376222FD1590301BA9A2E715
+D33B8C1D95F2589AB0EE476F7046537E27DBBCDADEA1E7357C9D7FA92C2F93A6
+7BDDF58A44966590821023380C97CDE37EF6D449E35EF32BCA6E69DC8458511E
+8DC8AB63171A6018AC9A334829E5978484C4C6E917A5F1C254E6669F4037C691
+36980250A80673E0F18C9E0FBA1E5CCA3BE30B8E7B7188062B25F8E1E16528A2
+F217C18D6A1955482E5463FBF097ABAF7314E449C6FEE56E2695407A8AA9648C
+61AC2BF3B2D9CB6317A9B16CE931D318C8BC9676CD908505568C197D90C2BB46
+06431C999EB68C8216409E4CABACB2BB34A05B697B9DD1E91471A404B4969519
+E25209EF4EDD420944BED17B18DB3566FCB8059699FE416789191EC2B35086AA
+2E10C139E3C9FA0A535DEE9255A867A26656213E85851DE5F51F9780D3A6E572
+F1F5CE64DA176CA810799DC1C60A8FD2A5ED42E613021A19928EC4572059B2C1
+EE441E79CDF7DD4AF7B6E3D3230419ACAED329388044B107DCB4DE91B71EB838
+904B1F969738BBDA064FFE75C6623639BE9924602DDF0C166B433B9D54ACDA5E
+018680477FB8F10621FF32319E58DB672D744959A33E7314A1B3CDE0C038F7D6
+0C8A195AF191E36B0325334A711CD8E25D9C1D257E46A734779E486567481108
+E0281DE96907D460546578DE83A0A01A9ABF64402B48DEF739F4308E14145753
+719CEF720FE5CF8DAD7845E74D502B69DC18D172C3A27411259B8042F3FF82C3
+B157BE242C351830255CF0EDA96577375A70657BD9A2E9FFC54AF0AE563D73F2
+E510279FEF48D79F5F7745DBB492F1D74DA738E6A4FE4364799B5BEC93B4CAF6
+B06B9B8C8D164F8FA1FBBA693204064F2C1806C39910910E02ECA8D092558CB8
+33338B359D56483B7B99A1D8137204EC1AE70ED3D75881FC3B00BB9349AD934C
+81A9F285312FDDC77FA923B18B1873D288C2AAF2E6D0AF90BF25A982B843789D
+5662D6A2DD58E065026885601ABED4B09CAAA3116DEE6B430B15BE0A121FC1BB
+FDEA5A501F0798CFFFFEAB5101E707F1A00C8E014A3561FD39972EA9AB108EBB
+960AEA7FF60C301AD6CBFCAA7D35CBF6F8462A4D76C4FBA6F3DF6BB762DF7900
+9F69529AB4EAF96C2866444B257160E8822533A7A1240C83EC18C364F577407B
+4CB314678D2511735308A1660AD94B8B818CEA4A3DC00C5A1C978F8BB4E0491C
+49328F6CDF95BF620AE53056364423841D84418B23C2A447B0CCF8D8633FE2E8
+4A4AC1C6C74627EECDC994059F1BAE9E6B10FA80D767B3FE97BFFAD413DCB0A8
+495039744B48266278194D60422D6E7C74D0DB45ACF217797D0C0678EEB60759
+6231438CFEFB346553A7A447B50807EBB6E885B5A49CA9A350EC4A8C76EDFBB3
+A4DA1C9E3EFA193CDF08553302998F20055C84420A4C5252F764CC4B7A4BEF6A
+A09170EC417B296DD9E2301CD8EABE4A087E648E0525A9FFAF26374C47FDC123
+82F18C9884843864F418ACB08041E7896FDD395225532460A8194A8DB4DBD824
+1C68C6665F85059E365EC0972EC6465E2D8867449907DA6692A021F026F437BD
+D02654BC11381BB6557663E0B0B8C4F2FF69E4776F4EABA69311BC1AF8155F7D
+6D3A418BDC912CC7CF1A4BBC8A1376D8B4DEEB6585416959BCA4AA08D4520C33
+EB054DE53140992D0707210593BE62B3659E3E493C4562C2E99CECA143791DAC
+679896BCDA0699E405957E17DDBD243E65CDD7C9C8629F29A2078658746A7779
+0F75BE24E2DDBB672B95F26366BAF036B3C23BE4132D7362E76D4183A469E0F7
+29174711ECAF4FD9A923E72FE58DF2854C5537E3626317D471D1E8A922C9BBA4
+CE9163A4086AC4A231C2BF35FBC39A5BBCFE41843CAC7D81A054509D31572BE1
+596E0B0B563DF2BF0E57DB4943DAEE35CA26C8433FEE4FC61145C77F65DADE75
+62DA18DFABC7F4194906F53884E62E77D8AB3E099776AB93B2B4D0C98FA44C71
+597202A2643942795EE8CE098FE26F1AF8134F1E75FAE18D563B1FF43A511C9E
+EAFB9EFCF61490A1A4FD2CF354927B72C5EDD5D62B2F3F5006D6130562A13BCB
+1B988A994A8D68B051A5A821CCD5D0F8D9D49FE7CD04EECCFD7A554CCDFFD77E
+27AC4AB5BF9FE40F90EBD066C483796CE1A364E95C5E0CF2154834760522F128
+B2DBD1F4F73347D42635B2875A23597C35A0823CC6F71E49598125411BC9B2C2
+72470D36DD967C947AFB031BFCF770FE50551A134DF8C5D1AB1F09819569A57E
+E23D4E87C0B52CD02B0A2E3FAA7D27A94359E82AF047756BB769BC5950A75207
+78ABD49D174F2F69810AFFA9336A52D6B93B004DCA5CDE58475C0210E0BA1D20
+FD4FFD6838EC56A0922472D4C4EE0CC481574BC30618179E733EA40A48847E14
+A75BE7717CC5DDCB5B0718074EAB6FF07CFFE794D335B3A13EB968EA8FC5B08A
+13B38AD1C2C964E4B07E90B9732C458216B028E07DD593A5B767A2B415EFE7DA
+951FC07800F11C7E2EF9BDD152BC6815B7F32117F49FE08BD79BEB949003512A
+327F3F8FAE1767E7842348BA4373649F1A21DB2C56C081BCF9FA4EA86C8DFF00
+FF45C4F1386CF8C2C4120F3F6019CEBB639F2D272D08C1763A470D4BF6330DC8
+43C069A6333113C3A0C93471486EFE9BFC02B760C7CBB2E9156087D09EE8A178
+5EF50B34994094C3F0015EA2ADB6C920F4302FDEF128711994875551C4E883E2
+DDEFFAAE11F2234AFDD96400BB69C1B4E6EFD75734C586A10A54A98E7D790F28
+DEF7C7DF61FB23BF91AA700AE585EBDE74E215DA49F4ED466F46129022722086
+8884D8E026F35C4BEE7E866DF8E0846D5EC3534069B713FAB02D4B4EE3B44E1B
+656F30D629D40AA1337786C1FDA08EA1217AFA4A6E2498B334DAB5461A70DFBB
+5AA5686C89FFA4EE82D81CE2B28334DC5C032487CCE998616F48150BA1281911
+076E626E5BFCC56A0A4CDC559F878F14C2BD7A5148C1D8CC303FF9EC473354D2
+D4FB0F0F2AD0CF182A28074ED6552E179222570DE0E0D44E8FF4DB36C3AD6487
+C4BA53C8548714A69FCF8E3E5202F09469D7447C6519AE902C1D611A720BAFB5
+59E27A6DBA73624F44B4ABE0988BA3450F82E03521CCE8EDE8BE7EE1223B575A
+DF9A52650E85545525E6F121FF2D1531F156EA9D5594239AEA2CD09EE28ACB15
+A445E11FD1C031188DB61881F474D49425C084489A88A47D681EA68E7FC4B1F9
+DBB552063A02A0EB51125E9B2CC646B940D46FF457415F9565892DEAC030F08B
+E4C10DC38D825C7597394C844CB863CE6C843F67F2E1C42C4EF86AC7FB727BF0
+224B5E91BAD99CC6638AB2C64469A81D8B1789981872ED037B3A34BDF3130137
+80FE80FDA65EFBC11A08B98A1AE595F980B577E22D3CB7FED1D4016F5290ADF5
+47D7D9BAFE39F294582F2C084003E9C83FDB9EBC87C8B477CB8BB359EDD9BBC9
+9368D6605E1468A20909831BF602EFCEC0D5EBA99A2223E5A269275C8B221B3A
+F9226654185929F794E1979ED18B4CD36152F973433AC67BE24B9D953254FBBD
+B644CDF3BF0E29A2C72113DC486E46DED2CE8F8DFA8B0F8478D1F18C9AA8E054
+A31C3DBE84ECEDD85DF6AF9467AC2990ECAA3384FBCA1BBE598AA0D6813C859E
+1520B88BF30ADA910A6AC3068A5B8CFD76B7F0F6F4AF4C32450D628B5320C384
+F23A2B5E8756895584155226A30F8B0437E028978491DCD00E79C0ED58DF261E
+79B9DA17E57AEE03EE92102EAB2D63E69A88EE0B1E2087ED0C0CF6475EBDC3BE
+0324D1FC8F7B90D8D807533E5436F2C2583B9629EC390403437FDAC908557894
+03054A6DD6A3586043A9C8BFD0C7EDE1229DBB9F69F7A5D20F55664D061F6517
+0051C6B3CD7338241FB403F2AF77DAB1A8EBE1650156D40863EC1957372BFDEA
+BA8D0BB1193CC5BEB5A68C8274802E14FFA3ADCEBE19070325B1BDB960CF2988
+C0F5A9BFD843C515ADEC8B8AB02B2891EDD7502D9F28F4E58D8F67D1ACAFD0C3
+3531E0C7D1554344CCF90AC8696E83A3F968252981CAC09653956F4343B99D3D
+4F17CB8BBE4506B354439B70F2024871D16668F9DECD8EDB872BE5E6ACC406F1
+1DF4E3ADF60EFED57D1C426292970199BB663405236C6A907B6891C6190E87F2
+78D9142220FF295C7BF44AF61470798FB8CFBEE6973C69DA1CC24ECB058AA753
+DDBFD92FBB15560EA19D5D92F0005B74F06F0EA5901D231996E0866389DCA433
+E62BE48479687084C1D67BC592E592939F806FA8BF5F0D3F644B1FA6F056DE0D
+51D3F212C6818CB6166317058C2A0C07AE2E324CD90D4EC83CF4819B10CC348C
+6DBABA024A5FCDAE6E288F82DA060BCD16437F07DCA43BF1E5A1B402F16C78FC
+075BEE900B4021A1019C4A5ADC33230047FF11FDE8FB775DDA267040A22B4E5D
+6012F7E72B8BC8DD3A81369A08FB81C6C4873C2147D03D4181D6D8032DD2B610
+9C44CAB50C5BD8F489EBF01C72D4198B66EEA4E976462F8874143640B82AE57C
+A51EDEDE75A9A55D31587C14F8DEFFE69F75EA7B95BF725CE9991FB2F07AF568
+5AFEB39447B728B99BE0502BF28DE1D92B15926BE4E3DA2E7BB44A24836A97C6
+EE3A2080E01DC6514180DAF9C055F4C94929D34F193920020505E62804461630
+9F42C652F9D5681C91BE23DCB0C634247E739135F925EF3D5424767D5F5C5879
+C46F2E32C7B3BE9E90FD6ABE693A6016AB77670129B58B8FE719FA97FE320842
+6488CB85B6BCC0012975D22E75A2E086131DE676AB825A386C086FBE1B65DDDD
+A19F06AA4C1D3EC84751C649F4A62CFDC48A7CF88CFEC68B959C211B60DCB045
+6BFF922FD7349B98E1769394E6CEA4F764AC4B6536AAE4E6BE69099A39A6A33C
+97671C3AB4E7A94DCB829FBA97DFE5F71B1728FC81F826699DFDB0ACE9BC60E0
+6EC15D35EC479F3F53EE4D0398BAC138FED504A84A13B78568E3F9C86BAE8B88
+61830A80F8B994D0D66A8FA3FCD6C5099C29FC285ABF096EF9A3BFDBB522157C
+DCE9F0D6AAFB1F8D7B0A3C573D0C170357175DD56EAF37BAAEF4C92FBE17E26C
+7D2BDAACB9B8F33D09651FBE0D49A8BE66B78D075485BCD38DED5056FCE48A12
+D28E9670EC7CF4E9A277D6ABC2F7AB30BFF290B5452582F372FC9DE6CEA9EC0B
+84328269F14FE7F47620B1042B283C54161AFCF84B46E6B1410587295E4F8958
+C1800F120B59639C85D46D46A4C64309931A8C91F138EB52F779189EF75B9157
+D624045F4B8846856ADF0AD735FC6FA41F7B6C002E9D1EBD92468E86C843AFB7
+4D78E3D54D866029DE5DF865EE3F7313AC358EDA70A792E22F2F806EF86A6B57
+64AAD565C57E64B1A6635B7394B4B5729189319FCAC8529ADE30633B9BDEE0D2
+AF1F8944EFDC7C408FD8FC270822CC01E7BA355C856219B3AC5D05CA37EB0EF1
+6766D62383AEDDA1F7CDAD1DF0172E766BB46C5FCCDDD61BB019D283EDEF312A
+B2DBA38C9BB0928FB93F50E8516AB353BE04403D132805B5AAAA17163AB9C847
+F1B54946B0775FD21325C82E4EC7F2186C54B4396BC4B0B913A59E4444D11B39
+8AB56F2FD5788A9BA45DA5499A50BA74D28707F62086907BF8342E0C753A31A8
+DE293B592F51D74DECA52858CCF76C69BAF2224F640069BEF2604983FB478173
+792D68030D7A6E3FE083AFFE9488D872897ABFC88CA8BFE484A75201D73058D4
+72A8A26A50BA1F2B50CBF98D46DFED0BA057619BF370E435A0400147928D7C06
+28DF2A03527E3BE925D6A664E4640E63BD22D54A038D934B3DB5B500E075B8AB
+06DB5279274E65FF870F1E5106E190AB0FD8849EEE2D605FD4F0DED2C3F86831
+4EECBFAAD8B2A895F08DBA692A8176F9080045519CC6C46B52F0F31DF112AD79
+8E46B9899C5527A011AB63FA443ACE90F09434C295A5D9E6753AF2645407488E
+D29E7711546F87265C130B76B4632242E43962A5C886D4DB6316A2F3420FCAEA
+3055AB5A9E1325EA870CE87F34BB2B3110E4919E1AFEE67606B00B03DD6824F0
+20BA42968B81DAE198C88057438E36056D46C550E3E5E03A99BD4B07E66A2179
+BBC5B3FB06D5D72022C53A3F3A1B759472D5A50D7F7A1F4E31D3F7A30EDC1D45
+4B00AEB5DF680145A123CCA3BBD801CA64B2CBEEA99842720F8DCE432909AE78
+5AD3F29AC69D302C62256CC4D47AC92EE11D2A3E1C666CEA24876491BB167548
+9E3A990252DF8254CB5E7141F57B78FD1FEB38BE135815C6FC86EF81B5994711
+E43083C3234C55DAD97CCCE4FF3F55C5A6C22ADD2C549513A465CFA3D8A9AEB6
+331374DC05A4F496BE33F9263172FB6FE1CCD19EE9515C5155ABECA9492DC743
+BE4142D63FB5E17D55C9FE642F07995502AECD9D555603D15B5BE420A65A6E98
+4F341BA13E44DBBC1DC8CF0D561198A2B40FAF35F7ED5FEB4429BF71F5C88637
+CB114F1377FD3227EDF592733EC68F4EFEAB14FE7C26DA7031075E04289FA6DC
+8A79F81E4E18CAE8380CC585E7DA3DCDA3FCB53929AA8D772D53FC6D821EBB14
+EB472017FB56CE9410FEEFF14EA69C188993922DAFEC805F4C8028537A9D6365
+AE1A6BEF37CE8E02B995C41382984802AD3D12AA9FAA36837F9F9F8F60D16B81
+474238F136F442CA9B14620F83E4046E41EB0FD02BD04DA7863DF26624B5489A
+B8BA35B0B3A8D128FA10E01DC9B622C26CC57CA79CCDEEB7E174698EFDCC0CBE
+879AE1434B3EC5AF48E6C2EC5652DEFE0ECD7415FA46BC0C80FCC57CC808B3DE
+CBE4CC7B62AD3B092487F7A23C38A2D9102DEBB1CF4C1EE7FEDE1E8BBCDF7F73
+54CAB1E591F9B3B3159D879A9492394B32F2CC43EE7EBA6E293AF12D7FC4ADF4
+DAF8F2F48A777E927A915DE1FD9125B52D406BACB0BEA149F6F6D79D92D06413
+5D68461A772D531F2E76D1947D2ED5BFFCD758E062B5435BFD180F7E3734D5DD
+ABD86A1C2BA643955A36C482BEBAC608F588C43E6EA7EA2AE01D0346D28F50CD
+BA8F9FD23674AB19A2B879E0DD19029EAC5D74D16B186CF4BE3382E74E361427
+536A00347E536701808C1D31A617D1F9269110B76A0D59C7B84D98C8FE308733
+C9497B807A77D244FEE03ED7FB5EB4D6ABB74A7129F23AF628BC01BEC6C43ED2
+D62F4E2133006FDB94D33CD31F9FFE57C8C9E31DC6D7A81A2C6ABF1D971EE222
+96A4D79F7232190EB796A43ECEB88F1C64A88A10C3AE8E98711EFDF984BF270B
+55C5B9082D54DA7D32B168CE573597DC5A453D76953DBDDDBC1798F8A645AEB3
+78B6B5BAF60C9AFA9D5F818740EDAA977EBEA0F68E531550E607E6FCB04F3E22
+BC9D6440E1E153C8D780213DAB08CF8CFEB03018942AF980642745D711C7DB1D
+BEFD825627798897ED8185D80234B6C087FBB602ADB1263C2A2A0F59AFCA7B09
+EA4ED3BCF936C2DAEA9C8DDAA90130C24AD1A1BA47711CC760FF72EB3F27C165
+CA1FDCF1250C6CA4A788AAEEE08902AB4EB03C6EDF281CA2F5B074C859DE3963
+27F7CFC53CC91C80F779ABB25F7A6601453DF5606B72EC562F615A92C1DCED58
+3911BE7784B6E8B17F8993E4D5693A327F9C289701F39ADCF583BB4EFDE1F835
+1A59BBC2E6B73CF422D877B0B423E4E8FD116F5C66A4BEB706A3D42E7EFBB5E5
+E73CD03D7A91719337CC8E13F9D8DA255185FBE3F4FB6DBE8EA90AF036A09BE3
+5047B59BC18C1C3658ACE003B6535E42043E4D7E6D79E0B48B3D0DCA36C046D1
+D5ACE0B6F91CB78BCBD144F3FAA3D9D711C9D11EC30B6CCDBF43CD490E9AC229
+9ED2CFAC4F53927040CC8FD26004450889A1167FA34247B7C283A46E4C0A8C20
+AB43314A34EF0BC02C5558746D35F2315624FB9D4A8ED13E3D1A8B80B872798E
+CCB9775F985E31E8228B03949B4E35DCF7A41C834E53CE3C163EEECE81A8278C
+FEA3A9E3264627D33738170C12F4EB23EF8F00811723FA4FE56A0EFE8ED5EBE4
+90455B690EAE1E8F1092C1AAC07FC418A6790C2DDA6DF739B9B586B68263EB63
+718EAD2B11037C5D26FF31FB2E56AB82773921B00EF07DECAEE2A8FD71AB232C
+86865012F1FCC80CBDC4B0E881819601CE2FC5AC36875F2FB5C088436BB11159
+813020F0433EDF6D96FD162F5E3241F88BA7025F2B010208DD1DF737FFF1185B
+812864C3049CE325E06610404C8DE9322187DAA7FD90FFDF2DF3C86D94E8E792
+377C1C1F10FDC78E1FDEAF718A2857C4922FA300C8D3FAC136BA2957C675FBDD
+21E3A9E29C797142BA6D30FABB0D5E97AABB49D113A55C4838B253AB8D7443E7
+15596B3BDF01C88C17135A74AF78551CEB6B0041BD17ECAF89321E6948E1C531
+B227A1F071FC3558501BFFC842A4F8B80C14D9213E0633485A66F899BCB473D7
+3C72329610575B6279C781714761468C785E426DC9393564979B1D6A6D55AE9B
+4954010208883EC964F35E8363129682AAFA2D40E1ED08A4A1DF27F3DB5474E2
+92B917B45D9473AC94EE40662DF06AC9D004541B6F88DF5AA4A36756620CBE83
+1254ED1C3C9CA39B09E0D4148DA552B00FC60FF68E7159F556998EB8A66C8EC3
+3B7842ACEE888BCBD1FA183BAB95B06B245ACEA49F8CC51A2EB01053E99E9A87
+A5198C2FC26E270961FFF61A093A084594E6C0298CF96B251C5F8395ACDA26FC
+461E6DB774F6220F8FA04C68519E19CF69EFA73E9A1BDFFE833B228DC19571BA
+34B7AC21EB2BF8B1876BD11E128F002AC9AD6A9785CBBFE2D5FBAC307BE7CE5B
+DDA7C12820028FBDBEF1343638CE166E43B95E6518A83828AA3C3628779FB2E4
+CE32DED584715FD18C95D38FA85772DC8650EFC42F980A1ADC012ACD93B7E1E5
+FA6453179ADC6F17C94FEA1F4CC2EF6A2A975C687ED81DEB7111F0897742B373
+30720766409C534C5E0A42D7221337FF3C4C59BBD239518F3976DC55FDBB8C1C
+8DB9CB4B05B1D9AFBAF0FA1D82B1564AD7FC92B6CB3582F7DA309403EB78916B
+BFDC6F918E26A39755E5AD6394D985C92F7927FB1287FAFF2F60248236F918DC
+2E8557C6805B01090A037E8D5C529E2D70976A9CBF3785F4BAFAF9923DB40756
+7B6CE8EE83559893E3930790E5917EC3421FEB042C0CBF6CE74F16C44FA08025
+82EDA0833C0486CDA66ACB450094BB65F54C83829B47DAAAC9E4CF115FC275C8
+6BE583008180F2E2C9B003712ECE32333199BBF9772A471EADE59355FF264DD7
+ADFD42FECCD00892FB545DFE555AAA4B273B82BD2740CB8C9ACD144DEEA94188
+D1AFEDFA1FC63557F9E527C00AE7D14762FEC2814487CB60E406F8D4A47365B1
+F7B0E0A56CEF011CC11345674611EBFB5A7C587C34F786498FEE4F0F999AF42F
+D955CF2ECC5B64BB1C100310DE5B6C7D106A80FA4ACE0184A6E18FAC544EEDCF
+307334E1C2A0CB6E488B21DA3BDDC5B593D5ABD6006D1E2BB56336EA88D56DAA
+62DAFDDC379B06EF80E9F3661C6B7AA6787ADD06155F3DBCABAB6BA3A46C9047
+5D295774447BC007D5423B9840E2ABACB5B811B30ABFF547A8A6E2C18A92DEF5
+D30890D49388E80E6EC7626FE3236AABBF64B21E5525FFB7C802511129EBFAD3
+D1E19814500A465DA92054F93FF77864698288510AB599237D0DBE1EECF81C46
+F706515DF10A1D0FB06939473BC72429A42CE6E15BA2C97720756D80DDDC171E
+7E8202D385C2E5B4A5A011933CE920E98A09527DDBF49FB4DAF2E736B1E42F57
+354C91CAACB68BEE8FDD10F4DECF25ABA4EFFC4588DFDB9E98640737C015EA04
+A33D5AAAF9AC4A7D288BC9D4A8AAB9B852516E215DF7614B10BEF003EE1D0572
+E4654DBA4D71959D403B936339D41C381FC1A206BFA6505DF3082D9FF767EF67
+437E8C2A14A8B6F0FB98C80DCC42A30C57C8AC3FE83570A1B4AB404374B85F45
+A1056E389A7148CAF714CF6DC26A04E3DE8E2E7FD26F6CDE3E836AE65E593A9D
+3FA7A24A32E3E99A152009C8713FF8960FC93A2E49B8F442B81A90F98B99E140
+5F0E0253DE8ACE69F1248040510DEAEE069307FBD02B821D1DAEADE6C41111E8
+37A80AB702B8D79977DD73429695C13DF81ED3B562FF4C168AE03ECD24909A41
+22C579987CBB22700D1D34BB16E5D0B4BEDB4660D34EF5CF0A4FE507198EE14D
+9FAF7C97CF769EA9159E1D8210B063141913DD402BAFD515CD746A7CBC061A74
+CD6D6DF78AA722FF543C5379A1AF5102B75C06F73E075BD8531353892E1733D5
+8143315C0C780BBB21D6954119C0AB1D4C89EA67C0AFDD4607AF07D509F481A9
+9045776F08003CB429316307E66E1F9490E8547FE0336BDD8B070290558E0DCE
+DB08FCF371A8A9FE905E9C3BA4CBD4F12BB2F512838D395BBCAB1488C58122C0
+CD6D3634C0F6E193E2F2E8C632BB9185B20D94503E02244938D4400F0DD8FB81
+3AB0CBCF32E462A223F9680A14AC8876917ADEDCC9B181D584AA307CFF3B66B6
+F59FC840A9E8D1BE101AA1DE41934C22A1017A8AF69D257433C2D2C5A0474F9D
+362A669B4044B3990BF83E8906C5B7E2B45D688CF12CC1FF38F2EA47743676CB
+55FCD3C6261C6F5AF002869128882E39E089A6FA108195A8B86CB07913FFFA6F
+6D8F8D5C9E897D63C174825286953B9DCB09B8475D0675E09C1D26286107E89C
+C75F92D14002B1289A5E11F059F28FA27DF23FF395EEDFD5F22374FF67F0B60E
+81D249898A228A6A89141B23918E977BA79C5F5E6CE84FD35F51B136D81428E4
+E4D205612F6DEEC1CE6AE571B30A33DE004A8F096656A3BFAF8BAE8A2C73AA53
+D7984D6777540082F3674304D2C3F17775BDF86A27563CC2BF95F190DB3E28E9
+FBD0716C0F1B0D56A96E2E870882F03A3E160621FB469355859954858C9CC2AB
+06EA8F87EA163B9ABC176D704D3C17A37508864381659070B071B80C79D6D60C
+7858A32F5DE87B1F818E78048CE81E229FD7BD91286ECD773147F94E7A184450
+D1060F0FBC5A8DB06BB4009B3F5F50EFEECEF8FE970E3FBFEB5ADEDE9EAC6A49
+AECCEB5378A9CE274BC7F25D03CF477C2054D313FD988A4D913D20ED3981CE47
+8674501E487FEFE5DD91CB0E5ED24BE1D2D45C88DBE1378B11F6B7076FE56BF4
+8E8925E65FBF23330B9C4A943CD96EEC06A6073AED304CDF520CD2AC1CFFAC7A
+6B8D8FFB7327834C9DADF578F250A51BE64D27A2B65A16DD0204635560B47075
+3A054F7159EE483CA06345D3D55EFACD47AD32A9D7D7404ED0CB742A3AB8C47C
+2C5CC71EA3E1405D6E114DD53D85C2350D46A8E4BDFD1667C65A8152D9F3331D
+6235F40AE36EDB507325E21496725F3351C239207C0C4BBAEE2DC7D2797B8818
+BEBAFCA4FEDBBBBBF3FDB633A0C21A8BBA856D4A3119394FB00AD092E314558B
+99CD5B138D4A42BB7B621DFCC2A2E2AD262479E878D8F26195A643BA0D13F9C9
+FCF3B6BE5774DE6F4564FB82BA3B2B9BA29A5F406F1A135D46DB10C80CA11E1C
+39C9A74A18D8EEE86C85556F8B9203E00DE0B1A164134E48FCE7F37AAB98A79B
+EAD809EA81192ADD3D3C6B35E521AC99E190262E5454C7170B081CB8AE338D09
+D489BB694D228CE9C05DA95297BF106A3B71A99A5F199F122971F5C4B0B9C53A
+4344FD111B92AF456697E0B85142B71FA56802C392C886A408558A297EC3C717
+FB803CA1002361034D40420699FFE3C149800137EBA3AD99AAAD74B471038675
+8B073F692D278E0A088D3F51360C2C79A83FCDABE9963A4D636631310E7C6D35
+EF02828CD45CEBF9892C2761D934E07AF32BE74852C13FE63BD3DFF3619CEFA1
+25F5FAC01306FD99A573F0F5F29116967FFA22C9236EE8EB052488C4CC204855
+EEDB80B30838AEF66DD960389684231FAAB83750575E4C9BAE860D9B0F838927
+791AE22921BAF254FE561771B7A9164362D6BD462A82763F6D19737ADA1C2B92
+BD72443D7521795F9D3702F83B04BCF992667CA255A3AA539CB71F25F2D0ED57
+9E0B180D1C199211FBC17EE282E7CA9E078593E6340BA651AB949482A0760790
+E4C3F1446653CFF964B9A3142FF4FBE8C75CFBAEFFEEE1810D38033CBDA2FE9F
+B42BBD97740EF0C118C7954FBE81FDDDC74608D036A3BBB75EEED4E1A4A56381
+0F57C993C4651E4753A27684D170EBC495D09202AC0CDC5F10267EF26EF4E7D0
+908F4524C91AD27F43737253BF0617559F2EB99EB26643D8C28B61F8968CEE7A
+A79A818887ED9BC3AECE4A35AB15752A368D09594F93B7A741282DB5C6E42144
+EAD79AADE23733A43500563C3AD34E0421D1E3B4642EC1D70F0054E3DB6CC218
+FF930B11B1CCC3E4C90BC523D4635161C89CD9FF8F2C4F6E4127ABF479914610
+4D95589775902AE3993E1CE3D4868A1055BFF961CCB244AE25C76C4CE556B8AF
+98129765EA10B35FFF3D24DE1CA68BA55E133084CD2562832630E302C3823EB2
+5D7293D0C760EC1788BA6BC9ADB7AF6DA83C951E0A23AD98EFAD64AD387F7764
+21320EAA8DD04EFC4C2BC011185DAC3DC1FEF1461F3F9ED515E2240433D855E2
+0229E1D5269092D0FF790539D2946A608E82E1FCA5E3A1254B27AA134C300FFE
+C7C724824AE8B8436577129608078274BB69FB6A026D0CA48B97314F596EB375
+390574158057D3E1C3EA4AC61BEC73F81C706A6C7A9B42EEACD6A4B5C4E69FD2
+C68AB11CF02CE3D9B7148BAEC69F92FD7DAF6C9D772BE60AD4579BCE18396E4B
+60EED65E6E2E62B283F135675C188F58C831B3A7ADCACACD39871EF8905B3264
+567AEEE25FB31D64C6596D60597315F1AD8F74E5577E6C966F8F65B001850D1F
+39F0234F0478F6DB136F17F20262CC072B25202BCC8A67EECB03A2834136EE5E
+8FDF55397F3572922DF82D25376DA73083419420003E99A020198ED0ECA44A72
+DCFF31392F59E14720BA027A5A5E81B3C32BE7DBEE039CEA50AFD5CF9CB9080B
+3952949A3165C5AE1EF9D8C76E0C901DF5013469D55C8AFE1554A74D6C565533
+FD00D77FAA0311910C9C191ECBE1A0FE30A4FCDC3909D4F6322DE2DE90865099
+ABAA1A087DE9B4642DB649ECA28D40631EBA0B3902EA6D70F9260EA9DACBCE35
+8EFFA26B2E8BF4567406788443950D8A71339F595C83E28111FC90181AF60EC8
+9A7EDDE1989A2678B8C570F5D0BC178C4018626B9AC851604F03C98469EFDFCB
+BC34589B59973E918756A2C1BB7D1811BEAA17D193DEA92EB273D50AE5C0FC30
+661B330B083311E5D971D70DE46E2239532FAC9A6D8FD913E6DD03F42ED6148C
+4F04E6D136D41C24BD9B973109A9B63233E51176EE64D247DE1C5CBB43F568BC
+DBD5A6AEDFB68E5A0C8DC465E9949A96665AB78F41132F96F3680B5A9A79DC44
+828FBDA04368F277C40F629961EAA9F3B253276EE252478A9F409C2FB6447C65
+37AB9FC9A216970D7BF6912FAFC92BA0C000A58950291FB3E47F0DFD493EC7CC
+A99555CACEB7EC87F4250AB92E7136500138087A19053E9152B6F007B8D3DE8C
+96224FF8D464BD3289C08AD1E05B9D063375F38FD42CE97ADAC4E5B83B8A88D2
+B2634B95A0DC0AE6A407E62D153BFC434B42680FD0F62F5FCF0818182F182D1D
+6B9EBD47149F8506CF38BA61D8AE460A8B660F40DEFBC9243154E5683EA8D574
+8D48276FE5128F972D96E42D89E374F7D8C72E70F84F028263507BC96F6B2B92
+EF4B992CA46361BA3EDB888A6E5C57688198EF10A616F7DCCA55B4E1645FFBEA
+C2201D5503101C400B147CA23A805AA95FF059120C677C32ADC486DCA6E775EC
+23BB704624D3755E09505C395CC3AB83D68F10E2D6E1497BC179F3CA82A3DFC2
+38275D10D3253264BA9C32DA47C0088660037C7A789C1DAF75D0476BA9ED5B62
+CD30BA0E268DF3537F8298BDDCA16B1C970C2863B21CD839FF6B713438447A4C
+C58C1F0ECE39E126AAC2353E31B6FB808253501CF26AA3AC48433D4CE5A946BF
+10347C814A195929213655345791FAEB7986B1DD4F2B0C9E7116B11A4F1157CB
+933B48B488B7DFE700423AD4FAA7E26F003B87B6255BB607A3A639830D68D663
+A3350CDD992B528E3D2176DAF79AC03F6455B1BD626ED15299042B46F03BB46B
+992109329C6F67F1CD92A620FB4D806558D6CFDD75DE4F7D6C558CD5325302BF
+ABBF40001F90CC940511F63F32F112EB958944E37A603642C0CDFC7941D9EC65
+F1F5B2805EC17A6662FABEAC3F1A7CE8A4958D64FCD57759F5CA294236B5834B
+0071972DBCFAE0D89A1BA76FA1EEF2C8ACB12E45C8D8939B3EF1DA3970ECD2A3
+30AE415757A89E44CED997FFF9F6378FDB532ADAFB25872A690137609D91405F
+4FDA7B432D432325F1467A7C85363A9E2825F86D5B9F9523E53FC5B58D82CB28
+90D43D172B2CBABDA71E5B83928A6271468C197108584BE45647AF5C9BD930E4
+18E321AE20B3D28980B1CA53F8B2696043BCC4C925F218B0AFF8E8C2BC1B85A9
+134BD28FC51E5F4E803761720601C5D9D87921116C342D832BB14EFA08032E5D
+7C0C4F14F118883DBB1CA0313B6658E3BB5A7ABBA4970CAB64E66515031BEEA7
+F0311CD7DF8CCADCB38103DBB1D60CE59FEF567B2755D0A65100C8F8EA622025
+4AFEC5D179796C4F87808A76B3F420A228544CC12427AE7A5E2FB6CD76D4668D
+BD5A22FF8161EF3FB20EE9FE64EFC4D1E466DEF81D20A395B020BDB7358E80D0
+6CCBBB8725B9AB973B060770E4CB902F429D75295D1E5ADA0BDC01D0DA7A4ED2
+A21346CC735F3E6662B87BCDED41C39EB2174C5ABD9C89A4A6554B3523E08BAD
+F208FFE1095E6641C548DC0B7116851695AE8813E691347526DA61EC59DB43E1
+03BD503968825F7EA207E22EA04656780C15E1E9D0A00CF8CEEC4D3FD48A4E93
+7E82A2D0F952F5ED616618739ADDA48480DA4665526260E4269F135C89C2F28C
+28B435A1A40C924B79934D6CC536A58D2F102CB46E4C3F6F5390008A7C7B5E28
+4044E385A5D6FBE641B6FB074C4E15DB9D25152E503EB7DB52F45913FBD962C4
+550310BC3592CF1C56A7E19A73261219812CA9A818856901E9F0FC46FA53FD67
+20A7AF35375DC845C8A9BC82F46C061F46233CE3F963C6AC49CCE0936A1813CC
+F7904CBE756A07106AC3D9B58C28EB405FE50A12710C7FA7B4F6900E163125DC
+43672E2C565C6959C412F7CC333F49E0FF5B1AE666E0770255C43E1779A67D7A
+BD794057140D8D1478B7B3C43C84C2C2E56DCA12A1A536F80B16BF9C5244FFB6
+906F2729E0D6C3A6AE9A837CF39F81668CE7B299F4EC9825892A961935E4C81D
+7A9FE5D9431283C53770E41DB77A70500A9B21D63B2F073D75D8E11579FF7C63
+3D1BD1D11EA3C49A594D1D83A733ADB8D887AABCB81C32E3913FC4B2DD1DFF11
+10C193CD5D5D5FDC8080F9B99C9B29A86ACFD94EAC9E052790D6A46E5A5E946F
+6AB9541056CC23323C09CBA556F1B0F28BA2C30E039B3552DDBAC17B9311BF1F
+648D3527E8650B3FC89CF81256E9A4A9054D9F1A9839BF7E0B875D25EAC8AFA8
+2B5663DAD7CC7DED3206BF5957291DF837535DB23BA63F9F7ACA7141E1490A68
+327E35FB7888C160C2D47BC4A7CD84194FF52646DF43AC83A51489481CBA4D20
+1E5094E7AC3EE66A5828BF1D87A530D7786577F164AC3D5C0D624FC6CF1DDFFF
+C2
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMSL10
+%!PS-AdobeFont-1.1: CMSL10 1.0
+%%CreationDate: 1991 Aug 20 16:40:20
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.0) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMSL10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle -9.46 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMSL10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+readonly def
+/FontBBox{-62 -250 1123 750}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE
+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B
+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470
+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B
+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE
+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958
+9429B9D40924DC059325D9D4CC0344F3F997A99E6CC0676735EBCD685AAC9142
+08DAFEC78BB41AFC2F1C219910BDF41D6279284EF600B69776CA15BC8A34347C
+30783C52AFA60FBE3E353E2AE354CF87B558776A22C776C7A0B5AB5CE1F941EF
+C2D9CAC37294BF407A671F10E4743BF842143F4F7DFEE643BA3BBD8BB9E3F24A
+BCCF7F0ADF8BA500620C81033EAE8C4EF2C1DEF13AC575F1B3BBB66F093D3B78
+5412B82B67FFA087AF57182B2230F9F2137180CA58A7D9B2C822FF04BE6CD01D
+43B2CA7058C7B953F6D9B5D6E91ECBAA5CDE1159B0E59C83DBAD96D6C8C8BAB1
+374EF652D10C0F3EE7104472C98DD3572AAF2D45A70BF7061447E21EE3C3BF23
+DF39C2D1B35B42CD5297BEBE6BC94F7C9DC6E61EC67E4F677256FED9064BD3E4
+B51A71B1D27CA4E5AA9E1D8080E6DAB5310711EEF87C40859FA935B19524AE83
+63B163FA8397BDFF443227FEDF7DB27DC35D89FB1C5E435DA0619A5C88AFC73B
+89A2DF5E767C5B536BC7167A840A0C32BD57A14DE69A7D0D819AC36FF32F908A
+5070F32983BB007437E3500799DF5E0AD3710A4C0000F0098D5BE99F2EB9C1C2
+C444FD9552D0DCA098A94B3BF176F511CEE13DB7EFFAED7C47B5ADCF8D4700F5
+7A5FD1B49560969BF5C44F3749370663A04776F749DDD7B50674D93254426C4B
+EFE264BEE7810EC93784B7C01A7F29EFD92547E13A2C7851A2E709FBD5B87850
+4A44F08F56A542DBE072D2FBC58D9E6468E1AB858DC35240E30D31C7AC13D6C5
+7D2BB634BEE96FA0E10F842B11A789F72A333DD6DDCB1BC23227EBC406E50B40
+30AF0C48E6359AB0C46898CDAF1118E46BFF8B00F54EACBC2AC262AB898C42B9
+2E080C10DE923C18AD2A2BE7ABFE6A00500618FACABBD844A515F5D7C7F7213D
+7084E7361377127944EB80BD687ACC3F3400538570CFA3A299054F000E0390FF
+5478FADAE4484DB8477D6E5E843DA9465F52C8CB88994A2DCD7BACB89D10EE84
+516D7ABC25A54AC996D6EBDCA47306CE267AF8AD5BB041EEB9F4B2CE4EAACFD1
+5D1DB53C1F07287450201D43E3AD980A644F39FB1FCDCE21711FD48169A9BA08
+EC2A65050703540945FEFDD28556DDA2FC55F7D7CAE89F4D176FBCB9A08A7BB0
+9F6F402A5087641EC7DB75D2CBCACADA9A373AC28AA030584C930A4F787C0D6A
+2E1F7B837C949DDCF59E188349BEE6721335A3AA15FD72464171B978C66C24BA
+5F94014AD374ACC4DB2D6C93D3C8FE5091397FBE134513AE4AC018EF044AD529
+02E2336906FE185C146C54EDCB967A7619E4403F9CE78491DE897A99715E0724
+028CB94B23C8141063150EE57F90A6BE0994D689C8545D763A8C60BF8A14AB1A
+74FFD3FE096003CFD3A7C4BB8AF842BEBCF18CB9A22A575383956D85181EAB6E
+C2D44AAB62708F00DEDF1488344F09D1D08B3EDB11D617A161A473A7570E15D5
+600868BFFFE8400320EF767806653ED6857CD72B6F038133C56AD7CD47A7B38C
+9B2D909F4EAF9958CA3CDE2A6227254D968E72E24D3005E97C89927193F648D2
+D2FE80F2845860B7C3B3F23570A2C1C5BD6348B905969E3322E72510696FCFF2
+901F55946BB66CFD2472A24C3093964C546ECFDAD7FD28B24EFA1ACA58EC7BBF
+470572D51E602B8AF8F42F8043D9A39D7598B61CFB7EC1E09E1FDE59A3AF2EE0
+6E402EC1335C147FC7050081CB486676A355508563FCF063646D7AE6224E0C0F
+397CDB78934CA760E52E113AEB044F20AF17AC32AA85C319A58541BB43313032
+7374EFFD2DB344A77995A00ECB28192C3D65124F40A37E8CB3F6660204FBF2AB
+CD193C8A1F199F1E92196742CA88926F6CEB7F72BEA0182365AAAE458A163A41
+3A9F6E8EC5AB9F8A73BBB46591F87371178741A97AE3B39EBD8280491FDF2584
+1F412CC3BCC22F2F7892A194E548D4B5712F7AC3CA4C5D43088FAFF53ECA3892
+65C6AD135E9D3B75B7606E259DEEA083CB2E9C3822B2B02C4A42A965DA50C3BD
+7355FB5738E25881777111280AE04BC1273698F7BE40E33151055C8DB4E2F38D
+F6A6BA5DF17D13494B2739328FE2544C893A43759C9D615C41E85B423DAA600B
+4DEBFAF52824B3D296E1F47B666E2326FBE1CE1802252939F6EF819BE3A9338A
+EF3DCC2B84E3DAF00E7C0D45E44840F8793BABB055C561E0928F7AA01B5955CE
+E3D94A281F2D47B024D2DDFD1BE0D39263D097FF18662A63EEA49594BCB4F66E
+0AD12249D6FBD2F0B4B51411884C235A64AE1E698CDFEED19765749F1FC5C9E7
+BFCDBCDD7F23D394EE73F2B73C65F0EE1C1FBB4000D63A2D1947CD869575A429
+65A8B30EB7019F74B2B2048898B27B0650E2D291C8D3337EE09BEE0A8421E2DF
+0D986E66F97EFCCA660606F0B0A7B18339FC44C75134D8630C74FD296232B686
+47F3EFC94CBEE564EFA1CE4BD13947B32AE6C18C198FF5E3250F0BCE7A292004
+6DF7BD82592128AF3EB9DA27AFEF27878C75AAC551A9DD748DB7F58160C33C51
+3B28D39C1783DAB4696FD05D00D9A676083EA828D833649055CCBC47D14234AD
+F2CE3C0A887655FC28EEACA2EA3258DD0237E1693F9E6B59815639757EF4D63E
+837AD18BDD32B8E75D6AA862A057AEEB7201F5FED012C2C1FB3D9CEC057D3E23
+5723187BF8E37A6C8E7C0A4D19A78654D07C72725AABEB05958EC35617411FB0
+E66D2BBB10216B9AAAAC186CAD162E0F9D9953871816F1FD1A5423F43B2BFB5E
+1AAE96834566EF0297E2D69CD19D6232CA6D5B6E9E9B7855796817F0DDCBA391
+B523F461C746120683CA7F7D123BC715A1D1C4567EBCB3B27CC2F66CC022555C
+53AE7E06DE7B967D6F0708224EAF72EA3C4C349C6C1DBF4E3F9EEDD8D344FF26
+E0587F50407EF2F96B9FE5D4D1EED501BBABB525E43B9E34B1ABE4B4EE73C296
+CE2883BCDDADF33E48C8A879065E0079A820107AC5321F61F7A1BE6A9706EFB6
+598C0FA5F0C81C9E48CA22F86A9F437068711CB834D90CF79515BC7074C0E2BA
+30E0486B9EA0B3DA075D6FA4BA44ACE3031E166F9BC8D293683C1D3B94A2653F
+442958E6508B00EE81D879DD8EA003AA418A09893AD298C4708BC328A0A21A55
+62177339C36961B86AFC97EDB88206DA6712353887FC431D60344E483212AD4A
+DF9EA4632745674A51067E5F308343E5D1B5845FA6A623BF4ECD000B368BA9B5
+9400034817AF11E3E4A5F8D00368A93E5D6F1FDBC3CC4B0065208B275B9858BB
+40E57BF7C98A4E8158E84538E7541FD3FDFB11A015951187F875A0D8C9B7FDD1
+BB3FDB57F4C1D89B547369E1D52CF180C7C57F1F4ED0F93E98BDD54DE02B2064
+30D15CAC1DC1FB2ADA7D048AEFE4290B7F7E2AEBFB3C7D41EA1CFA52EA515C07
+520A359529A88CCBCA53FEB15FB263D01CF5DAC4096A00E5C6482841CC42AF26
+601A8101647FC35955587C768B7FBC7214098B01C53092C4869F65CD1E0E8616
+D6166662CCD0E2DBCED327A7C8A65F2BE7A6F2F5AF70C6722D3717C150F4BEA2
+C50CFD52C8473E80197084FD6220447C562981C6ACC17A833B6D88E3539D02EB
+84AB15E42E4DDDC5A8F8EC091BA226888EBE1985A465DADE44B283B7EC620986
+1D6C8B22D7D7B5FFD77185643146D49B6A5EC171969360AD890CBDA38F7DA67A
+AEB2ADDBA1EAACAF16A2C76080764DEC104C99359AC7B606197DEC3F91985097
+0B173D6DA02759B3406B1F05DB46A51DCA1B6A4D1BB709F5EE1C071553478ABF
+AD71F1A99A6A8E488B32D0575ACA020AA97D9E107FCB5C7BA9428CCD04EDBB48
+A1346168107718F3C98978CEC898A3494D96C724C355F01C04FD608CF1B9206E
+8507257264443BEECE2C8AD2986A5ED9CF5BC20F779856E29BC9D0E44CECAF16
+38483464B050DF21DB51C9AC852B60362F3FEE49F54152E794DA4BB628F1F1FC
+0C7700599029ACDAC782DB220CFC678E82C09E51694EE72E821ED4CE5B524F38
+05ADFD38982E5B91313757B55FF58873F8FF594E177301904C33BD54DBD196EC
+437060F04CEFD4648EC5D6CC04522885ED6F1887393B6E6836F3768C9207EA1D
+9CCA8B396BBF77D4FBFBCD401206B629AB96091B729FF137A152BBC0485E49C9
+A0BA737BAFD17F53F319C202A90CC8153EDE244AB5EE452687C496C2E77FAD68
+21DDA15C279714E0F6864882FB357599424BC7BE8695089F89C76F12818825AA
+8E1BCE2EEB1E038B02ACDDDE39C803DF4C8C0D38228F852A1DCDCA97912C59B6
+6C3CC7E533CCC630DA6920C04217E141E2F32AFEFC294A58AB3C95B326EF98EB
+56E3F430BC78AF90D61BD5E810C9887877E93DC4D95DB2DC1D2C3C07D9BEF1CF
+EE6FE5786CA88765C0899133AED7429395326A22D822027A4BC0475FE2F74EB8
+BDF61C69C950CB72F45A45F95920E2412B8D776C6E8BD6338D3AFBA07793F4D6
+7AD4CEDA52B8CA8BB8CB29DB49F8D5A920D1E167242F26C7D51FEE79677FC4E7
+0E711ED65A8FF70517BB5283E057D8C8B1175934F9567C4C7BF479839C2CFC76
+D990522E64E93579625F51A8D85B5CA4E3DC5ADBFE802F0B835F664572A2AA40
+2EBC631BF40F7F53C12E1156048ECAE68DEE3BFAAECB70013B7DC4C2ACD5DDE7
+D64C094E0FAACAC86246C5B9D522F483189D359DD65337DDCC6C4438615A99DC
+1936E0C20D2109B3E7023F019BE2F006D12B5AA643C7B5443D73B7A3F28B5B7A
+D8B8417E5B747A27FCF19B5263D542D6F2E02918E0B7A3574050641104FE2711
+33E011619A91AC3D293D98EE25C2549C895FA14F749E76BD4E81F4FB055B8FD3
+F2F65DA710EBEEA9AFFA46EBD7193F90D3112397A2AFAFE84CCF9DE1EA2147D1
+907C47480FBECB6A6EE3BDE00C63187143E74F35C2027714B30FD5F09D80C412
+BB820C5A8A30F3F11D395480FB43C20ABCCA913E6EDAACF7338A68EC3277A344
+D571E1D2CA0675C197BFDE9B37EA3AE6A43DF326E0AFD91D9514A962E44617C9
+AF848839DFEE22086E4EE1077403E9916D32348D4810FD973B7EBC4086700F29
+2F62B0D59571A52A88E6E8A64193228349E288173F794312189F2BD2E1FDCC97
+6881C1921FAB253BADE378D303BF2277DF8BE6D1C7A56C36C6CF3D74C6520AA2
+37333C8C0F4A8F1BBDA2FE5920997235C8C8651519DE875BBEA6BA56C065AE5C
+6F8C1C6227971E3DA49BE96C70263FE2173A3363585096B304DA49E46BBF6E34
+715C7F41D56722C326CEA609CB72907D0732EBF080B538518CF0CB0635B0F97B
+625F051EEDE437AD14A05A84DAD051E3425871065E4A2615874C30C0149837D6
+B5A2893A49D062658008FAB040D27101F1571AC352ECD9672E2A30027E204EE9
+433676723D012E8CC81569EC240B50C4902C5D4B30259BA95B69E82D1B81597F
+CC48B22EC65F7237AF0B0A1595707489AC4452D40456E1247080B58A98419EE4
+4BC1937D64008ED2B1E7C13D7FD261BF3B63F65D7EBB05A00F057D78554AB6A0
+9AD437F65A25158A55155A9CBB0866DE98A2EDD5550590EEF0E1333DF5A974CF
+39E4A61FF9F8802F030DEBF5039F962133D952073494FDBDB161DE14A84C6B62
+C54A5C749AE60EBD07A0C29842706B74B75BD54D5092694B1325A58D5CDED356
+CC6C8F81133915F05995EE1885991D3B14CE0794804F3BF58D5CE83BAFA05D5E
+A005736C32E209E08555E88798A225113FAFB91F3946B290859B52D94C011F9A
+295A554C3793C20ED3E3A6B5BE57B533E8FD92A5DB0F67A048743EF6C1BABD9B
+FE787A1282E24B098F1276CDE25C6686E5455C8C84B19BEC816D58A5642E1660
+8DC4BF1D7EB903042F6B57687E6D9A25058DFFDD5A55D27B4E8E30ACA5C11A90
+CBE71DCD014E3ECBA954DE2EAE0E96BA275E6D5FBB2114BBA5D4AB02F9693545
+A2F3307783FC641D1767C8AC174B98876767E4ED9F6E22DEF90BF7BA35CE7173
+C7471745C7E3FFC15D15C135A87F38E96ADBDF35A36E86A8C30BA572A4A22FB0
+365A02B3EFFA2491C3A9CED6D76E9293AEC8724E46DA15312444FF8EEC21077A
+26E54E8CD9B077C81EFD5745973DC67C072BE37D4B9B7C6C3E6DE4E74C035022
+52ADA17568968E18CE102CC748D679219D070864B2A465D6F4A2A0A4A08887D2
+BDF4865CEE5BBAE5C764373A5B44EC9B399387F79B84F5A85A5DAF403F64CD29
+6497560F918AB1D65397363498FDE113D1C43085B70F3761D6CFF81C64343B55
+113754EA46D2CC06ABA93EE3D388AD8514579CCE2CDE11E14C9C1FAD283F57AC
+607BD42A8DBDFFBC679BC1B858A95F2A1F2BDF280E8A19C98EA5E5FFAD402AA3
+F03F1806AF305F072CE35F644BB0C095D38FECCAE226C00B63D26E367234E1C2
+12DD8D4D9CD3264A39749A76EAC7E03D389D6AE33B068B2D42A947C2CAA69295
+CFC49CF12D9898F5A54F12525B668555F97EDCFB8B0701A14DD5EADC49BB8531
+5D6D7A1A4C78C895154F4762BD3F34DA3A3836F1B52695A064530984FDBD32A1
+D064359695307BD42FF880489735008C405B63214F58EE970DA4F171BA941499
+EB22232F4EE7B4E3D6063CB4FD10DF9D6EABA14220B994E5BD8CF96E21F966B4
+9CD5A96EA1DF4430C46B043BDA6DB7A3C581A67AAA1773E8208E45F43DE3AE95
+8ECF8210DF6A0C3A69FDED35554CFAC2403BBF4BB808DE0DA9BC3EC57604F150
+17169E5A4BA101C020203EBC7CB27168348087687BA16096105BBCC82A0529EB
+6E39BEC21BB348A074A0F2532307ABE656A0051F1B87C2B762074F7EA6A2611C
+42244AC5AC971E43753FBCA6C025A5B9C03E573E0A9B42B43C2CD0E9FAE39E49
+62490710A8175427337E393F80DF3AC43BF179CB829DE6331AB86422FA498833
+D1C14F83E443DE738C7A9BAF36531D6FE7274FCF51A152B6447B15275AC70345
+A51815AEB0C014299B15E880D593BA8631D656F33A56B5FC851AFCE74EB8640C
+0094ED50A6931FADB9C20C453690BA4D6EC88ED660AF05316DF2186757B7CDC6
+FF37755B746DC9FE45100117F1B8093F96254973D54B9DC21AC8B430DB9A6A5D
+6CD60B3C822958C48EAD747F3C8AB10F47B29382BECC04D96B24B343CE86E7BB
+C0926A6D6DED8F9F5E9B05F1CDFD07501315DBF2522EDB572B5724413A8051F5
+D84DE87C7D8C505256194D083FA9887166547D96576ADCB15D9A6A1A5886CBA0
+46372FCB670C6E95E2EA81DFB3511134C0CEC3C9280944958B7FA2B00D6A87C0
+D28A8C30A8F6D5FD6C61B152DA5D43F5525FAD3A004055212BBB225AB5601B65
+D684E9B4CB5DB6493BDF74B1F75B12F33ECDD0AD8103F865A36F2309ADDD8BE6
+229CDB25B3A922B591322257AB8A5BD62312758C5185D34B109317A6893CCC3F
+BC668B9E0EDB1885D9EF6A6F1077CC9B025C66F4E20C0BD2326F82BC6097A63E
+E332543684D7433A7FA613E82CFBE7D081B484E71B5A938FEE191AC8C9C79A2A
+929E58EAA236E4FCAF87EF1A1DDE828A84D5D43C25F0CCCF3977C79DCDFEC056
+EFB75D03777F00F5AE7833F0EB91BBC1B6EE60B9CB8D6E774F72745D21FDC5D9
+472332B20CE5A9887550310CBA5DD35532E4E7A5C810041165CA595B2285572B
+29AAAAF676D81B1A028B7D9503BD9EB46B4C2FDF24CE4FD5926E4FE2E53A0D75
+167FBF24100706E09CDA5B76C4650F9CF9A44E95560CFDF63672DEDCA589D737
+F4E48F28CB42582D4ADB35494B41A4D37CD59986AE9298E1B191538253677D54
+E0DE24266E195A6EDD88B9A5FF4C6A64B20194E86C551953458637878E41B944
+8299B195E848D4A51EF3AAB030AC0048C780A12440CBFAF8531859586C97E826
+9FFAF28E8BCF0AA7188CD31FA9F1A4C4D96B01C8F1E64895F16CA9EEDE3B1E05
+963CC6B45F0E5C5C5C62BFE4522E30CA010DD477C61FA989F6D0F1D3A17ACC9F
+5A43F41A6015A9F942DBF8FDDDCD7C27B4FAC601C0415982E6FE6CEFA3F7C1E5
+9A182EB2235D4136F11D6F408BADA58654A928B58A24145E1F4B0B996D93635E
+AFCDA40907CC13D1C1199ABB4F08E015C8B204A3A6EBCA8EA9A2A7D3ABFB00B9
+BBD42CCAB8753DB0CC5968081A27F638831E8A78EE7CD3FB1D74C9355517A1D9
+3AE0BD6ED674F581B398F1ADAF2AC848413BD4AB04B606C7D45C55B736E3F7F0
+17E77DE215FAD7AEFC628062E0E5513C9F7E629CFAB25E14B4E04C0E96689AA6
+8F6034FDE0E206CBAA6ED4D0799A99B41105A5C136CE05CBE2700B7B0283D376
+782D3518644FE0AAD2993CCA0CA08A70A6D42ABA5EEB4B0F8BC6F729608BAB40
+9D046BE1BDA44A9FAE8D534C365D0B8E6F39092461029CE88B843E33F93DC572
+B49C727AF0127907FCAA339808291BDD960A1D65F83A8AB8137D48BE5D0C7496
+439E9952B2667D999916C770FF0F8833FF9FEFFA76FDBD8DBFBD8673D95CA735
+28452636631B8717E5081A8B41A192836A9BE01B60D545EEAC2FFB961D0EB73E
+7E0C5230E9AE38CF6754B6C6C9BCA4B819FA08CC989430B849FFA13260691523
+A03EB48C15A50A3A044C29BE621C4F8C124B53B09425AB326CFCB449759EA353
+B569DC0D6D1D7DC29C8B23A31F35A94CC47148033635C787E406037B1C618E31
+E3B43A9402E60720457F60BB4D5A31FFE1777644B053CD2BAF0D55DEA14434B2
+F230DD01934F90C7D3A20363058D96056ADE53FF93A84B6DCAD0CA78132BD6CB
+8C3C2C02F569DE5FD19ECE80891582B445B9D2EBD93A8402948A2BCB5940C75A
+9B7E35BA0A2F8D51F41D89D1D221887023521F707DBBFC51D3935137B07EBDB7
+FFFD435DA22425413DF92F516AFEB3F40BDE4BF90556AEAA944DBC5D8F17BAEA
+67DD983C2ADD85D37289932A6462B632725EA66E3A335AEFDC40C5533EEA296F
+CCA86531DB67AC517090633AB4DD8CBD7D8AA219FB1D58BE0B12E85D10E618CD
+0FC6A362B042C6B9FCABAB9EFDCE81702A0F8AD3C64E4ADE4DF40E88197752C7
+C89B8481FA463C3845A4226DC7E7F613197D689A6956906D487195C167EEDDA1
+F4761DED3428B835AFC14E6683D7B4AB3CD54E3EF8D0CD312D29AABE4A31DA9A
+1E488867F8B981E11207ECD854E55DB368A9A5BC9AB5FDCAAB67C9F0B5C27EC9
+EE29FBA4B8E195B8CD9D53D9B24E1830494B6085540F5467341D23C581FEB427
+52AF14F88D590F71F3A43407521FEB0F6F6D3885BDF79C8EE7414346853CECE8
+1AB8B35728A13632371CF9456A68C760155FFCD23D2029770AFE5DFECABE6571
+15FB24827CED98A2E39C9F3D3C6BC168191F0A32E1D4A3A6EFEFE5331555CE4B
+AEF8502F2D20F1B561AEF8DDF61FE9A9C0DE17E1847B8C18342682BCEA1481B4
+2E03967B9393ED8F64262CE87F5732B2A8F5C8BBA53068CE14AC143A41AFE6FF
+7D1BBD08CF1C89C3F9DA27436745AC6117B9C68A3410C1C0143A97F62FF7EE55
+4D23E7ED7EE9C31EC1913BC091E45E29E2EE681FDE83C55EBEA07BA7BE6A8883
+80E50B0820C2537995E2AFA62782DE1E30EA87A569AB931838BD7024D297A690
+106179136110A244859F1D5ABC6DBA94EC87C9DB9DE843AD2F05840D4F90E9F1
+91C41D5FD756E25FAD3492C463315A556A63D97F4CEE0971B8B9D1BB30A58665
+FD37B4D59A10F5365E3455A3DD3A732E5734279B6FDA63FE903CD70BC04D1358
+2AC8F9DBBAEEE92A8A933410493F9F186EC52F3304D50037C96A419A281541B2
+ACC0E5A9BAC9B7FAA8E0BD99B5251259A1A6EC8D3BA47974B9613948516857BD
+A3B84DF70AFEB122B14982FB1C3E88F6EC2284DB4B4C943A2854FF29B4AF65E6
+974332441DD5C83163CCC2F174AC761B7C702AB6C9754836E8BC1EF7B6A5E7FF
+9A86F51EA594E2C7CB13DABD156B477FFEE840EEA55129C3994A424F69AF08B3
+97D1663E33175B1159446831411E2F8C8CCD531FC46BDB0C1B590A396A3780F2
+FC055C5C752BC9DD17B1A4962727D4D255E5D6080661263244E38E1BE17043CF
+4DB4CCA19DA7CDDD94988886604746B49BC36C73E168FE7CC628C9F6376D3DCB
+B4DB779C0F29537FC2F22A5FF5DBDC8738D32973A64CDBDBD0FC8E956431E871
+8DD8E33DF06557E28B064CE7A7342FB658016BD92EE67A6E1F5389E977A95AC7
+29BA4581090B2E4D7D53B20F56FD9311D86A9CCD61D42CAAC4977674C8683193
+948DEB37FE15675B798F176632D7ECC56D9D48CFBD3EF0DCCB540BC072F887E1
+2BAF8767F80C248CA2843E9BD7D3ED9C693B6B2BF7769821A6E813518A810780
+EE9E13CC85358098797A1B19CE476831D3775D0DF7C7B90A8754E3D91FDA2873
+858030879318D96CBD2220402A008ED4040241138F4A7A0AB8E9356F6D53F819
+DDEF5FA13FB03DCC0C82CAE070E54A17C72B04A66EED7E6CF236C9CEA7E0BBC0
+29F6AC55678C3469F15189A585AE48156F620A2FA122B4F028E936CF5710591D
+17C0BB7B6BC53208849952DC5184245FA6CDDB9AE599CA076F3AB8CE856E5B0E
+9EEDE67AA13E8F5089C2130ED6A053979E0C62A104CACB2741089189F627099F
+42C3B82D792D7ED93CD0D63C87F0FC5FBB74CE9AD5DE2D81CCBF067BBBD2C323
+411F1845C287B87BCFC5CCD50DDFC6B906E8D89D4994C8188D1DC5A40B0AF52E
+5E8FF0F22280DDB503EEFED2236826F2EB9F5C3A23F343DD129A3D534D28548B
+F2B08FCD34D33AA861266F62EBA0AA48C85A0D4869805F235278E49D9BCDDDB6
+7C293B8BE5EABB67E64247AD01451912A522BA99F82A1C50087474F2C2020CED
+DED7584E3356566100B06A492BF76E6D0914D9A684ACF99AFDDF909DBCA11A87
+72FDDAB73425D666F55884D53D8E6DA6B8C1D6842B809A01BD806B648652949E
+A7D352FCC8BCFEBCDD860DC736CFE87B09D47267912558F15560328573F1E163
+
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMBX10
+%!PS-AdobeFont-1.1: CMBX10 1.00B
+%%CreationDate: 1992 Feb 19 19:54:06
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.00B) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMBX10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Bold) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMBX10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 12 /fi put
+dup 45 /hyphen put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 76 /L put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 87 /W put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+readonly def
+/FontBBox{-301 -250 1164 946}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5F00F963068B8B731A88D7740B0DDAED1B3F82
+7DB9DFB4372D3935C286E39EE7AC9FB6A9B5CE4D2FAE1BC0E55AE02BFC464378
+77B9F65C23E3BAB41EFAE344DDC9AB1B3CCBC0618290D83DC756F9D5BEFECB18
+2DB0E39997F264D408BD076F65A50E7E94C9C88D849AB2E92005CFA316ACCD91
+FF524AAD7262B10351C50EBAD08FB4CD55D2E369F6E836C82C591606E1E5C73F
+DE3FA3CAD272C67C6CBF43B66FE4B8677DAFEEA19288428D07FEB1F4001BAA68
+7AAD6DDBE432714E799CFA49D8A1A128F32E8B280524BC8041F1E64ECE4053C4
+9F0AEC699A75B827002E9F95826DB3F643338F858011008E338A899020962176
+CF66A62E3AEF046D91C88C87DEB03CE6CCDF4FB651990F0E86D17409F121773D
+6877DF0085DFB269A3C07AA6660419BD0F0EF3C53DA2318BA1860AB34E28BAC6
+E82DDB1C43E5203AC9DF9277098F2E42C0F7BD03C6D90B629DE97730245B8E8E
+8903B9225098079C55A37E4E59AE2A9E36B6349FA2C09BB1F5F4433E4EEFC75E
+3F9830EB085E7E6FBE2666AC5A398C2DF228062ACF9FCA5656390A15837C4A99
+EC3740D873CFEF2E248B44CA134693A782594DD0692B4DBF1F16C4CDECA692C4
+0E44FDBEF704101118BC53575BF22731E7F7717934AD715AC33B5D3679B784C9
+4046E6CD3C0AD80ED1F65626B14E33CFDA6EB2825DC444FA6209615BC08173FF
+1805BDFCCA4B11F50D6BD483FD8639F9E8D0245B463D65A0F12C26C8A8EE2910
+757696C3F13144D8EA5649816AAD61A949C3A723ABB585990593F20A35CD6B7E
+0FA0AD8551CEE41F61924DC36A464A10A1B14C33FAFB04862E30C66C1BC55665
+6D07D93B8C0D596E109EE2B1AAB479F7FAA35279ADB468A624BE26D527BFF5ED
+E067598E1B8B78188FA4BCFB0B51692D07B0BEBB930C6F0997B437E2C51B876B
+61A563A2673932C2045833FAA35DB22ADE12102335D5DC734AE3AC5EEE6658D7
+92EB62131E1DFBA441F53EFF9021D9D4C491F26BE8F54C61165CAD778CE8695C
+EEAF70E3B20C64D4C2B34A084B5770BAB2A974E898F62BFE90F132A37E2DCA4F
+43E13DB13C94DFA8ECE2B7374827AE168634FA007F8981ADA046CED3448BF453
+FCD9A4F194FA648F9FC0971734BB69CB73439CB0DD021D44A7C11BF295E81733
+4DFBA460FF3D654F9FB337E99E6D66FBA87A817EB9CA1536C84833870E3626DA
+55D48DE850D3E6F6B29DA0E7C9D681283586F208DB8D58042E3A7CE55BE84822
+C98237911453E479EAB65AFEBA3F61A763B40E74535BE56C9D8D06DDF9441741
+5C9D9D917439368736619717FAB4F06E2C329AE0BA411F3FD522D9C33AD8369B
+D7DCC9DF993778482F35F965973DE876FA19E109AA198A00658AB3F0D8E3DDD1
+08A573F2D525202AFC57E05D141E6C0BB811E1FE280EEA002B7A45BB363AD06C
+318D320D2C81AA5DCC842CEF66E7DF7670588CB39C9F42EE7763A3A17372432A
+173BDEF7ECCEA297CCDD76A835C36DCE9DB8F8CB66CC71B4920CF5BF055A5260
+5B41A5373BA6E4F63C85671D979EA5EC30D22163E6D206168A3827F465279870
+CA80E6632872F721BBCC622EE4214BF723551C846765495FA9921E11FE1A950A
+53150C3F5D8595958A47E0B16064CC3AFD65DA294FFD111153F4F233BC5468AE
+69585C16CFBFCA32C4B96C161F47B56661DF84FCD8ADD3EC086CFB6BB5179BC3
+A5469A1CFBC8620BC711F42D0D3139BCE4E38698D9C574450DB43B5A19FA6D54
+0368BA9F7A8DBF96DCD0B8968CD194264E6DD10A958846C278B8C2BAFE7AAF8B
+44C84C955F1A89A13E62A054BC76CABBBF6296DE00A79CD7C8C61C70F127618E
+9975B59A880685E126F57AD80F8F4D376E1B476BDFDAC868FB6AFAD9D694B561
+001623C4D9F55366D053B52F2B09EC08B81901AE0986C5350312E626006038AD
+AC15FE313FCEE1A2E61F8992AC00CA7BB7F997707EA377D37EA6FF35BFBC2866
+A572B31491F9B80445685DBA5E62F166E80589F768FC95BBC79158C23B2F1BD1
+25816F1486A64F76D99A638AC0DC101FDF390811B3C118C2D972B2E7587F6F24
+7F1DB2DD922D237A7D18FF08FD665355CFBBEE799D3BFF11CD94CFFDBA3E725E
+DCF4CDE4307E3B199D91893A365D04F43A5305BDD2538E28A0788E061F3A621A
+B4A04E5063B47F0109C1693A284FA43E8F1EA9B68145FF51C005D3FA40713BA8
+1879BFC3CAA881B9D885A0C1AA8BB9A8C848963020A5B15F862E7DCC78F25D7C
+56437215999EB78142C128C6CB1E6E75EBCBB1E4614E8516FEB1E68400C61326
+D9F9E8A41216901F77D9466455E2A0B45FF50B27B55A1E1DD4F243C92BA6B175
+8F7695CFA1E91CDD8651AEBA3D258FFABA6280BF2420A98FA7CECD552D152CFD
+A8CCC94C032087A28D68332769DD2CB4ECECB15717C245BA305CB616CC72644D
+C78326E77FA602364A7B1630CA0BD0282FA781E14282982C1AD13479B6178D28
+1CAA541FD3F4316F4FF81C53496DCDF5F86E0D7C870FFCD85B36C936B1E08D78
+CEF3823546BE4329B97EFA4E2880AF3361C0DD67F77C8BA6F1CE3822B7FBE567
+064ED0477949BDA06483F8DD04F891473C8FBF73A61F7C06B20FB8B5F0BF4B77
+1429190979A4BDB29D77E94D5FB486A93B8B61DBC84AE06B4E06CBDA3A942043
+9F9926F541DDE4E9B73606C3DE3E4E957C91D74BAA629641A6BA8E053FFA10E5
+581F14FAA575EEAFA39C6534A94D0B1BD7A8ADD7B219900B9F300BF1752C4236
+81CA46AEF5361701257648AB2ACC9825BD79FD6663507BED21CC7724BE327C32
+5223DCD4A92411BD7FEBC5C99BFD4C77DFE394FB6D190CBFF7C94837CF66EE0F
+0D98EF9BF9CC9B14365F33C78320085E763FC27DA1E52B0006A0019F56E35236
+C5D3C182F26D23353CBAB3DF0625BA335B5B965A15119F1240E2D757837B195F
+5B089B39BC8AE493CA98A6151FF1228EF46924021498A17AC49B68B8B555FAED
+73449B45A818BB4BBD8A0D5910790C9824F13F5A0D0C07634CBF077840537E38
+E7B5D57B328D192C48DFDF345B485B9ABF6664FB147256268155E04BEB5E2D3C
+B3635D6821066F8118281285E3DE0E31DCD1DD130171BDA0792ED9E4588D5A33
+E9703E3A82240D7CB225D971B91F4457AE9A119DCE5670CD46344C1E9367F1D1
+CF9FB36C5541128BEA31BD0E609170433D0092487F28845A5B234434B01BB2C0
+FA3F2E8562D927A5B25BE0DC8313029969C9AC313947C924800EC92FF63127F3
+0AC6801EC1B0FCB6C82CBF7370973B21C9C77CBDE9226278A4B5CC752FFECF16
+8CF30E7B81CE53C3933AC580D848F9CC7F3377E0BA5BD88905DAE82BFD42E1C1
+069C8AE5FEA017F4C8C9AED30585050FBDE9F530EFF051A780E5A7F7897B12BB
+E968204D5654BF09156BAFB7DF7ADEB7AE2C0B05416D085ACAB40333D10926F3
+F5734F57F0ABAE2ACFFDD09DB497EFC9E66BEBBEF18ECCD13B09650857925716
+B4ACDABA324721422EEC2DF66005CA076F3657A12537DD5AA5E456FFFD52633F
+12B352800E09339568D2F9BAC471B58E108C990AA8C481002C442932469EFA8D
+67FD87C9F4DD28C62EDE5C0D58EA1E0911FDF9ED05E032E3D138D01B63F27988
+471935C56A7C7E77DB9E6A3044FE2EF9F721486F229836C139FD92D82057EFD7
+E7FBD5DCF2F9889F31ABF09F119DB6C0A9C2D56FAE51962FA345E78D873BA145
+A1CD40DF061187115093C6DADAD21C1925A83BEBE4279DEA1B78A0183E68DB58
+70409542168F86094825DE53480D281324FF58158658D21B48104B83D6347488
+819B637A785A8D353B506DFC8D58F57ADABD4B70BE468558A73CFC5D0FCBD1D7
+ECD18F93FB4B5125C5DA18FE220B12CBD50A1ADEA8158B4C48E2DB42DC80537E
+4DA231CE0464C56CAB8F59FE60393C4C305F6E1724126F765B54652B93C96768
+15F572F786700305087B798177719B112B67BDF3EF0E708A48E8D6296BF3B937
+A9288AA57C8243C6D28DFA1B31C331FE72BECA3916FD0513E85709684D3C77C6
+4392980F0F2859D40903C3AB70270ACDCF7644032510BFDF0965B30E5FA47CA6
+61B6A7D3A467FFB5405A7FC00134B2D5570C74C1E27F5433FEDB15A29C7729C4
+AE8C7F7517718CD8BA705D76008CB471D250A77F7529AD67103FA172B2B482D6
+E6FBEB44DE62F956839E878A52588454DD72377A0CE7DF791C2EB04D559C0B4B
+5BC9CD13D4B0082F29D8C2EBC6678050F0C6982DE10D3295086ECFE64255679F
+EF0C90170EEE04D0DBC091DAD7472590E5D471239B1E9B8477B0EAF113B6DEE6
+54F55398F7DA7C64092F33FC1DBFADE12B23FE70BA4C9538DBF1C19F4B947603
+6D0B7049820B90804D19A22B8A9C3452CA601AE21204DB55787A53AAD6D42AD4
+9F2A2E849AB4B1F4FC726D0776520D3AF92AB14F3B76AD31E91D47E8FA5EF826
+642BB26EB6FE1BC93675AA40494148AD957B2077BBE240C1DC145C43F53C6DAA
+4C5EAB2C91D2D3C63956160CB99ABF21C74C7930D7C9207E4B515293DC8B4BC1
+42DD53FB3DB8F793BC0298044BB2D9F7F8588F267646F0C72181B900B8840743
+A87717DE9694EABF10976EA2FC141DF70BBDAA4E1AED08ABA4E2C386ED629E24
+AB9157BBC4CA7AC1B4016F927473F787DDE44BEAB16319C8694BA592A1426213
+4DFE7039D154E7A5A969FCC2799A7ACA0174CADD74EE4B85AC4D62E1965FB298
+EACF6FCC737604E71381B924D00BF62CABE5421C98211C3C01CA517D4A3984D0
+0F5A24306C30224967BCFF64516137BE52BA47B283A62816C84205A296DD2CA0
+9F39B6FD01BD2AFBD06F66A45645662F5FFA5A3E0C35E6627211181152CCD857
+B2037555F204FA5B7E321873BCF4D84B1FC7C2942EA9F943D199AB7C7B12692F
+77D30BF33B3F90905C1CF6AA6CF7FE2D7E7ACD6C296FF0AC39F9EC0335D1B1DF
+B812CE8A9D64B833E0DD307DDAF65E9A2B4E7E03E79229F4E183540846A3C337
+B00DD353ABF3538EE6AE68D4DD7BDD3DA51B5097331BD48AE31EB303B66689B8
+2794A8D350F0B588B45632725BB6E7B14D89336E71D744C2E3E3453BA5407BB8
+8E9898D3D4D24A3DA0962FAA7BB24A66379FFB6F0AA077E3B01F2612BDC8DEA3
+CE1BCB25ACC872A6C0A98576F9EA016F723A0AE79BCC936BEDF4C091BA9F4764
+4C7D026ECEE22AC2FAA631FE4EA642570CD3AA905DD810F08F7FC8A9C26F17CF
+95C05142A1ECE12979BBCD0F52C0E6CE766C904C0B0F37ADDD3D97154A2B3728
+F09C77809BF1CF46E09AFF024993E7C825A777815B420E3B8997B48E969DBDC7
+4127CF29407C0089ECB3D63F6FA89AAEB2E4AD2D8622A3E245C854AF13062EFA
+C52C7929CC42FF622C13B8C13631D09E9BCA05B113896E559DE7CACDD2655C67
+BD760BF29FA4C51BF674A0D5DCA5DA2EC73E6C6101149DF9FFCDC152E7142CA8
+49F9A6277FAB6B35F42A35DB82A564EA0C5989282966A92EF9CD1A37264207BA
+59EE7146905948A128002F70022748117950E2A706EA9851B337B3C54F6B948B
+B4E92AC726D48C214924C86F27AA8D054FE6C9C471B0D7140CE08319EFA54510
+6DD42EA378FD0FFFCE2458630632AD8130DFD8701080D5F73A0CBE281EE5C3BD
+81F49BCB11458164A061EFB788F7D2FBA00FC53E40A99CEBA0D4A6D1FA5D0FEE
+07F08CF70575185902C77FF048E67B00440115054959D952CCD88580C590EA35
+6A0EDB91E90F8E0AEE102C2A4AB460257090496809AB12276D3A262608F356B0
+45D393DD4DF0031335BC278C2992866FFBF0CCCA02BC37C82680888C95E51917
+368167ACAC86ED36FD3FB26B2D17E375089C699AEEDA5B0F68D87C8EB6BE46FE
+C4CB0F4FC636F6DFF435CFD510EAAFDD266D9BD57D33F71AE47584805E14979A
+3A374DC19A43E1065D5E4ED4C2FBCCA6C3BCE0EE791BC30630E08AB40452DBF4
+9D2A21B4B01F5F210F3BB42FF8C9F869115E7A0D78F9D2AF68C91F9BEA8DC210
+03870231F666E31899B1A24A0757EFDCD4E16C2E383D690D04D3D57E1F2CC85F
+D23AF5BE23B1D4AFFEE6F66C684B93916B91B64DD85D1231E3D60C8E2FBEEAE7
+81C58E0BE8A0016CE39EF705F76D628FB8C08013D25B925150B95F7D0B814D1A
+A25C71C654D4F1B5213E05CABDCAC794BA0A1B9251A123ED53C36AF2177EFDFC
+6AE748CFAA85A25946B2A72D599A076F5A515E3D741BD7119FC61C2C75C8589D
+CCD57D7A9B15E7279ED49EE50A9B5AFA22B902074B5D471A8ED71187982AECA7
+EA542C62EC41C509D2B13609A07CFB15FB2520D04D6EBC1BCA3B0DD51C1EDEF8
+CCFE5B0B5123AE854AA7BE938A8F8D809047DF93499938EABC1614C7714600F8
+862C14E0A4C1767686DFC884E39A1C63B17870FBB98FD39041539E12338EC4FA
+0BB682BFBFA5B748CDF535DEBA2828BA26BEC55B96868BC4FA6E288F3E1ED920
+EEFC42896CC017F618D19B63DF610CA08FF6721446B8AB73D536BD3F5BD1794E
+F89F380D0E3EB181E0A675230FC8353B32A1DF6E7DE4EECD1EA87DF72F3033A3
+B48097F10AF413BB5BE98852AF7E62F088E885A86BB07C15B1A4497AB0C7E181
+7BAF23D1B31696AD74AF642F36ADB05A14F004EDB1CE6734E7FFC8CA049AB6C9
+5408F91DCDA00C4B5022C29DE7B6A2D1C41C244E771DA6D050B14C08A8E3C8B0
+D089BB4B68164EF281EEA9B6CF58A7B74B598A1E30DAD1F73D05D1E77647A6D5
+673C6B83A012B15F373079C30E72523B591D29CF5F7615DF4B5F6726915A5D03
+6D8233D313B1F8DCEE93FA749EEC483DDD9AF0FC7EB8C879930BE3BC58515B84
+BEFBD90CD57E8377E2EB2984DF2B1BDA6A6CB3926BA821F58F9BCBA8317C56D2
+6D37DF6AE562900695DC31004AF4506FEFDF6E8D5804A63A59D176517910C784
+BDD6B7729337C7668EC4E393FFE08A158F0592B746D6754F5A97E4312AA7D376
+A29C7D43BBBB8DB4CAE338FD76D8139D6D97F97F95905909490B48D37B7BBBA8
+D9A98555961E734822D846EBC665DE1792F0F0D942BD7DA2D8DD9AB29470AA75
+7D3078C021DF4BD24F5CC9B12F0C3D1DEF9CC10B47B7A12AD9558742B47484F2
+DEFA8B5077ED0191C15E89FE58490107733572AA95D643F4FBA761C5AF8E0D6C
+3250D597317FE0BAAC5CE4072E688B388FFD7D7F6D1792985768AEDD8A20255B
+44F26FB215A666FAE804204C23472876169608AFE831886F8EBBF3F84A9CB38C
+D80226FBBB3C2B60EEF75F0E2C9A9A30F5618D13F0DD84B36F4F30A211896FA5
+858248862E9F422E9E31231DE72A628EA00EABA81C59567D86F0E66BBA8587D8
+A3A0133BDB30C74F2652CF75C7F247C7F5B01ACB9E8F892676A67CB7FA879D9C
+6034BD216AA626EEF69C718CF5AE2B9215D949FB4566E39169C803A4122D7D8A
+2F5D2A7B903E7A5013EEFE0558D472CCEAB9827620333E4B44BF44ACC1CC0E8D
+689C9202A9E972D34ACBF7A1C7C97EF057D5575957272934E0E5800153C8DB88
+E771DC89C0407DD9C806EEBF6BAC5A15632C1A72EBB047F2C6C1583A2D4F8F08
+58D680B3F48738CBDC2E4E81B0BCE80470960073B5B0F69C62435F10FDD73C06
+80A0FCCD1B3BB0629A62F1EFC982C4328B6486FC222133091D4AC153D72C3A7F
+C1ACF5B02AF85F63590D95DFA6B1F887B96505AB280053663AA8E9A0A8D446F2
+CEB9778334A1C8469F5DAA99734EA85DFF2929FC6C1CDA3D1984283D4F3C8E5A
+D3DE3D61040654C0958F49FE50F737312B1B8B53FD77EA34B8CBE290BF448661
+F76CE5533613360094C37932A6A7AD06E63FD8D02B359688E345E548DF53DC86
+B16692D707E2901C0721DB5BADBFB271A7BF00F2F3F0EF70918E322E4F343CEA
+D18FC6504C697E69EA7D6BEB73EA87AD51AB32BABF794F1B22A6955B6455C114
+9A438671F30970682719974FD0B71B2B4A699D0430027B3D3E6D8478CE522408
+BFC9FD0A559944D24955742BAFF646C98004AFBDD735D457CA34B400B5D5D14E
+55466E7F6476C54F49D9C240917AC429E534C51C92A9B4E52F5CCA11E3E5D3EC
+6A0A28B39C2C7AC684FA169914A7ADDA925851D8DE6C750222591B9D98E4A209
+0ECCF91AA890AAB75CF3D8F0651DD9440C5123C7F81446112B4B556CF001682C
+C660950D870234A2E96B373C97AF166027AFEB6697748F952C87360540B26105
+E958B8A1C306BC1CEA926496C9ED819AF00EC1DD7AAA64E6EE21BE8A65A99CF7
+86746F3D155D79AC812E1F2A5CF3C6F5FB9716CA5C9A8AC7E580522C311B2990
+E289ADEE82099F2187F37CAEE490F807BAA4B520977A62DD017A7CF836CDE5A5
+6AA4A7862E11757B5D67A28BB35E3989BBDA1AE77AB80C7E33117D6A9A353593
+687B60BAE871DDC7B0E9A10758CFC7E3E972B51A8F1DD50546AF7C498EA487DD
+FF5E9AC8D87F2485A4E680909C07CED7254B5FF9E5433C3CFC55286B1431E39D
+D4912DC8BECBBDCE1B7FA21AEF907D5CFC56685FC47116F7F20629747F766974
+95D75B64D0A6657FD0CFE9B56B912E7FBA38AE10EDD1E8C427772EC42CC100BF
+5ED34DFC3093EE90D7CFD9E2ACD55D1FF31118B86BFC8ADCB490499F71946C1F
+57477E88574FAE17B4DAEBFC8E100BEECB1E473C5A2F882A63F61B7826C3CA7E
+44363CB33E5D8BF5E88F27F626B3EBB0C313D34B0BC69CE395DF99983E35D77A
+2193C441E0107DFCCF424F49E3C7995B8A2C6EED7ADA45A1A33895E07F9ECE8A
+DD91AA4F5758CC030D3BB0D7C2E86A1531E9F1EDE5AE52F12AF9E91EDF021030
+6E69FFE765CE505C617E6ACAC1B3D2021F1DDF82B3CE0B7E9A68EECD246AA818
+2BBC9992E440BF3B96384125EF21BF56BF673D0256BF647CBA2A538438CA8292
+89464AA423C9438EE2235BFE98B57CF89B1B1CAAAC22343324A63F913D1432DD
+44FDB2E1F60FB78653DAF52BA657E5A48DE5FA5B4A419B83D52EBDED19355B5C
+FE6A57303C33413039B9C074187F2ED11E52074A6EDE22482DF46B624FA64A70
+B2FDCE4D657CD67EB327D5ACA3460815649AB144744DA5C51BC6EC5E94B3ED1E
+4F88997E850E1ACC9544239CA85A7D5C28EE249B966081BCFDB0D51B81EE6D56
+DCB2FA5AB76D47BA98896B0D52934577760E231FE276629D9BEEF1179CDAE173
+BA3E480FD2E2D1AF8D73509D1AA108C56E668E8A7EBA8B6BD4FF4CA54FF2D202
+DE60493D82588C215EEFE423619700C3FD2BB73DFDC0CE2EB6EFE7C2184657D7
+33692854C0DB7DBC388D061CDC20060E4076889A01D0FC9D6368F0227FA1183C
+3E68DD3AE54B28808C93FCEF4F7C0B3555234C1B700EF5F9906B871B2A33F656
+74FF5C9BA74ADE3B7DD08EACFD8252E5F7E00349EF090A0CB375E8E16C035BB7
+9C25D612AA75843EEC123998AD8AF43960D55DED6653D8E881C6D6B6DE9624C9
+6E9FF1D74AF8B3BB39CEA0F74E13B65A171F1816FC514A32D56A0F6D2947EB44
+FF916B467361A185C9D3337A26901BFB6137903D9A89359F3DFDCF4F74FE20ED
+C37A1B1FA70E64B910E9E234F92CC6AFB9CD343E14C360C9A4D8349C125ED130
+EE506B5E53C74FD4DB539C4038A5E99CAA46429F02E3DD462F5D2A078E2E8880
+3AC7B4618454A08C8B3C994489449A5DA7ECA6B80FC084053C65B4574A75A1A7
+4A9E7F86FEBEAFAAE9EB8F10B6FD73DF6E6B1638CD6F73FA2B3AFA49EA56A2CE
+751D167118B3073746FC301F5E5F97C0EAB8B7B5DF5BB27958312CE8792281B9
+D62301C147101F32634E7730E1697F6C76FF342770D635F417B26682E70FE88E
+A5178BC9F1604681EF2E5BD37937B5EE0AFDAF9845F25A3454F30BE34BD516AC
+7E104033A567B4445B5BD6ECB3D71EF454E349BAF12C059A90B9BED8A006CFC9
+A927BFFE206AD54351CB3772A33A83EEFEAC789492C95A15CF6ED00C9016E642
+3D474AAF77F5E968CED1637F7B96225C7D769FDDD18B385E78AA60089D2BE218
+14F2E47DCB504026811C1E1966754072525FC8554943EC9817AD0A7511F21CBC
+49BA61D493584866C5FE4BCB22000E1F72D6320C7A6449559A9E085C10C3C1C1
+3C69C0C355385948C822CB4CE2726DB4A78BC3225FC1EDA373C64DFDD4F3A932
+C99C34F0048A3C8412B0660BC8E435D8AA311487E6766F203149941CE19B48E8
+724916A0250AEEB0EA527CB9D7DC48EC31BFD11190F329FD642D18A4BB0E01A2
+E6C59C2AD964A3EDDAC052FB2479401777E6A5AD02BF93FB0D3D4C02B8771CFE
+95502A45F1E36516BE1715B4AF4B73021771E4808E5C95CF68E472DA9DD4C429
+936DE6A73825DBFB6CBFB3287A2922926B80CCB38D51612027440CC1CF53EAA5
+278D9AA61490D705A0F4F912C72EBC8E8FCF6A51AD580D483E3C5B830AB6A41E
+4DF559E9E61B92D183B62B7EE4DDFB9AD14F244B19F6467B2BF210327845F1C3
+B77577E2E2A206913AA4FE0D5574230B54936A34ABDAF521F64DD42274A8DFC2
+46896952479D9498448B59DF3B31A4BF20AB11B425DF82F11024A09AA89D9BA9
+44E7E118D80E61DBB935B2EE788E0A79FC95BF18E264413186533EF5F24C4518
+BC7C75E83E12660CE2B2087851BB4DEF2263D647BCB2383429FA0239DD08CC2F
+B60EBD65000D268A1EF12570FD0777405DB67FAB4529A3E4C4AF4093FD6A0A66
+5684568035B9B6B39C8B7263AAB848007FD44692A4D9C1DC972CA488D8979F78
+D984BBBBBA63594EAA2147190E82EBDE64C2B4116D43A9809A2133B6F79999B9
+22FC69623EC865A27A601351B1CD9F2534FB692DC570611FA8C87EAA4380637F
+7939E2ECF4DE7E78E253AB42DA597D724ADACD23163F41DC48ADFCE89E241923
+4F45B563D56816079967D165BB8E6747CF9C2CAE63438D6EB7AFEFADA73C53A3
+524B8F33D53205E2C22C857836E2C71A87C3CE545814EDFB4007A69E5786B8DB
+54B91E072C602898DF9CF4D93AB699101220A7B7A68192BFCDAB82947F7E1A77
+7B5D8B2CABE483B87D0DCE7C9AE04DBEB4EC3ED1C74BC5B4ACA1EE89E1F879F7
+89D81AC3BE8A1F61C0F0316DBD0363D193149EBA185CE7C561DE05C3E3FBBA9B
+9BBE1C82E1D4BFA1F38F7CA850D101BF3C4B6D26D981CC71C7C9035809D17297
+3293D1C5030219DF943C42B8947D2D8DD8E1D63EA94F4E1429FA6AE178D317AF
+242D813B967B677CBEA4197A3418D647A90BC15F13C5E448C74E6D3563D7399E
+8EDA835684ED87775CD3955D69BA7E87A5DEDDEB53E898A30F9ACC5707067968
+90091B8862F83E3214191165AC4FE1F820A8DC9301A12E0C9B1706F0E655AD9D
+3863E0D6B5700C23E47F17ED9F8D99296D4B84CF381C5BA776D5C210D193D22B
+43ECC441368D803F4DF51BB88721F2765FA2DDFE5227846AF185745222E10BE0
+95C282B5BE11FD21DD470705221403C776CD2199AB378A1B808A8D8378B554C6
+41FD8C08EF663DC9B69BE65E4DA7E784D5C009E5F5E339DE43ACEAA8606ED98E
+F88C13CF6B104463E048B405BC87A01C776CE1E6DD3BD14DCBF84C4F04F2DC70
+90B8D8FB1A7C23829AF0B4AEF88FBD330B5CA2C122FF88D5308C003ABAB85CE4
+283382B16DCBFAA56FC90BEC0390D4E9D159B27FC4359560F0B3F2D2A66E5957
+451D6A81889B299614E39F6F5DC8D2CDCD2AD0B2045804304FE4093DB8024F49
+095952867EE708A43684090C3C08325950E5B6E31614FCB9BE4530EA4F7C85AB
+CEB8DCC3CA496E59DEF5F4D159B576C67D0F4E261D67F8D63446643C4AFDD11F
+2D0B1A625F93E45A43A507D6137AE4D25A6AB887BDF403CFCAA4BE8B4F3433B5
+0492A4E82FCF71F0F81DF6CF1412420BF8B7B74C3510E4D057A6490BA235DBA7
+E2EAF838F9F6338EB93F5A5EBAABCCC73612D0EE7CAA32FBBC06F269D44429FB
+9C9F270E8A461ED57EFE97D5620F357B37031C17DD01C129E42B7C09BEF447D6
+363162F1A326EF50C9339C532FCA859F155ADDA8A614EC8E083863D68084655B
+B9D22E3198EF1476E7179201594ABF6AB55D9C58D3C27AD95A6ED28D89E30A0F
+00896350907820CFD6E25B7B6A8D45614E3D92AA93D6795ABF514A58F1512D31
+C97E1588372BF8F0D3A25E86926EE1F546A1A9049F01186A2E057C26730B2DDE
+EC28EB6A9F6A29EB6F6888C822AD5A1413FDA1990737E554056ACAA6358B8894
+26EE5AED75B3582E857A487A954390629DAFB8DDA976CA79970C1486F80C7C11
+F4FC26EE0B8B18BD9AC1ABC684E546D2FA829DA2BC619EA1BDFC27492CC0CC28
+C232399559A1D5706909228BF0CA06301B36B87C0B5C761B1AD05EBE4A7FC4DA
+BE7C55BD3ABAC5095192FFD33D441120A6560F12D886AE15B0B1FDAC9730A7EB
+E54A1FAD362ABFCF5B72EEB279A86A0495B78A8FE5338C3BCF5F0105C66C2674
+1DC8919CC9BF9F6BDDB04F42D18965C6D1C525E3E45ECE744F722BD6EA835732
+DD72EEC69CB42B634D5FAD83C295B184110CD718BE52B7BD4A170FCE27ABABA4
+74B32012F20F359D3F3D0C1818AE641D5DC4722221609DC3A78E826D68061EB8
+EC734E42B9469B715D78CB2BE74E1599A47ECAE1234F8D278633FB1EE2D83B52
+A7AA6B7E588819CEE90BEC43EBAE93E511E4BE18436657F174C2ED5957590800
+F35AD6671FC0A352B1562E042140D3668E1239C90FF717CFCA0EA4BBF2679B86
+B179F2717C27263E31DCF3788EE038D4C6FEFBC918C5313546C8AEFA73FCAB0D
+FA055D120659BFD99937CCC34D533A10B67BF498E2A52E9DCCF38ED40F7FC380
+9F869127773514D198C61031EC04E916126227BC4611B8528362C78429C897E5
+8943F4B4DD8C590FC1AAABD603D9FF15133B1729FFBB1A2B0975BFDA92A30CDB
+3C3A59B7A6B5255460A7AB1F01DB3C651DB95A3FA4D79E8EF704954A8F52343E
+DDF4AD0DC6FF258118274C23A470844E58385F135D812D1EDB742CE6E33855EC
+53EBEE6F4BFFD48A2230CBA4F30DCFC8F86037F942E6A253F03C2711002FF4F4
+7027D7D1C0475487527D316FA6AB9E1B1D04A56E818CCC1D106BD5D9D2858522
+92E832FD5718FBF7EC656CA84FE2B2794DBEE834BA2145EB1148FC5D57E818B9
+B7AFF6D2F2B0816C301175E6DAF7F276FF495C0D0E647F4028C94D9610EE2B7A
+A81E66E07D2A9726CD469EDA81858F8C269797EA3A8CC018B7A6C2DBDD71E261
+90E903120EC01015CA59F444BA8D7137D57E68672C5CED88EAE80FCF9E67C3D7
+9B86FD5734278233C8E264C53C88CB7BEFE88BCC5384095154E3FC528520B6E8
+94BE6C714F9E8D97E2EE980FC6EC8AB86006D9F9D24F90D58BE98982ACB96F71
+C2D5B94CBB00AB07A1B132606A87B1BF710C9419EE196753E24E544DF7EE0766
+D2DCB7CF6A2934B96D66CDE5CDBDD23DD60F163217F3372138E7B8A7FD206843
+CA23986600CB3CB287BAFEA5D94479FA9ED24AFA727EB872CDF44C43E870E43E
+0C9688D426F0C86794ECE9D133A7C32229ED93313AD008730C3000D053962330
+C8D100E7F5FE25E31D0C590010427CF42A6AA682AB43A082B52EA29C6C5BEE05
+2D69BD0400954CEF43016B51ED03B80A28A8A427A89F099EB2162E688373D231
+E7E9660ECAE039EF1F61CCE716589A9BC2DE32CDA7C2D72292608975DE5B5F5A
+41F6169DC5A8097530BB4AB624ADCF9900247498756A91AF1257A7C980A5272A
+3C6BD101D2706E53202682D16518C0B9B221A90EAA867ECA1FAEA87205AC8648
+413801CA4376CE0C7EB38A816C54402513E68A0CC783B352F0D5ACEB7E7F344D
+557C8E732E089D7329DD8ED63F2A22AF3E66914F8907789972E8D5CF72865E68
+43783B11F75566F28081B5B74C56F44C05BE7DF015143E9F05ED154EB1CFDD7B
+A99F2F535A258A9C6C0E6E0A2D4B91DF0CA6284C5EEA3263C3BFEE493E21F66F
+A68B008DD39AEEB566C4F4FAB93E8172FD9EB0E00C93D057534C2FC2DFA4E92B
+BEB8F33F1B685044467019470184DDDC1EA9A16F63DF5BF240EFC7B3DC53D8F0
+8C2C168C317757418EA33ECC81B136A3DAF4A7625DBB9DBA43D053364B910BAE
+537FE379B65ABF70D6A5DE9613FAC4
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMR10
+%!PS-AdobeFont-1.1: CMR10 1.00B
+%%CreationDate: 1992 Feb 19 19:54:52
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.00B) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMR10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMR10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 11 /ff put
+dup 12 /fi put
+dup 13 /fl put
+dup 14 /ffi put
+dup 33 /exclam put
+dup 34 /quotedblright put
+dup 35 /numbersign put
+dup 36 /dollar put
+dup 37 /percent put
+dup 38 /ampersand put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 42 /asterisk put
+dup 43 /plus put
+dup 44 /comma put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 59 /semicolon put
+dup 61 /equal put
+dup 63 /question put
+dup 64 /at put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 74 /J put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 81 /Q put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+dup 91 /bracketleft put
+dup 92 /quotedblleft put
+dup 93 /bracketright put
+dup 96 /quoteleft put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 106 /j put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 113 /q put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+dup 123 /endash put
+readonly def
+/FontBBox{-251 -250 1009 969}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4
+87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F
+D1F017CE45884D76EF2CB9BC5821FD25365DDEA6E45F332B5F68A44AD8A530F0
+92A36FAC8D27F9087AFEEA2096F839A2BC4B937F24E080EF7C0F9374A18D565C
+295A05210DB96A23175AC59A9BD0147A310EF49C551A417E0A22703F94FF7B75
+409A5D417DA6730A69E310FA6A4229FC7E4F620B0FC4C63C50E99E179EB51E4C
+4BC45217722F1E8E40F1E1428E792EAFE05C5A50D38C52114DFCD24D54027CBF
+2512DD116F0463DE4052A7AD53B641A27E81E481947884CE35661B49153FA19E
+0A2A860C7B61558671303DE6AE06A80E4E450E17067676E6BBB42A9A24ACBC3E
+B0CA7B7A3BFEA84FED39CCFB6D545BB2BCC49E5E16976407AB9D94556CD4F008
+24EF579B6800B6DC3AAF840B3FC6822872368E3B4274DD06CA36AF8F6346C11B
+43C772CC242F3B212C4BD7018D71A1A74C9A94ED0093A5FB6557F4E0751047AF
+D72098ECA301B8AE68110F983796E581F106144951DF5B750432A230FDA3B575
+5A38B5E7972AABC12306A01A99FCF8189D71B8DBF49550BAEA9CF1B97CBFC7CC
+96498ECC938B1A1710B670657DE923A659DB8757147B140A48067328E7E3F9C3
+7D1888B284904301450CE0BC15EEEA00E48CCD6388F3FC3BEFD8D9C400015B65
+0F2F536D035626B1FF0A69D732C7A1836D635C30C06BED4327737029E5BA5830
+B9E88A4024C3326AD2F34F47B54739B48825AD6699F7D117EA4C4AEC4440BF6D
+AA0099DEFD326235965C63647921828BF269ECC87A2B1C8CAD6C78B6E561B007
+97BE2BC7CA32B4534075F6491BE959D1F635463E71679E527F4F456F774B2AF8
+FEF3D8C63B2F8B99FE0F73BA44B3CF15A613471EA3C7A1CD783D3EB41F4ACEE5
+20759B6A4C4466E2D80EF7C7866BAD06E5DF0434D2C607FC82C9EBD4D8902EE4
+0A7617C3AEACCB7CCE00319D0677AA6DB7E0250B51908F966977BD8C8D07FDBD
+F4D058444E7D7D91788DEA997CBE0545902E67194B7BA3CD0BF454FCA60B9A20
+3E6BB526D2D5B5321EE18DD2A0B15E53BCB8E3E01067B30ED2DD2CB9B06D3122
+A737435305D42DE9C6B614926BFD44DF10D14402EBEDFF0B144B1C9BD22D7379
+5262FEEAFE31C8A721C2D46AA00C10681BA9970D09F1EA4FA77428025D4059BA
+2988AC2E3D7246BAAAFB89745F0E38580546045527C8779A254DB08DCC6FB9B9
+0E172209FBE3857AF495A7F2B34BC895A39A30F903DC6E3202D29AC110D868F4
+7184CB78407B8B9D42F6375F67FD4B828592E4A977B9E71854D143CD1A9EDCD1
+767CC2929E071FBA4C3D17500E28A23F697B5D5CC68D5F56EAD14BD504E07182
+3FDC12F5404E74EC1C02AF00C1A6A17F958770ED4A024F5B3644DEFB61F2578E
+56013D0B4E7CA3AD255E23DD63369A921D427EEE0E098E8148B16E8A5613A8F8
+A5F1099E15AD16EC554B644DF306F0CF3571055A81F1B464529DB49E919F88E7
+581066BEC4765E31BBE28C245BBF0B74610DBA30C63A71A4F3B60593A6B41C6C
+636C980828CFE9A3362FBC02F1967F0F770A4790F90DEF9D56E0A76B0703FC58
+2841E6E8D984FB476D4FEB960FFB6B386EC6CBB9EB83704B0AF63F38C77090A8
+DAA165E6C6BC86601B14F8E9F504A9D578AF05128D8C1BCEA9D21057958D5DCF
+63459352EAD6B4A2A666CC5D85855641CB31507F9E30405977B74356FE985A6D
+541884CB65A4F5A8D4C82CB9D82846CC510CBD243E98A0011AD37A81047021DF
+46F69D7C3DFAF2F10F1F0CCEFBE12EB70420BE90C450975434E223C67D24226E
+8B62BCA6BF93B0B1373AF55E4ADD92775B2DF199B6599CB02DB64B2D6160BEBE
+449C057B5B2D226E0F5D7CFB5C9A4A7184FB29A595E91252AE787861A6331FC2
+6605C995D55120121CB463473A7CBD22F270D56CA8E0DA99832A468D399CB9F5
+A1CBCF0031D99F3C4F4B78A0944BED5A7B1AE23E3A66EED453917F9296077306
+06CFA772BE60854A30885DC5FB8417E0D3F7AB45ABFE186D877A377F5D17DD35
+0FAB81745294E35A5DCAB20321C6ECAE276B63BB17366867F346CAD53E06AD96
+091CAC75465BCDDFDE9C4364B2A8EF496C4CDF76B058E4BC1F616F6CF62FB60A
+64F81BABA7A729B8CF679CEE01B1C985558E8D1493C03B834F3696E5511A1917
+2AE7E16AA8FC516CD2CEDE020BC5777598165B6EF2310F4DBD54FE14071101EB
+47F4B2B59778B1EA7DE13ADF46393E07DBE2082C2487944A71CEDD4ED7D3D877
+749D2500636C3996A34EE0CBA770F6B6A655DCB9840AA8236EF3F6182E1C8997
+395077D9DB15B9D0A2DF9A3F6042C94E6E492C965E4E8542AC4AF5B21906B6E8
+4AE2B01C0810E38BFAE99DD83EBFF8E145D09F763B6B134A25A1CC067C6DC1D0
+7286045CE90BA968598D83E5602ED96C72A424848E211C028CB344D95DA04ADE
+4C5DADCE9009A72B6EC01E7B5CF8C52BDFD2B416F5E1833F514659D94BB2F452
+EC4F2E65CE71AAF79106A0468D76D283ADD44D7DB5760AA429D61C1DC2E912C7
+9446C19557A1D12E7116B765BE522EA166E8F0B604807215323DC5C2DB1F2E05
+246873CE189E03FA291A961E4AD90563A8F7B0E08A67DE4CB3607C6ECA114DD0
+DCE97976E208615F3CA13FC44041360086A4A173D5441D9C33A38013099F73E9
+0FBC96808F7442FD4D56DF7C4F2D4C9B2301F7CE626B4C6C1617B8F1584DF195
+F92FC6385070EB02BF2541307E4EA34C131815FB9028C118F4B792C4338F02A0
+F6B5FFA3E4CD9AA4C95E7FE26CA24BB2B34C48857055B8EB53480A6CDA79B587
+3FE3E719924EC7D32A92D77221F13F3C4ADCCAE9A13BCFCB5FD72DC40F90F396
+ACED5022449E600D9F12A63C094F3E26531ECF9AAC13D3FD80F25E37A9FF12FE
+EEF0EA34D23081DE8674EA19431153CEC8E96702138A31C19C05246995EDC3AA
+6C98E2316BF65DD696EFC55816C09C7F969FFBDD771250D41657BC81F95A6D6D
+9FCF05E485ECD7C6F69CD8755197834EC8DAB8C390F161F74832525690D5A443
+B2E63941267E719C53CE707F9C0B7FEF30A238A88EC1BDB8ED7D379225EF7122
+3B7C8CF4C130B89A5DB4513F11B8D3333C4FD9B33CE874C104517553E6DD37BE
+320318774481CF4EEEC3E43FFE81EC9C5043AA9DF67293D72FA76353412F321D
+1A80076C42EE240D3E65912F94578B8A2B4DA42880469451907FFEAFB59F265E
+80AA5D5C32348F9B7CE6A6855CDEBB4990938417ABF998E4B433556BFC31219B
+C2D8ECA502C967DF8FE4206274E389B52AD065E9AEDB067F2E6595D5989C4788
+41BF327A1AF644D3C3C1426270168E28CF38AB046EE4893970D0566367650CE0
+9656CAB7CE1FB66A23CD3841E0F37D4DA2BD4520ABEC9B781A2B9E934B50D554
+BFFE5D2EC1A5D1FD36B1208365FBE15516FAD517FE5ABCB086DCBCEB50B7918C
+E324EC58BC736F594FA4789B528265B51B79B486AEC5252471D5EAD0C552628F
+988EE219BB95D00123D475E96A268E8793B053343FE518C86FF4A0371D394E87
+9CD9890B65DD3B714FF8AEBEEBB77FBC08B867B64E4086FF917B8AA277E1B3DA
+65E05E5BE4941717FBC76966656A5EE7CC4E1488ED1B4388DAC813D1D25C1308
+1B220AB8A036DA4A3104B552EE21330DC917B9458699100283BBED7DE5634B08
+E1E8A1275815A358B4C0D3787313C850999DF7330A5165A70BB5B5104415A5F9
+733160B501075FC60DAF1C8C6DA3A674331DDE8854DE916DDD0491906F4EBB7F
+6AC56C4A9D6132320E2E021CFEA843F7C56203E943D3A9B12D8321EAABAE3580
+BD58D81B6C551BB86D2FB83A3E6B4924EE0D07E961E5235E7D473647322CC62C
+69EB8DDEA11AAED833A80339E58330BD4AC7BC67B692ABA6A34D4D2D7A1A279A
+4591974DF964E64592E3856B6D72B26D6E16241437159F3A09A5F30A43600835
+30C76CD71780CC61C31DDE51A144E6E656F62A579D808F5FA729F1A66382EABA
+98B6E376765D96FF4015BF46B3314B72C007A8DAE08A2E29F3461FA56B4BA6DB
+AF6AC06F4C94FE3F2D692913E13F99B6AFABF801C0119625C51F8015E35BA453
+E58AD266F5BE4EA6E839C605AFCA7F11B673E51FF62A17D6BC824119A89599F8
+6E04D3DF374382132A2F1FB1F9E307DB10AB21E627C4356DBEB97C0A6205AADC
+1122176F33DEA813908601A242263A845256234C6A3C9242AA2811F9E43BAB93
+4A024BDEDA3CB1E7DBE07BD210EA3341582B6D2A1577185C01E6F38CBE50E63D
+C50C27D22533C60F2FA74E15A9098F5B0AB07B31A098A88C9629F2BFE3E51379
+F443E54F4AC11B6134C39EA3F16B0AD01160792AEE382FA08C171DE8FE8D78B8
+BFAF4B630DCC09B8C548ABF9AC0ECE250D4F18F481EFD5AF1F00B23DF090B57B
+C57825A72FB1E529CAC192DC16ACD2D77E8FC158921B4E9073108E69D69E191B
+7E8E1840F83F758C840A0DA59252EA309DF1828E5C01FB9528AF8EED2A5DBCE0
+B98CFAEED4BE7BB81293E49C382F8662548F7CB5579C809007E665A50BBDD51B
+2CE1756BA9E84AB65F970FE5E4282417D5006EF7786C02D0817D3841DF95E00C
+87CA35863F66C06860C9117A4E7E5008D45B70584AE3154BFDCA49006E9548C9
+78D25EB10052885AEDD07F8A050E5A64C5BE3270EA594D79CCECC92996C2FFB2
+E5FA947080F1EF2335799A8DD8BFA215877BE32C2B5A633153F1F8EA8C93B836
+2BA3C7452B8D0AB8E6EDB16FEEBE51B64FCD0601F8F9FA99EF4241CEB58F8291
+28F21AAD148D8D681F84E51F5A53F6C13E5CAFEABB18CCF22180C0B911A37624
+E25FB908863CC80ED9C93B93AA72997D13FE0C71F0F38F274B638D461A441421
+4253CF8EA0F89FF54F775FBAF2540C02E895D0BD75B6F03DBB65124BB41F8743
+FBB668587AE9359136D860FC3E09458570DE498CAEB9068F44BBF24C77D46395
+96A3F22907F8A0C508C083FFF396ACFBFB26F6FDB2F28FE49053FF2FBB643CB2
+50B37C1C917466C323ADDD9C246DF9F7D7B4AFA75BB0571D5DEBE80565F81ABF
+02EB769F35EA6E2319FEA269303A7F72F754C81311A5A22F6C4927EA2B1EC35F
+B804811735EF39249E020EC76AD775FFE4593CFCF5C6739AB35528E02C863668
+48AB1521C4FF943E544E42E33DE193867A715D1F6ECAD74F1F5890369D6A1375
+C468417352E9765AF21B9C0822494026EF63D63D5BB61200149FC2AA8F7CBBCB
+7A7D5E7BF9EAF67987DE4F41ABD8B52D9978C70CCEE6550B42D14A6DC5D3DCA2
+2AF30D02C0732B97A1E818C11C4818D35F55E45EF64F74C5BCAA9E58B7686DE9
+51A29D0CF5CEB3AB6A1F280E893672BE474A173A6AB7E11D3BF82641AB1EC067
+AC9F2175B1E324F9DB03DC91928081303FAB31002BE72A3541D91C86B3FB16CD
+DA1F9440D6E67951640DB487D9C14B9A7DD41F2F450026CB7B311AB3E578E513
+CBC2DEA9E8442DA882001486101C232581E3C287EA8B1B045D594EF81A715ADB
+CCD68BE8EE8288D4FE53F1720A6E0F25FF0BA9B85D0BE1AFB9CFD76EADC35429
+05FAA1D36BBEEB637B9514BDD2DD2C0C4366597F4A6DFA681F6524407F0082B7
+73F05A553A57C15855D524588D46DDAB160AE72C99B6DD13B820B17A807DC197
+7CDC6D8F5141167915F8965A57DFCA7FAF941502F6C00A1CE8AE03C8382D5041
+3F0400089F18F9F8437D0AF632520F94F4BF2464B50A1AB0CDCD94F8BB75EE4B
+9150F660BCDBE851879ABD99A35E9F75E52F859837B93410444E8E58CB9C4B9E
+C7518E7AECD56AA1B04B3E89584919B6A84974A4B8F01F6B2E9D12F13F913479
+710046D5AD2C9862B71E9384969AF640436C630796A0453E9735FE8F96D3CEDC
+7FCD4A0DE65945A0205DF90B9E7FD31A3020B6E87756C41CBCFAD1B99D910E44
+7D4E55730848EAA86C349C6E4051E7CCDF94DAE8E38D1406696C2F7B312EB45C
+C8AE6400CC1B1E9613726751F1B66689F58DBFE9DD4435DD20D3164CE9551382
+0C56E69322D6A55F9F84A67944A3AF8FC8A0FEBEC541B24140C17510A35A9483
+FC9916389A93C8A6E7204087D167C15A3B3CD306B5EA0BA1A652FE4C0F4A63F3
+00C706FF2069B4D1A74EBF169D3E550EDFB283EBFEEAA6BEC1161A363E3791C1
+4DB5DAC83AAE1F922427127793255A482A6FB51E93A36ED4004D32FF21AC74EE
+ECC545D1D9CB445C23FD6D3AB380E49F630A289060FE2F128CFF54F2E91F3693
+A9E34F1B0DD6A078AB015C55DC52BA002FB1C597C3CF2A0C1F05C1ED15A173DC
+EF084B375F84F9749187C633C3A2275BD9AB6C714884ED37C6CB144CE0035343
+5D65C2CBE7CC790F4F6DEC3B40999F9F1FA1E2E552AF0CD0F913077E37D8E3F8
+2B77C80134B6163034B8A8B54B13D1A75D4E21638188C1403F5376EC67341F0B
+B69D18331EC9C4A6B85AAC493FBB73C1396A3CAA5A330AD45F074DD0A975F02F
+A30A31820CF85BAD947252DCDC801992EC112A76E8E693AA911352B32F2C2C79
+9E611ADD6329C6E258D293C5334C8DAA9B74247E8E138C377D563A10F1A64BAA
+82B9F1E319AEA437E4895502CB8BCCD7EE3046E67A46E255CA5D34D049ADB2FD
+AEB2725B5C13ED0335CE3AFFF946B913F5000376949348F3541E09A226D8AB43
+D9B96D5DBB7FEBE52E13FDF86D8303A4A2753B6F3DF0DF97B885D5C6F6EEE3EB
+A60967FA4B2FCBE6F039F6D2A6C79422D4F38CAEB72074C704DDA845A4544291
+7BEEECF8A4AFE80143FAE28C27DDEB1E5CB0EFB1B017D42AFB5CAD9365A77F1D
+AE6EAE307026390084C8C9DA9131A46487C410235020F12591168C41B6C4BF2A
+5AA04581F532F15F27501295FE091BCAF8641FFB901434AE4847BD08FBD94A34
+93B9A0FC241B152E0F1677D1F6A4CC955CA533A4E9CEC00782D9000AA325CA1A
+8CBD580A18F9431BB20CEB8120814EEB48F9123279F26F7DDBA577D6F08E9F1D
+42339C59A4D913AF2FC11E40632695D460AD1E2220F3E951754FB8807C90667D
+6BC9ED16A6B96C2CEFFF8F84AB02B5619B53C9DA4237F2D51841044E55C591D2
+F71F94A5D6B098EBEE8F535A84FA1EFF618D9E682F74C2B24F6B7492EE264485
+D41FC1B135A3F78F7DBFE730B2862B9EBB76E50647C22B92421355D354C3305C
+FFE93186364D9F3EBF9100C563388C426FC6B8A37F535A79D1DBA9858ECCA6AB
+8B39A321815354F1FDCDE71B64D2429155C97D5906A2F9A2B8854C80045566F8
+11E2A2205BB47FABB6207F0AA74F099B5DA39FEABE06D6B9748FDEEF7D2E977C
+089F437B42450C9EBC6FE89D876F8DF6E58C20D2B147638252C63B4E84B61FDA
+69EA7692FC1369369CBA019D16B6F6D28356835999BCC24DC6B0F0897E798426
+84EAE64D0EEEA2CD568CD124810D330AE06D623259D22D2F977D51962A498898
+89E0E19C928DCE67DA94C2B0C86CA257E453798DDD111791E29D6A2BBABF4580
+1861D8D940D70EA3B431CC20F8A602B67C528381449DC8353343D1F205D016D0
+538179F3AC9F4ECBE73D892692DD528DB2D3AF1D31E7248B5A4EA0343556CBE5
+B619A19EC1F04FB65CEECC60D7B2C68A1D88347D2730A2819B3331006EB854C3
+3A41FD0AD0DCD40235E8585077B41A6AD9678D87F7E14928F74F316BE123DDFC
+47811C5E052E82410D52D0B13EA86E20942F4988466B0BA666321848F1B00174
+457A338694C9B4115F0476E0B934B6A4F43B82505690836128266B686CAD4DB1
+DF53574837271BC9B28F0E8439DFC8917EA393E6B15DF5E38571835A3209EFB3
+7841AF4BFDC3B7F29CCD26CD41B14EBA0FB3B4860C4168C88160575983C511C6
+45CC50FE11082DD88D9C74B28B72E133DBC714FA1F028C633118850D7282D719
+2C7C2EC7CE1685DFED43816A34151A02FD6F78864758903A5CDDD5F0BAC32B42
+FE53F2547BA1C0CE4BDE807CCA6E2738EC2C3D25165546FA8FBB46F8FF1E64B4
+7714EC2C4C8978CB1EDD6B0C7F9341AD12E63D46DDA9DFE8D2239721E2E2C2DC
+249FBD8AB460390D5BD7C3B9B68111FD3466E11BA596E769E39372C3CD1BC8D7
+565C38FE1FE65FB3C26B3BF58AFBE54C6DAD2E3E3086B1B39F4BB496F08E7887
+A992C7FAE9281E609989EC45652A3A2F13817AEBEA23F7C71077CAB9CF2E6191
+F343BAD93C12D420E0AA5F706F917B7119FEA746269144F67AFEE8C66048ED78
+0E024635A608692E1A31BBEA0D87DD37C41D4E29B7C36D26539B121B2004A706
+999399ED1621854369C0856B5A3602E54FA53488B70CA8F7340F009D69BAB228
+2D210498C0632E60DB02546D0A8F28E93AEF943BB8A19D6572365BB9B8786B38
+B5A172834A3E651069084CF475ADF6BC436962580A06F5AE5BBE05753ACDF0E2
+545E9D7404787D328725ACB7D10E4AFBF0EA921E2E1EB0A2FB36A60B94086554
+FC6CF4AEE2E3166DB6FEF1412D5758A140FFE0210DD7EA7F5ED6CAB1064D4E0F
+B8C5FCD936DA5BDD3051EA1E212F5ABEA7DE611D7019CB62FEC5C97F348FF947
+E49768D88B45D2DF72EDD41E7AEE598E3BFF8BE8E6722D3AF05F991BA5FC7955
+48F2C7149CF4F33B2B62856851149528F80498EB5A835D02BC7F15137950CCD5
+8EBD57FF3BBEA46491E7E94C367856E6F8175864E895FF3DF53E37C3437A7268
+DF442EBACDD073AD234E66BDD8AAAE748A5B49C251647F384E843C93C0724F2D
+CE55E19CC28C2E0975EF4517C8E45D6B794C31ADBF7DA1832F286C9071FECCE7
+9E2A81BE0C11B0BEA840775C1F5F094FCD44E22BF193BE278131F6E6398E021F
+F1BCFAC298C92D1B3B63A2EC163885443D4B0BFE99A468A9586DF8E634AC5EE1
+4FEFB7BFAAB04A9A5C21354B37B32A055913422E85D86C13D0CC6407F0294680
+FB8BFC01749DF59401C258A44F5B8F9AA6F75910FA93786406D6C28C15067201
+56D8C65DC1DDE24CFE365B0CA10698F999263311EE6E3A4C0B10DB6C938795D3
+8073EF0652385A902915890966B8A95C081F36CCAD79492E4C43373719E3F49A
+816C289AB5E1A3490098EED8D755822D25C97EE39FD9BDE82FBA7D3A7A988A6D
+B00FE58376F725FF49E9D8D93CAE42AFFB48D01455A8934DBAC290EDFDFC06AF
+F38139C11D57F29C8D0B562321AC107331ECD505634A54B3F7E7C70278B1578F
+D4FE9EC16FAA9308DA077E973ACF872DBC9569C30BE9464EF647EE9E3EF7E057
+56F95E8FD465FF0148689A7ECCCF65E53DCDC0E3750D226E92CE155380D314A7
+896E8E3F079BF9ABDD45E47358DECFDF5B39B5DDF9A62FFB556AF17DEE47432C
+2CB8E2B48AE6C4E7099794700D4E33CB7419020AC5BD616C13A53D7A6152C6F8
+8BF5872FE600F44A245F884A0E2DBD44BDD1F3E81660C63A19A5E51571909146
+A293FA884908938E3B59A33590D870800ECA676A70B97C55A02452AB5CA13128
+E68C7119DFCB11213DA64985F54D038CE3A49363249867241246FC2C5DDEC532
+1B3067F6BBB1BEA9B359D5FBC186CF19A965DFF5CF117823A614FA43AE5856B9
+CFAF6EB0900741D3A2CBA1DF9E5F92503B128C878C2BF35973C8B67F7356328F
+065AECFAA6750C633A435BF27EC5A815C5A50733DCBAAC59EA0629A79CB2C55E
+349C802A8783FEA51C7254B52C563C2C3952739107ED219CCC9FF776F6BE85A7
+0BBD47696B6E2A2118644B12B39C3C47EBBFCCEF7A47FAC7B048D7FA3BDB2EDB
+DCEEA6E1806791D24CF1A933F97C4E0B4FBB8D8AB396CA6D9DFAC6A6C5F9D5B6
+D84F203E506857F5EBE68DA4D3ACE0FAB800673B1CDA565BE75C96348A056256
+E4E55820F5A3E92B3B54767283F69B7CDED30F43E13890C28EA5EB8044E781A1
+E556B8BC14F4DF6A662CC960CA2D84E4E82E884A2993A2C4F72455E64C82426E
+A3A06212E274881248106BBA6BB1912D9798CF18834A0B8A6AF0AB7D9C4CFD70
+0755F3027E6B8B8CC92C3739550A25B53430E8233A38DC43058CA991BE39A049
+E9C4F0738EBBFD64CAB93EB3CCEBB15873CBE1D3FDD0A2010D84772F026BEECE
+457DD1F178024CDC317F7A4358415D187907DA789FA3F5CDD2DF409A4F560082
+D866BAA86C282BB59661B780E305DBCBA141F8C31626FB8A2D96FE36D0BB6E0C
+818A510EC286E339B272D134BCBCEAB20EA54E008749C987843A35E0BC4FC6F4
+51C69156A5FBA0919F097703A589F0AC7CC1636BAD443ADBC14D1CEEC8CAAF7A
+DFC003A9BB6D647564C31C9F8B634F08D902AA74CD31E78BEA3D1F7B48A76EF1
+5EBDFFEA47A0AB6E112B0F4E9F8181915C38E764DF5A0AED0C0B6DA0A36C94DF
+1E46D4E71FD152F2173E4CB14E2EFF13A5256E4459284EEDCF91BF2D468E5B69
+B27E25AA8111D71FFEB0A233BB9E9111767D6A96C37A12E913C80EFFAF872D09
+C247B13B4AB649AFEE4052B2A912799A1A64241E2FE836BF67E1FC57C6EE3D89
+A60E4AD8024696519E1C831C6C3782D74274E57E11838AFD681034BEA8220243
+17D634FBA59776051EE9845E682139F82DBEF57602655D2CEFED4CBA8734EB26
+ECD5A8A187F47F9172B837B42DBC23ABC46E37B10AD31A12C78F6FAD29DC33DD
+C9569882A60C2D47BEA5F1E1FA4C7444A5076BB2FAE7D890BF059E68EA743F14
+3DBB31DFE65D661AA351455786DC4956EC6B41720C596E75703C2B3D2A243014
+1C7A148BFE8074817026499A35908B25907706F05738206A1927DE3780F3055A
+4257D086D5B2C16F9595C0102D03F9227AC82FC961BDFC923DB0ADE61517AE94
+D5A6F5CF4692733707A90EDBCE9CF2C1702C891EE107328ACCBF406AE86F15CD
+7DA45BE141F59F964BF11B6453CD9ACF6CF8255D3385219FE1F473811BF1A3AD
+C1236F69DF20A21A2E7809D2D3B4E5C48CEC01FE0BE8A7E000EDBEC6D3BB8635
+D88B61038CA583B986C4B8026EC737A22A1323096424ACF1940374D50097B613
+F59D2EE1FCCA68247BFE459329CBF8B3946D71515FFD94989A22377F1C614197
+A33F4BF7AA477EF83D2BF4C2B84AC30D082DA46B352AB2E4DDF79CFA06ACF6B3
+F5B5276CF19AF172561D47A92C392A039E4A0C1602EFE1C2A4A7D12FFA4DF8E0
+0D0735FA17211AF8E9EDC44E1B5AAA782755A91C57226130BD16381A96D7CFFE
+B45E1DC5F25FD2DDF260D35A6A91ACC1D14FE619D78865E5D3CBB766BE1615EB
+A972648777E55B847487DF5E1542FEAC876B2F3DCE15ADD69130FDCCF8DF2F0A
+1280EB86A8575B9716EEA60F65469F928EBB5CA63364D24ACB1061134D4D1ADF
+0F5E690C6B098898C1970E8B85DEFD65DADDE104D9486B1FC68E2E6E7AF84EF3
+0184986F1C35C71C43BB1E22633D6AB97DCE2AADD8CD2AA6A4BD653964EFE00F
+45777F2E211037281C3EE0529B11A53682E7D6A283DEF258FBC29F845D6698EE
+9CEF1F691F80FE9CC15B6D49E4E65162F520908B3209C5F56F54D242FCD6FE14
+FCCCF023938E9AD1FB75B47EE1CF65EAE507E0796018DACC8ECB7B7409EAC387
+DFEC49F88B238CB1F58A988F096C9CD38D4DDF98ED5A1534EDC35045C0126172
+7B9687C65C9B53A0BCF38A1AFDFCC09C70338876614FD4B94E0C5ED6DB2210F0
+DD1493EFD84B0DBABC54349C7665785D534B0E62E0D60B826B9697A977DE2D10
+7AB9C0FC1DF6B9C22374A768D1A83BBE3EB5A1AFF968612D252C38FF1E6DF43B
+600BCE109770E4B72169D887D63ED4A99D42BBAC4A6D1040C236B9620A82B3C9
+16E4867189B23C2CF3A4C74F2B6BA1A872A99321A2F83E2F4645AB26FCB722AD
+69CD91A39BA3B80DB61E1F39B442182B4E5356F910D5D2B2A302D5E0A84F14F8
+4A307FEB5F2B7C8AFEBC7E0E11F64E473E682E95182D19C62377CE3925B47D97
+5BED80079258FB004E8DD0FAC627FA3B8419D2CDB57B691D4F5747D3C6F82D51
+EF17725EE9D94221696AA7B7E22A2B761418CB71B2B022DD7B78BE7CE61D77C7
+2B24EA281583002286742650CBE59383CE62A51B345D93A230BA5620B7B99C1B
+01A653B8AE03CF79067FA259FB4C924C23FE19460BB276A5BC129BA8D10025A7
+6BC48467B76E8DFB656D2E50FBAEEB148894F9808574A27F478BFC1AE5A06CC1
+CB9B8DBA1649BAD8D945AC2CE7D42D995E44EA9482ABB7FAA7CCE140F9845344
+C1B78999AFED6D23C668453074C2AFF1307DC40C80261321372C4A2AB9A9C2A8
+9DBC33ABED76502F09099F2055D18974C2E0FB8AB6749CBE851A4DC97E3A8E04
+EB48A390E99C541A59F2ECDC0CB3D5DE991DAEA6AA1368228898C8A69B90304C
+FA18E275321266D06C32DB43390591CD41DD1E0CD7FD83129E89E3FA3D7D6E9C
+FA3CC4C3FACEB55817D9D9457B559309A5DF56EDE46F4C4B99BA10C302245D51
+F0D9660A99D01B5125349E1390B7D636E49D40A153A291B2B2A881CF8D9D0EE9
+5A3AE6EFF61B01D926CA46AE78B8D8670DB0160A154AFA587DAAFDC88B1F07E3
+5A09FB939FD04B0C49C891F4DEEDD67C300888829BD13645D1F3131C97CC39E2
+4B076A76FEFA86C65BD3AD836C70FFE6239657B02686D4CF2EAEAE0C28222ABC
+266508088A7A14C4F973C648C5EB3740144D6B1FE1B99CA2C3ACE458800C33CE
+10EA2636874D5DB56A15EF7A416903E830F8A80AAB5A324D55A90B5133B750D7
+15F6E7B057AF8861628364A577B0611D3CDA76CD0D1D0494FA66929CF31F0281
+AD662396C8E6B960E63E454B1FEB22DAEC770F4558CDA9A88EF7528C8BAD10D8
+400BD93BDE9DE519C516CEC04C0F4A04A2CBA8B20EBCA04E92427FD53C04BF6A
+089A5291366162BCF9BDD5DF7D5EBF2814F62E440CE1C9A4545559D0805FBB15
+D1478B4ADDB586ECA220567426C04EE77AFD804EAD66495589BBF59B99CBC118
+FB84AFCAF626F16A0F9D3306F0D32C98C19A9D24433B1C0100564B3B67A0CD76
+7BC54463440766C923C660C521ACA51CEC94F8426AA3F014B86C2818B61D68E8
+27B1EF085993D82E66CB100AAD4B6F1F649D8EFF6AB9E70595CE158470F6A2C9
+987A4EBC5CCFADAB433CC914EBAC83E6877C3E2FF6FBC7BA3D27173A5C3FE3D3
+849C54452CC6EC6A49EB4888AE8704CAEBD788509DAB1AC5CF42F600855E068D
+81E4FC6103002D0A3958665CB0C925FBB0DFD793573481ECFE3C47677BE59D1E
+87753B9A476D791EC30B3271C26D164282472B9A9700B7B7B52B59743245D24E
+9F9137BB2AE6397C1C983480DE0817D74667ACD338F22450A8E7A3CB2B0F8FAF
+E62AE44F230FCF3AAB64313B9C71CFDD9FCBC61826B31C36E7673BBD5DB7B944
+E1C47C7ECA5AC813D6C9A59AAFE306B8F9F3AD6159D77038542FFE1FBF307DFD
+B72C26E5834B30E3B30456ED51D9068DC7C5610E07696D880000EA5EB33944F6
+91C08157D9B9C094AF0CEC1269F1C75EADCB784503612B9F1CBB2E9ED8C75568
+34BB8736888AF7BF9CBCEDDEF078C06DE0A39F605CCA03649EA2288646A53A86
+48B4909E264892E3902F9049C63BD1B9FAED0F86B4E2A48BFFABEBDF03DF493E
+7129A6DFE8745BF260F0E781CBDFBF82B8C0D675B30BD68A8920747A9F8BD67E
+9225836B9D376803647BEBA6A793620A5B6E655F6E804BCC13AC9DC7523E8A37
+B527C5B2C5678B2CEFC06BB34F1C717077E5EB2247C2ED7F1C8E799C9CFCD0C2
+1981966D6B538AF1CA6A45E60DB3B56B3673388DDC88F4999AD320902EA4662A
+C7AC86E9BC9846A8AD6C70243CB3F0CD76B8D85FB28459C6C934F1BDC914E1E6
+05386FFB1FE419E92673185C4078C778C504926A3EF633F626C1E915A255CC19
+0B5491D633E6C55EFBB14D331ACD310E05AF9255CF9D5F4A5366165FCB102D0E
+82E350B6D1D7CA627C2B9364FA3CF6365E89F1F6A8B3EC62959723EA69947A8C
+06E7FADD9E8F77306801886FC458D468D428EA661B177DD11EA9EB262E35C1CD
+F2459040FD4FB56413E3D476175115466E86E86A48D37B7055091B34CA71175B
+C7D3B92738747D9278171BD2B6D90FFAB0CA0C8A2059602BBCD576AEC8B22BAF
+03B3D5166AF750BFC75E96DE08CD03D758A7D0D890733BB90B83B43D891C7C95
+882EBA8CB11C8BC17CFC77D92425878C391825157792922E98BFE8E388CB7C34
+E0864B35E46A66A76BE4AD49843DC8D7749EB3C75B4A9151D2D3BA2043144114
+CE0790F3666D8247B193FF496C1FE74671DC0395472CCAC82964B06D06F0B5EA
+FA826241D5C83D632A2E95B0155FDF99C3D9782813D74243BF5B2AFF49A9A2E6
+7DBFEAD8071D41699398EF82AF074C6D36E2A958C7C22BFB7D244E23A9135803
+1152C0F496F880192FC7D4291BE9ECCA4DA0B78329012146F9CDD5F13AE6BC64
+1FA4AA0627D9BAAE5E94931A75956703502CD4AA005BDA838EEF2C8E2D9C86FE
+C478840C67F0C3653E6761FA9E3D32699B87A5EA25E15A8586569A0A4C0B0355
+F55C8EEA5972AD04D9D259483276957317A895EAE1A9051C2F50D8D8F2574C20
+61BA0DFAAB062487915BBAC3F94D68597336D2CECBDDE91114397CA140304BBE
+1F29BC4D399CA8294CCD1AF86F7154C35C2BDBD522D1E2B50C83F8A3653AF4FC
+67E8DDD986C66AAF93DE1658EC602ADD39F149B4754F82047F31CAED0D16CB1B
+D6432783BA32462770F2BF25CCAD21FF0BF63356D02BF65F609DFEFE2A6A49F0
+3A99A28B4C956965831A5B4D7134E56DD49036A0BE4BF4FDC529C2E61C40CE36
+527E593B4AC66EB306DCC8B7F9C5F03E51DF3E6CEB90360692EA4F1CA8507B0C
+7E741318B8F27DA7B124DA9C6880200487003EBED5684CA278C9CAF90DC9512B
+CF0C4EDE8E22E97DD209CDE76215ED9034C6DAA5FBF0CF0A69BE243DA3DC4C53
+9409B184657FDB99EDDBD18E3D4875232E9CD7733DA08E917020D36EF8EE0DED
+DC9748565E2FC6DB1A828931533EFE23C6E45D7D51B753F9651EBD911A7526BD
+5800ECAFF7AA226EF9A77EEC33545BF089C1CBABCE64B535C8807CAE576DE6AB
+DC87B761759CA53BBF81425076CB1A3E80E59E69871EADC7568217A647620647
+F6E4DBE8C73D3CD572737DAD56D7C7CF8E0E29E4BE702FD3690917EABE0E0243
+D6C0BEB85A7CE6B358C03B168B7498D5865E9EA0147AE2D0C03FE89FDE7D345F
+170DDD1234AC758D038AAD707C8737A42C6CA8673A2BE06E822E7F810279F60C
+6FEBFA60457F2B9FD4B8F0739845DCBE70A8917249D1DA0D0D6F689F19F88606
+EE480B0E20AD4BC9C1FC6A69D7D8EEC59C9CE8BF5AA1F80EB16E71C9C729683C
+C4BAEAAC8BBAC6CFFD75C6E263C3B5E0EC37915818DB6B5DCBA0E7642BC15A7C
+25BED64854AD9EF87E641A6486ACE5D8E5985A12F641023BA4CF2A91B071592F
+585BC2A5700FB7E78EC79B97F440FFD7D8BFED7A614AAABE8A02F96733C04489
+4AD85C7D0A16D149CCBBEF1BFBF4681C8997D4B082BF6C23865BFDE1572BF747
+D563A7CBC031FD1F31F87AB0360A3A19A4B0692DBB21D2870B213C2579A0468C
+2C116720B51C9C05FA21C8926FB5C56C9A01592921EA6ACE28083A15ABFA09C7
+F26F6718B5DD19C49136BD67889D92CD8EB170A390AF147CD77486E02AFBA609
+FC026062588F302DBE927C81CC7181FEB421C9BD6F7EBF384351A76FF78F3FD0
+CCDE2DA3A920F1E3ADB898C5F6FB17C1A2C9D916B150BB8D47E3F454FD9F5E6B
+91AF2AE713B7F5699A87716DB11ECEE2DF4FD6AEA2338B4AABDC2AA4D5F2C3D1
+95628214615DE31B258A69DCC8B0439D3834E704E4CA690583C4E044FECE3EA4
+D2FAF665D893A7EFA74B37CAC3E6B9531D45C26ECC4B563F6052BE495D2F15F3
+F4E243BC1365EB9C5D324B339B47589B835E74247E1A9880E689032D74C97D19
+279A2DA845E3919355FF5473C3B63556A627A8062EA281BCACA002B910E513DB
+E10D4487A38A21543F1BA8039C6832B40599D0E6167B7B3460D74BE10605EA47
+3EE399C32A1406704534D419D26E15E8A66DDD88B7B3BF653D2BE8FC63CAD30A
+FFDC877FA3A3E7E1A23CB44B70E7E203DCB586D7B81D1E3A1C1E500FBE3DEB6F
+BF80C00DB97BB19DAFC0FB38270822331035AB82BB6B43D12B9CC5B0076AAA04
+560E62C55017054BF01441F2DC393F44D1A4F37584D929EF7E0B801D4F5D1CF7
+C0E8A6D6BA9F74051E614FA33AB7F00DEA6F138D03614573460D878BC25C3D72
+07EF46D27D26F4755953ACCB841C30ABE706C4A28AC01204A6756215214361AB
+E929409274B089DA1FCA4BF9A6FB7CEE925FC86FB1C4C018403204B1076E1857
+B81233ACF6920D29DFD2C5E01310D4B41A5DD73E9EFD409202D87EAA7465F15B
+2FEF5FAC46E012F7218982BB213A006B7756CB42A37E39700DA1961420E9FFAA
+2FD4295D243A79ACA04E14729EE32B4B5E38F419FB1C4450C072B7F228017A94
+118EEAD4DCF50896EB5AB380130E2E4C139C911FDE6036F6D1A36920CF4D8EDD
+23449F8BBD9E7F0572895C444AAC65743AF93639680E85C27CD4D2CB53D16CEA
+DFB66E6BCA776DA3E0B6722E64EC5951DB230346BE53B09EA0FEA4FCF8E86D27
+A190FAB3B3277C158357BB542DD8DBF741912884523C16982125B85BBC746E65
+3D0F0A1D7041383C4EED67B039674652D864F216B9141B6FAE8FE901AA46BC12
+6D815BE37692B5CA665004FD4D23F148652657A35DDD97652B50D2C1973CBA05
+DBA70EF4498B15541C27C528C081D492734D7C92F717A09EDE796C7986C5F3F6
+21D1941B2A183B6D34B3695DE39527EE244B9533ACAA37805E79879810048820
+D46FE34A3E25E1BADAFBA9F606B07EB20FDDA9775DFE883AFAA932088BF0CF68
+DBA888D32E2CC0D3DC135DC5F537387E91D85B860F5FC7C268E7BDCB58BBBB4E
+49114D3EF54271517E762CD5B38A43AA96E2CB38EC43BDC408B2BE858019C731
+6266C735623E072450A46DB7F7100E75A52A6DF1C9034732268699EC5D5DB448
+2B6CD8CE5508301801548A13E7192AB4C860D218A8B9197486F4393C9D1F63A6
+23B74D2709C14379B2CF6A03C9078A49907D6F3D8A77103F0907D0B91AE09BAC
+EF02774D74FD2A7B5FF5457F0C9EDB1AB6FA13232E1A2D7D9F135A7DE264857E
+2EF7A190A73AA423042F8942E3E91A0E7A0A305201366693CC35F9517DC38B7E
+B24E733C6068666C782C8D41CD27CD463559449A3BA4586AE7D07146FBE9EFDA
+BCD23880A5CA2C1D45E07B12B1FE4877074B4BDD05F24B54307B736B0FC49AFF
+60356E954E33130A60877DBAEECBCCA5619E5447FBE42C47AFB9B4D379690BBA
+60BB3B6763BE9C12F3C05CBFE973D5D0D2F10CB0D75F6DD3A2875D200AEC5DF3
+99805230170E8341F297E1C8F4CA0B72F6C4B4DD5808A658309DBF3709FC7F7F
+B60BA3C59C1DD179348413107B935550DAF2413778CE356EA8F34DC3E7D64E23
+8918F6EACCB7B2E80AA9180EBAF176B14313DF50B522AE0B0D7D243B5CA08033
+507DE4F93087EE6F4C8FBE31D9C689622FB66F260CD29219EB2DF4C649B111BB
+AA0E26AFB6972DF09FEBCCF00248BE2A7E8029BA08EBCE8A7B0E1CF310F74D24
+100E8E5D51CFAFF984610A38CB1095B89EE7767DFE323E476B69E4800391B44A
+5C51A7CC2C94200A5AB216EF0EDE3C26252BB664802D0858E722A8FDBEF4688F
+00E5D12E69D5963B48AC1A26355AF9995BD566A6EA68675C5A0CBF7C179E297E
+574993035D0B22B7FF7DA5717310707E6832696FB4020D0BAA41F247AAE332C1
+80AF204E5972B4D399282C06BD1D6371F6CE17635A70339AE79DC85681D25B2F
+67EDB43C4310BA00C6DB8C65F2D277D10E96EA4C06FA24E4D252E0144DEC8FB5
+18EE43D5C71720E83F39B4B400E8787189ABCFF863F2692AFCE4388B41CDB171
+B148102A5F4A50BB162866644EDCC4C7E6A615FA4B73FE735EBD5BB4C8B2A72B
+E47ABF1B0D5EA995E28FB0F758E4F484B5227BA3E7A22F441122BB1CD07422D8
+559CCBDB9D17068D0ACA47795E76CE25819875027FE4954924F7023216F1A526
+75E0DBCDBA26AB40B39C740439B5643268E7B533AE8E4AE23DFDA57428AF1E95
+33872479E12DC1022205AF91184D566D8C8A2A10F08E6475307A3E39EBFCFA38
+1A11C110AC615378DCA70493B05837F5DFC80498DB0B8546B8A5D64B48683831
+3CDC5B4E301CF298681CAA6D3AE1DD97113CBC7D009FECDCEC0D7F7A3D774DE8
+C15EF3AB6F520C9C14BEE41D57D352ECEFAC66FBB95815C8626BC59A20068401
+4E499E9388D5AA912097891EB8793F0A231478F9759B69C58F64E1338C00D12A
+58BD7DC5A5164A287AE82301E96EC471F69EE38593C6D8D10107DB36728DEB2D
+15E7D16DB331890DFB63A7328A14E5583C303F4AEF34A0FC41E0388E09126ABD
+C9E2C2A7E1770EE0F894B8BBF22B4AEFE3E35B86AE9F7A75169EAA24FB17CFD1
+C14ECFC0302AED2198ACDD642FF224DB45F96CB869C856FB51D6F2739F6C6D15
+5740E9E4515DA13460C6330710E62BF93E65E4730BFA48BD01C55D78C616484F
+D200AFAA5F1BEB2BD962E1D00FC806DFD6CE3304CF661B139BF9FA18B2222CA3
+05F26D43C3469A8856D4FCA1CE3D400FABA0B6EFEF31E077F1C08022388E17C3
+B82FF34A1EB9D25F9A7D930310A6DB534564CF7EDA5CF9032752A3E3262438C7
+B16508E739F02EFB5A5651975A08C494E53872B6CD97AD868259EF95F3A4054F
+9DA61DFAC94722F68A242B0E1278FEFBCD43F21087A82FD0CD09CAECC7FB4F3C
+FE441938379EFB10D45E41C6E63DB2C2876810097200A1D9057F861561CCEEEB
+0604AFF0DB4EA4869EA9FF6E7CD8F930A8DDBF82C800BE2626F46FD93F361D7F
+9A3D3C138AC8B12CFC4734851697CE8F1673D8D43DFDD3AB2DFEA03B2C06B565
+72FD751653A3DC6DDA4048760A1A4443903F3B039C2268220F2B580570A302D6
+751FA82C884669AE49AE2A6D1EE377B96D125B47EE3E7DF66C33542A70ECE4DD
+67F35081E2CEF1D28EED41A53EA61013B5C433B39532135352F2A94D59313328
+FBE57D6FE410E64B1E846B03FE0A30422F4E5D5C8146128BB4AA8C2C630B9499
+C910C05D206610438F4FA65DAD327282E3C58C3957101B20AFDBD864581875C9
+DE2C3AC55C343137BC4D1B909629A2EF9135EC4BAC0BF29018A82A0C84142457
+1F71A2A27E2D9484AA47784EB92EAC52573900E14F6925721406FDB8F9A2FD68
+ADD352B5FA039D2390DFF4E0F72A078931A750411E9E035053B457E600314660
+B50320B70934D4E94E4D3B308D7DBC2388A77FF084DD83F8884F309ADCF4EB87
+66A7CAEE25C6E20824BF2C76068850C2B5FCBD07BC7CB7B4B7BC0E46A4092E08
+2867CCC3184B02C3F04D18121275F250FD3E075C7A3810734B7D9ACBD4AD0D1C
+DFEBF5037B035F0B74378B25F367DBF7C26E489B06E024EC80B473217B54C24B
+D0F998E21732CB608D2477EE18CE7CE18FB417C0790B16BFB9F892033B97EC54
+BD85AB9344F1BAB2A9BFA8DA80E33D589256F43A4257FD46F37C2F0592A48831
+3DE6049C649ED4FA4E83A8CCD93B2247146F20D01018924FA8D188B03A5D3B44
+413DB76A508EEA254DA3CEF3B03C0E624264A9E9D572ED479C3FA76FEDA23D0D
+9887AD60469474764EEA04DD4B5DAAD669C14186D9678424A091D0FEAD822699
+718F7D23B05076DED3C883404712226EB7E52ABB3DFF9FD907B4B5B7665A9865
+1FD41E0F66E70B5CFA97DB81151B96FEB4B33A09720199082B46BF9C6E715C2B
+D6345B45AB3F553D3F20E7D19CDE669F858ED0489DA8A09A3A95AF704F605176
+3163DDDAF1D31B22DF8A5BFB4C0EBD69A6BB12C2DC74940E1BAEA5D954479566
+029ECDAB26EC6D15DACCF75DCCECC4386DB0D86D2802726822FC04E6C676B7F4
+3589EB5E53B57AFAD12C29B777266E0714FB0FB476CCA6FFA25F713CC5E27BC8
+786B114EE2327D16DE9C0E0D42D018388D2F7B940279726ACA3ACCEC31F0852E
+9EFE3419CB37660562658CF54E7843B8D70D62A7AF1C812017E7C826E58F3EFE
+AFA779379127642BE0A60705400EDB133CCC8BA30965D09938D22C267D064296
+85DE334C38DFAB31BC4F0CC33D8F3D93EBF3BFDCB0C43F77007B9C1E666C6713
+DF254F5E19F655F8EFEA367E10BE74A282F909989D865C8B6D52D39B114A729C
+A7F11D538920E61DF08EB89A48D59FDBCF4AEA67CF8CE990E1BAF5AF145CA80B
+81C16BDDD9B2BD1A6B153137930D69ED680EA892ADD867B393F6501EE5A67316
+DB3665BA3036321743415AB1A784A9D1464E245AAB0F9EC455254FB0DF049DC9
+B83D67D7947A3FCA600745E4696190800752BCF657B656C19AFDE528940B059C
+56B09D9A5D692576A746DF0214F0F8045A649351BBE92695C93866C060031350
+9A85807EE23FAA86CABAC8C35EE8F8F87430298A9B2890DBFE87E520120F3D9F
+25F4076B09619B7CAC6E1DA280637862B87DA391DAE17A768B82798BFB40FE82
+72D6F288B8BC577CDB1D0E907729312C7F412FA1A6B568840B04B7F0ED55DEA3
+71551E02D3451ADD0F0D46D697C7CF1CD8A6C4A372D11B4CB39A435CC350FD01
+434914C1F9EF60E2296B5557EFCBC15AF21E4C82D9A52B0763128A6A9CF83D5C
+F7C5F36B001C5E77C00ACED958E35AF237C055E27F26ED00FDACC250E8716574
+D50B9DC810293430695F4D9270B981081E49C47A915B42039DCB36D3CE5555FC
+26FCE46B2D996CEE6AB80454CBBB35F9F53A4E939C82BCF2477BA0AF6F88E574
+D83B92F7081B0E1F5B0CCBF6BF9675AE7B9DBBD107120481737D28E2FFB6AAB6
+DA6601EDFAD88E2BE75C12569E4B8551D4869DC5A36BB6E2AE00E1E141DB4A43
+A6B4A90A334BCBACB678FCC647D25BEE140449033160EC5C363F9E575618C223
+ECE6A79C1EB76FECA1578E151984914439AEDA51C3E86167E3D63552168B9B8D
+E77901E3291E2C4DD5376F051EABC76D9127EE146B8BAC22857914B71D77475F
+209F54B80B5F55A9D23913B5002394A1526B9492FEC352B05CE461F71C8CE490
+47D9796810CC96290FDD9BE5D4350637F6F8C8870FEFECEED33C129FC5CD0602
+BEE07534E254D181C89AEF245AC1D1BED915F4CDBB0B9B745B82049FE6762D6D
+1E4CCE1886C823947623FD46E39E957B3CB503E93596921E75F4E8181B799D6A
+277B64201D325B280564BDAA7CB7132F16F48EDC386E5285C1A5E3088EA7647B
+92E39EDCDDEA3D554E3406C6E411C22313033C7AEAB9E4DB2A1A1A4B03F75D0D
+C8F1B5B2E09B2C22FF062BB1F017BB7E383D444F6530B487BAD96C594CCB9685
+C3C905398225E045A40F86717AE3B78234B3774D4B445EFBD95C26F2CBD98EA1
+C95A2A88D21B4415A0DF1A724385AAD2115CEEC3EA9AEA9203ABDD304388EA0B
+7C3B76DA1382D38AF01325D88FF9168028DA9353BAB23F67E960A5428F3107B5
+5CF7221175F1810BF0D07343BE59584B6D06F9D9B5D171F1D6BB167B020C5039
+C36EC1CB1AAC41773065BC7991D712ACEA5D7F627B02611FCDCE21711EC7EC74
+AB0BFC57B1CCED1884BB9B18868A2053AF58F621016AE639ED6D58EABC42FF0F
+A5F76685634C85F3BAC77EAB39C23707518CAAFC7DCBC9F9D27B8BE49E85D335
+4A74F0A8D93CB7C2EC5A9982804BF24ED1832C549EC8B2AB2B1A212B14E04F26
+BFBF1811C51029CF134633B62E08C3F88C615157DBCC5D336057548711630253
+C97F950490F0A2479405C6D88896D9715A139D0D365EEF1F65254616DE309AAC
+8C708FD30001B3AB61A07630C8A5ED420D286442FFB6729DF0BFA47BE2C87480
+62BA997499C1CA63131F3AEA492C2292E8F1B87011932640FA023A1C022D98B9
+2397BF2C01709CB33B012E69B928ED9E78B5157CC3A5E6F504267421EEA08A95
+A5B3062D0AA95CA6411F51C3ABD548B82F47D3A759B3B1C5D8F8A227BA4A23C7
+77B7C36721C2DAF57426DD1A5538DEAF00B432D8E839C15C33B2762320295E2D
+CDF4F1277FA2319433F4249B246D4BEBAA57DB6378C96576881B855717AD5BE0
+949882C4BCE64C7E037FD8161CFBF8E7212C23BAF8C9CDD6E194483436B69C59
+CBE7AF01B041FA9507CF9EEA2272A8E90F4E8EE8D0EE8BE355369BABC289855A
+10A2E0C23A146E9394BAAD955E6F55E44127003E6976DD267BCFC1BC14130D1B
+5841165507F65D0599FA44E81329A04EC5B71BA7D4050071CA65421C0457D6BF
+F4E361666041C197E2594BF098E6AD3212A1075DBB2815903464E2070A54ED33
+C29B0B92254C9ABF5AD9A8B92F050D2B02244B09DBE3AE43920A0714CCFD525C
+C5E5594E3E1B6C58AE380F3E680B96127F48C00A5CD25D09A4768FC25E0FA213
+5662DDEA45A533F68B0B77E7938E03C304927D597C9925A925BEF5762DBE6951
+2FB9C0D5E9D85704B2762D3A8E49DE2920E533A2A2B3A6B5910D0210D51B77F1
+D4A7CCCC264DCB4D138E4157F9931A376785A4963EC4754BEE642C6A9953711F
+9235407EAC877A53491706029B42562370A3776CD6E00664291BA8253644B031
+8C1A997FB81F7D88B33D51939C7AA6833BE8B9E22BFE9960897299C357CA4244
+A0F42A92156CBFC0C46E9F76C9210239D9B116BC8F0D1E024FCF879349137D86
+10AAB7DF3EBAB12F3B087076146D0B4E0800ABE190175F877E67037E1C4D5DD2
+B1F53957CFF1C51C349248F68FE367E451E7685F104482D3B9DD4D7930E63CAB
+E8A97DE032E9B4ECCB6744C2FF3A796530603D9B1645A144EF9B78F832EF35D9
+5F04CA48482BC44B56626F80195C2E34D5ABB6EC46B5CDD1051B1121C06BD2AE
+633FA5F7EBBF4C54C9FDF19ED3165B0E176E3DFD22B2CD6B9376CCC6C862A13E
+3A7316D6CDE2B598F22D3D3935A888146BA654907EFD4EBB93E16C1691127ADF
+44D0D01061E29E58D102A537C84A694341595DE48E29D2928F067B7091C0E711
+68EED7D9FE14B3F495CE41BF7BC7CCDBFABF97D8C9FA5FD21604698A1C8700D6
+692774BF8A0A723B868BF8E80F82468FD097639C571C3A0EE0C154DE9FB11B7E
+89979087BED793DE89F2B4B3C6A267E4FE3C8A02EA38847E2A4CB03E2B73AACE
+332836D739D1C4B14C71E5E5E110DE20DBDCA5916E4E33D1B5037B55F991FD0F
+12B91E669A6DBA12DC98B4CF9E160BAA103BBA643E25275BC32BFBA19AD5401B
+EAF813FAC17F67B0B9F222D03A080813DC68EFF4CF745E42A0423A3A76A639A1
+3C1217D84E62AEB0495FF3D9F9557D3EEADB4CF622232B6AE4FE2DC7A95AE179
+6788BCEE6421FDF76448F0462B79F1612E83774EF10D5F62A5A275420F2E8590
+3EF5ECFB398574DDED563876110507B87067F349E123010D781F9ED5EDAD8F07
+443E8F84ADDA31121DB3D1414B540ECF9897476FD351A6EBDD5490EDDE270312
+0234293E6B8293830F57F1B8AB65EAD8FF7EA3F0A3E02C38F927318FC492105E
+F2AD9DB49BD49922F6F54B21DD1E5B8885C19424927CE4DF58754DD387A29CF6
+11E2CC20B3B726B22A0D46C709FFEA147ED78FA7F874119B11D63CF78C54F6C0
+E77AEB656B5F3318531CEF393C1860E69AE5EEB179C2C8E01E10D2A594FB29EB
+B9F897CC3A7F0C3D9022D80197166552F2BEDEAE8459EB15821A9CE4CC97C7F1
+3E588FA18BE5FE27953BE6E6C754E0C25BA394A62888B49B636661C69B5848F8
+5E6F9C5516928D6C2BFE046A8E6E9DC127CBA203391D1DE19BFEF942A07AE4D2
+5A6AADE9DED198F55D0E2BCC220C64DADDEDFAFF96CFC4A4BA1AE98605E81E66
+96DF11D0DCB551701A4B76C64A7601D3B1B2C0A558F04FE5289C5EE052EED2DE
+D72459CA00DD31AFA2AFAFFE05165E51D29F93C27891AA3829286C5EDE807583
+D1F6B621B7BFC9A0158F6EEC63BD5FB85215891A22B8ABCFE02A1412F34A4B50
+6C85476ACEE743051AD048FA3733791A0BBA0CC7A980E04C6845E8F771A07F0C
+81BB3D93EE17BB943036396179D8118C00CA7BAACEB386B7C29D555A2AE07162
+6BFAD2F69AB89542C2F3C1A1877B8D44EF6631AB459974B4987D4007C8CEB06F
+D226E0845E190A170D2C8A84A579D9D171EFD7E29CA9B31CD1CD3CCCC95C1FC8
+0625DC4C76F91E9066BD5E6094CE3072AAEF99DB5E6E10950FC342FEA8777404
+ECD78AFA3565
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMR12
+%!PS-AdobeFont-1.1: CMR12 1.0
+%%CreationDate: 1991 Aug 20 16:38:05
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.0) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMR12) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMR12 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 46 /period put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 65 /A put
+dup 86 /V put
+dup 101 /e put
+dup 105 /i put
+dup 108 /l put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 114 /r put
+dup 115 /s put
+readonly def
+/FontBBox{-34 -251 988 750}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5CF4E9D2405B169CD5365D6ECED5D768D66D6C
+68618B8C482B341F8CA38E9BB9BAFCFAAD9C2F3FD033B62690986ED43D9C9361
+3645B82392D5CAE11A7CB49D7E2E82DCD485CBA04C77322EB2E6A79D73DC194E
+59C120A2DABB9BF72E2CF256DD6EB54EECBA588101ABD933B57CE8A3A0D16B28
+51D7494F73096DF53BDC66BBF896B587DF9643317D5F610CD9088F9849126F23
+DDE030F7B277DD99055C8B119CAE9C99158AC4E150CDFC2C66ED92EBB4CC092A
+AA078CE16247A1335AD332DAA950D20395A7384C33FF72EAA31A5B89766E635F
+45C4C068AD7EE867398F0381B07CB94D29FF097D59FF9961D195A948E3D87C31
+821E9295A56D21875B41988F7A16A1587050C3C71B4E4355BB37F255D6B237CE
+96F25467F70FA19E0F85785FF49068949CCC79F2F8AE57D5F79BB9C5CF5EED5D
+9857B9967D9B96CDCF73D5D65FF75AFABB66734018BAE264597220C89FD17379
+26764A9302D078B4EB0E29178C878FD61007EEA2DDB119AE88C57ECFEF4B71E4
+140A34951DDC3568A84CC92371A789021A103A1A347050FDA6ECF7903F67D213
+1D0C7C474A9053866E9C88E65E6932BA87A73686EAB0019389F84D159809C498
+1E7A30ED942EB211B00DBFF5BCC720F4E276C3339B31B6EABBB078430E6A09BB
+377D3061A20B1EB98796B8607EECBC699445EAA866C38E02DF59F5EDD378303A
+0733B90E7835C0AAF32BA04F1566D8161EA89CD4D14DDB953F8B910BFC8A7F03
+5020F55EF8FC2640ADADA156F6CF8F2EB6610F7EE8874A26CBE7CD154469B9F4
+ED76886B3FB679FFDEB59BB6C55AF7087BA48B75EE2FB374B19BCC421A963E15
+FE05ECAAF9EECDF4B2715010A320102E6F8CCAA342FA11532671CEBFCF38BC60
+5BF06A0E01053B7F105ED5140FA4FA37A4F45ABFB58DD41780629C7FA7594F8E
+9488B074D45BA0E761190A94DBFF4CF204D5812EB1DFBC0C456D6A044C558945
+8DF6D6AF8A51131AB5913EF2544E475F489FE776FA45E7C0EB62096CF4517450
+8A57DD2B80EF97DBD17036EB9B73FCB82DC4F671BCFEF06A6F86189A2012F53C
+E518466A9385D08942279391EF5C2B3567F2E53B2148AAA0625BDB358ECD2C9B
+730A59F8DF70FD3E09378E24AEE772A69C96E09C0D0703350A75F3843DEDD822
+B364988376CE8027EF12F0453575AE9AE46296E13925BACECA8B8808DA388222
+BA35B431F56BC3C349B8CA6D4AB83664A991FED51478BFE25B0399B54EF27B18
+65E2E39E57DFC5F57371FB4643D7EC0AD41840CA7C682EE7A1B4FE3E06E40238
+B07A2E7A7FB3F35502F1CCA283F9420F2FAB9EC0A8C8982BF4AFE69A3D2690B3
+CF5DB716B3CB9936C49A12944973F14C2D9A368E4067BDBF91E413A3321B3BFA
+B84463D3C680604A4C4E4B49D0F9F9B59D5B68ECD3891FEEDE9B29B9C432212D
+82505A8D423BA734A53DEB930A392BA6011C6EA6EBA7ABAA6AAC003721FB34A6
+1544EEE16F6AD73E6C5743EFF09975C186A9C769A4732F78AA09218AE576FB14
+70E1697B813AC1B09FFAB762678BA9320043C256766AF1BACD3702CED1228B94
+57E353589810F99AF74109EFDA0740CB0475DE7870AA7218120462B23441BB1A
+60ACAF3B8B171E7509854D1C05C8FBF62979D2B52030B4C91F9D038EF26F2C11
+346D0E9955B491C3168E030B9CCE2964883B824F0DCF27EECA6C6E0478CF6B36
+AF2D33C9265A5F8D76FCC46AA30E6093E3822CE70C1ED22CDB8A8F910F5BCF45
+2C9D2D41B342B43DB5FE5EFCFEB5D378F78684296CAED9A39FC3834929073B6E
+A934014457B89A61253E0924D3C6BB4FE4ADFBD0C9B3C61D08E3DB2B26785A1D
+3B5E0E23258AE12276B63E9D79B2EAB305B8108A0987216C0EBF033A839BF611
+CB208A97C18AD434B4AA716C57905AF301C24DD78EC659F2398D46BAC7C30682
+F7E21FFC8370880EB1C9A98807FB05BD23F160F1567070B644C2C0F08C981C81
+3D472A623CBA7ADB80D118D51BF4F2D139CD7F27753F38007D4831760CD2077C
+23643D8F0C038E949E11415E9C570E6CBEDBB60B480B9892731D073C3357902B
+40415292F69357C1AA0C94780336DB4702E659DF67225B2B25811EFE3FBAAA3C
+E06C49CC4591E5E347925A62079C501D27DAB6205E3162D86152476602386329
+0476AB5766DBE6936974CA9B133459886FA5FF402BE911036A9CA31BB71B6C92
+01E5270681E15AC6F3999C114610B08B91FD22B4A4843D0B90276EC2F4FC347A
+C814329239DB5C15CD43DB9A894C666F5121D37B7C6428FF061CBE3974D78B54
+CD74069DCD42AF4734AB5D4239AB83CBBF751DBBD320BEEAB8F31B6036CAC31D
+99C15FBCEA633DA4CDABC8FFEE5E634766C00D4CA8D81F7205A77EC394486032
+57C8547EDB7FF10B3CC9ABB2BCBDD51E304153DEF8BD8EE3591005CC1013BB68
+B579080881221360FF4A62C4D5235D9EF35E09BB44FEB0E41FFCFBF4F654BEFB
+D273339665FAEA9167AE154EC7243623D74A9D2A60883D948DB4127B11F95F0E
+2F5ADB3DDA9D8B9EFB7D32096C0562E81868F9B8277ED54053A37E9EA94C922D
+C42F22136F3E33F63D819C4F8424ACD9C868CCEEFED00274B00A825E61837A2D
+5DA162379664177CFBCD0D4CACE49044160B5275684CAD4C336B730FA4CA49B2
+BC2A450D504857287F9D575884130AEB50F8F14B153C615CA8C3D2AF1EBD84A3
+F158F2EB29BBD92095A15FFE4C6F40E06658A3A52B61EBFE9F3EE3F7E37AC477
+BA24CD27BBFFC121478133B200731F4AF2032B6B6D4F03D113AD8F2391DA0DEE
+27653D82D4838E4CF541CC922E141153BE8DD305D1F89C753180D11DAF0C792D
+56F3674DEEEEDE6494EF766D2453232DF32A80DE36D626594CA73E0F5058B571
+97CE052CA8364A3BE32FD595306A7177DF9BBA06B1B670BBF54D49446E913E64
+E630478AABFCEBEDCA6BB1B1C8DC776E6E253D163DA2B6EE9E5C650F0E172EAD
+A2082D2C14CC270C7E08D213BFEE4596BA64487C447528013F4015A3080FEC41
+DBC11EDBDDA0746B228F45AE86F0A4DF2CEDF61602E7895F3CE32CE145756822
+2E9629AD492BE60B91A0EFAFCD3CF61F019C134EC31A31B61715F7258453E321
+10D09772F56CC4B267D7773BE2B2836C8882561DB6B76E1D40BA3C5A8745D6AA
+ADF93F52BC563A6E27C5456D88F5861DD4E674B4046FFB51B1694C593D3A7D4E
+E9C38ACB2DC0102AEB761556EB9C3C71D13737013D4AD5825FCA260C52F34370
+DB85657F23087DA39702E64FAB15079224B181E9B6C45207DD6271F5F88A0F8C
+3984186804B501D5F0B8EB83C9ABA185AB12A625A364B35857729DFC9EC85908
+0E69DBC9DB97DED2FC244C5386AB7A5DD6C2F6D7B58D00BB3397E74AD5339E8F
+C901FAAEF60492AAACF12C8FDF612DFE5383F98D49BE25BF19E6D21BC7AC3C1F
+857497A5909CE313DA186A628C5437BCE75EEF0144D444B3B9213975D86FAB42
+BEBD3B979136CA744374DC7047970A85744BBC7B15ECA6298819C3CFD43E2F5B
+66FB7F7EF295784CF4BB97EC59C232BB33507366DFC3FAB358B45AC3A1A41F66
+7511D9E06C0D1058A3A36FBB63A6CB58E2FFCA728B488D00FEF055B194963716
+F4C638CD29B7B266C55714EC054CCD7FC211C6989A7DA04429CFA85F7A48036D
+5B0C0C7448CAE051D9B40D9D5FC7CED07DBC1A729F5EB884A07494FC3CD32B25
+C056499909ADB2C51C1B716593E71DDFA245C6F061FA75C47BA92BA3AB974098
+4C597BF9360A45DAB32CED234C3DDB4F087295B191BAFA8601FA938220A208F8
+7E69991199BD1AA04CE35AB4485C5D3F778ED3D98F7F7D60606BADBB9BE61A81
+016CC2AB7F35D5F6C46CDE336F260E46F09BC0C8ABD019BEB8C2BCFC1492D5FC
+2E5D7096FE60880690C7029E848F290AEDB43E2DADF66135CCF79C63FFE522C9
+0A9F283C9CC4B5D4DD9982360EB2F3E07B0FA2E9A9790249D811A3DA5A27239D
+E581D249898A648CA8E33C7273AF4D846C1FF578FF809782618227B2533EB859
+40E2E3BE6ED0997FECECC84404014E3CD692A7CE3967C905B6C7CDE743EBCF5D
+001F22C147C8F5B58D2C6FF35599022A8164F83D85172C5F294F0EF3F7EFCD42
+9A5F91890146261D37F2213784AA79FE9EC56CFFE4DA2CC29B35146F3775E714
+31F07B6673ED2E2AC1
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+TeXDict begin 40258431 52099146 1000 600 600 (cfitsio.dvi)
+@start /Fa 138[49 30 37 38 1[46 46 51 74 23 2[28 1[42
+1[42 2[42 46 11[68 12[68 3[69 68[{}17 90.9091 /CMTI10
+rf /Fb 193[71 62[{}1 90.9091 /CMMI10 rf /Fc 149[25 2[45
+45 86[45 15[{}4 90.9091 /CMSY10 rf /Fd 134[59 59 81 59
+62 44 44 46 59 62 56 62 93 31 59 1[31 62 56 34 51 62
+50 62 54 9[116 85 86 78 62 84 1[77 1[88 106 67 88 1[42
+88 88 70 74 86 81 80 85 6[31 56 56 56 56 56 56 56 56
+56 56 1[31 37 32[62 12[{}58 99.6264 /CMBX12 rf /Fe 129[48
+48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
+48 48 48 48 48 48 48 48 48 48 48 1[48 48 48 48 48 48
+48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
+48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
+48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
+48 48 48 33[{}93 90.9091 /CMTT10 rf /Ff 133[60 71 71
+97 71 75 52 53 55 1[75 67 75 112 37 71 1[37 75 67 41
+61 75 60 75 65 9[139 102 103 94 75 100 1[92 101 105 128
+81 105 1[50 105 106 85 88 103 97 96 102 7[67 67 67 67
+67 67 67 67 67 67 67 37 45 3[52 52 27[75 78 11[{}62 119.552
+/CMBX12 rf /Fg 135[102 3[75 1[79 1[108 1[108 4[54 108
+2[88 108 2[94 29[140 138 146 7[97 97 97 97 97 97 97 97
+97 97 48[{}23 172.188 /CMBX12 rf /Fh 165[56 68 68 93
+68 68 66 51 67 1[62 71 68 83 57 71 1[33 68 71 59 62 69
+66 64 68 7[45 45 45 45 45 45 45 45 45 45 45 25 30 3[35
+35 40[{}39 90.9091 /CMSL10 rf /Fi 133[46 55 55 1[55 58
+41 41 43 1[58 52 58 87 29 2[29 58 52 32 48 58 46 58 51
+9[108 2[73 58 78 1[71 79 82 1[63 2[40 82 82 66 69 80
+76 74 79 7[52 52 52 52 52 52 52 52 52 52 2[35 32[58 12[{}51
+90.9091 /CMBX10 rf /Fj 132[45 40 48 48 66 48 51 35 36
+36 48 51 45 51 76 25 48 28 25 51 45 28 40 51 40 51 45
+25 2[25 45 25 56 68 68 93 68 68 66 51 67 71 62 71 68
+83 57 71 47 33 68 71 59 62 69 66 64 68 71 43 1[71 1[25
+25 45 45 45 45 45 45 45 45 45 45 45 25 30 25 71 45 35
+35 25 71 76 45 76 45 25 18[76 51 51 53 11[{}91 90.9091
+/CMR10 rf /Fk 140[46 46 1[65 59 65 1[33 2[33 3[52 14[88
+20[88 13[59 59 59 59 1[33 46[{}15 119.552 /CMR12 rf /Fl
+139[63 64 66 2[81 90 134 45 2[45 1[81 49 74 1[72 1[78
+12[112 90 2[110 6[60 2[101 2[117 1[122 65[{}20 143.462
+/CMBX12 rf /Fm 133[103 123 123 1[123 129 90 92 95 1[129
+116 129 194 65 2[65 129 116 71 106 129 103 129 113 9[240
+1[179 162 129 173 1[159 175 182 1[140 2[87 182 183 146
+153 178 168 165 175 25[65 26[129 12[{}42 206.559 /CMBX12
+rf end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+%%BeginPaperSize: Letter
+letter
+%%EndPaperSize
+ end
+%%EndSetup
+%%Page: 1 1
+TeXDict begin 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)54 b(Files)1263 2518 y(for)g(C)f(Programmers)1667
+3013 y Fk(V)-10 b(ersion)38 b(3.3)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)h
+(Cen)m(ter)1522 4255 y(Green)m(b)s(elt,)f(MD)h(20771)1857
+4367 y(USA)1682 5227 y Fk(April)37 b(2012)p eop end
+%%Page: 2 2
+TeXDict begin 2 1 bop 0 299 a Fj(ii)p eop end
+%%Page: 3 3
+TeXDict begin 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)h(Ov)m(erview)85 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)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(.)131 b(1)136
+2344 y(1.3)94 b(Ac)m(kno)m(wledgmen)m(ts)30 b(.)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(.)131
+b(2)136 2506 y(1.4)94 b(Legal)32 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(4)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)31 b(the)f(Library)58 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)31 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)31 b(PCs)f(.)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)32 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)32 b(the)e(Library)j(.)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)31 b(Programs)f(with)g(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(Using)31 b(CFITSIO)e(in)h(Multi-threaded)h(En)m
+(vironmen)m(ts)62 b(.)46 b(.)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(Getting)32 b(Started)f(with)f(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(.)85 b(10)136 4385 y(2.6)94 b(Example)31
+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 4645 y Fi(3)119 b(A)35
+b(FITS)f(Primer)2918 b(13)0 4904 y(4)119 b(Programming)37
+b(Guidelines)2482 b(15)136 5066 y Fj(4.1)94 b(CFITSIO)29
+b(De\014nitions)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(.)85 b(15)136 5228 y(4.2)94 b(Curren)m(t)30
+b(Header)h(Data)h(Unit)e(\(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 5390 y(4.3)94 b(F)-8 b(unction)32
+b(Names)e(and)g(V)-8 b(ariable)32 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 5552 y(4.4)94
+b(Supp)s(ort)29 b(for)h(Unsigned)g(In)m(tegers)h(and)f(Signed)g(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(20)136 5714 y(4.5)94 b(Dealing)33
+b(with)d(Character)g(Strings)61 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 end
+%%Page: 4 4
+TeXDict begin 4 3 bop 0 299 a Fj(iv)3311 b Fh(CONTENTS)136
+555 y Fj(4.6)94 b(Implicit)31 b(Data)h(T)m(yp)s(e)e(Con)m(v)m(ersion)65
+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(23)136 716 y(4.7)94 b(Data)32 b(Scaling)89 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(23)136 876 y(4.8)94 b(Supp)s(ort)29 b(for)h(IEEE)g(Sp)s(ecial)g(V)-8
+b(alues)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(.)85
+b(24)136 1037 y(4.9)94 b(Error)30 b(Status)g(V)-8 b(alues)32
+b(and)d(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(24)136 1197 y(4.10)49 b(V)-8 b(ariable-Length)33 b(Arra)m(ys)d(in)g
+(Binary)h(T)-8 b(ables)31 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(25)136 1358 y(4.11)49 b(Multiple)32 b(Access)f(to)g(the)g(Same)f
+(FITS)g(File)h(.)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(26)136 1518 y(4.12)49 b(When)31 b(the)f(Final)h(Size)g(of)g(the)f
+(FITS)g(HDU)h(is)f(Unkno)m(wn)k(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h
+(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(27)136 1678
+y(4.13)49 b(CFITSIO)29 b(Size)i(Limitations)42 b(.)k(.)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(27)0 1931
+y Fi(5)f(Basic)36 b(CFITSIO)d(In)m(terface)h(Routines)2074
+b(29)136 2092 y Fj(5.1)94 b(CFITSIO)29 b(Error)h(Status)g(Routines)89
+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
+2252 y(5.2)94 b(FITS)30 b(File)i(Access)f(Routines)g(.)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 2412 y(5.3)94 b(HDU)32 b(Access)f(Routines)72
+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 2573 y(5.4)94 b(Header)31 b(Keyw)m(ord)f(Read/W)-8
+b(rite)33 b(Routines)40 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 2733 y(5.4.1)106 b(Keyw)m(ord)30 b(Reading)h(Routines)65
+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
+2894 y(5.4.2)106 b(Keyw)m(ord)30 b(W)-8 b(riting)32 b(Routines)86
+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(38)136
+3054 y(5.5)94 b(Primary)30 b(Arra)m(y)h(or)f(IMA)m(GE)i(Extension)e
+(I/O)g(Routines)54 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(40)136 3215 y(5.6)94
+b(Image)32 b(Compression)f(.)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(44)136 3375
+y(5.7)94 b(ASCI)s(I)29 b(and)h(Binary)h(T)-8 b(able)31
+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(48)345 3536 y(5.7.1)106 b(Create)32 b(New)e(T)-8 b(able)84
+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(48)345 3696 y(5.7.2)106 b(Column)30 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(49)345 3857 y(5.7.3)106
+b(Routines)31 b(to)g(Edit)f(Ro)m(ws)h(or)f(Columns)39
+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(52)345 4017 y(5.7.4)106
+b(Read)31 b(and)f(W)-8 b(rite)31 b(Column)f(Data)i(Routines)66
+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 4178 y(5.7.5)106 b(Ro)m(w)31
+b(Selection)h(and)e(Calculator)h(Routines)88 b(.)46 b(.)g(.)f(.)h(.)g
+(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85
+b(56)345 4338 y(5.7.6)106 b(Column)30 b(Binning)g(or)g(Histogramming)i
+(Routines)74 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)f(.)85 b(57)136 4498 y(5.8)94 b(Utilit)m(y)33
+b(Routines)27 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(60)345 4659 y(5.8.1)106
+b(File)32 b(Chec)m(ksum)e(Routines)47 b(.)f(.)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(60)345 4819 y(5.8.2)106 b(Date)32
+b(and)e(Time)g(Utilit)m(y)j(Routines)90 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(61)345 4980 y(5.8.3)106 b(General)32 b(Utilit)m(y)g(Routines)h
+(.)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(62)0 5232 y Fi(6)119 b(The)35 b(CFITSIO)e(Iterator)g(F)-9
+b(unction)2154 b(73)136 5393 y Fj(6.1)94 b(The)30 b(Iterator)i(W)-8
+b(ork)31 b(F)-8 b(unction)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(74)136 5553 y(6.2)94 b(The)30 b(Iterator)i(Driv)m
+(er)f(F)-8 b(unction)78 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(76)136 5714 y(6.3)94 b(Guidelines)31
+b(for)f(Using)h(the)f(Iterator)i(F)-8 b(unction)45 b(.)h(.)g(.)f(.)h(.)
+g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)85 b(77)p eop end
+%%Page: 5 5
+TeXDict begin 5 4 bop 0 299 a Fh(CONTENTS)3334 b Fj(v)136
+555 y(6.4)94 b(Complete)32 b(List)e(of)h(Iterator)g(Routines)62
+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(78)0
+823 y Fi(7)119 b(W)-9 b(orld)36 b(Co)s(ordinate)e(System)h(Routines)
+1992 b(81)136 986 y Fj(7.1)125 b(Self-con)m(tained)32
+b(W)m(CS)e(Routines)f(.)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(82)0 1254 y Fi(8)119 b(Hierarc)m(hical)36
+b(Grouping)g(Routines)2163 b(85)136 1418 y Fj(8.1)94
+b(Grouping)30 b(T)-8 b(able)31 b(Routines)87 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(86)136 1581
+y(8.2)94 b(Group)30 b(Mem)m(b)s(er)g(Routines)h(.)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(88)0 1849 y Fi(9)119 b(Sp)s(ecialized)36 b(CFITSIO)d(In)m(terface)h
+(Routines)1777 b(91)136 2013 y Fj(9.1)94 b(FITS)30 b(File)i(Access)f
+(Routines)g(.)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(91)136 2176 y(9.2)94 b(HDU)32 b(Access)f(Routines)72
+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(95)136 2340 y(9.3)94 b(Sp)s(ecialized)32 b(Header)e(Keyw)m(ord)
+h(Routines)74 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(97)345 2503 y(9.3.1)106 b(Header)31 b(Information)f(Routines)64
+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(97)345 2667
+y(9.3.2)106 b(Read)31 b(and)f(W)-8 b(rite)31 b(the)g(Required)f(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(97)345 2830 y(9.3.3)106
+b(W)-8 b(rite)32 b(Keyw)m(ord)e(Routines)c(.)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(99)345 2994 y(9.3.4)106
+b(Insert)30 b(Keyw)m(ord)g(Routines)89 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)345 3157 y(9.3.5)106 b(Read)31
+b(Keyw)m(ord)f(Routines)45 b(.)h(.)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)345 3321 y(9.3.6)106 b(Mo)s(dify)30 b(Keyw)m(ord)h
+(Routines)36 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(104)345 3484 y(9.3.7)106 b(Up)s(date)31 b(Keyw)m(ord)f(Routines)c(.)
+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(105)136
+3648 y(9.4)94 b(De\014ne)31 b(Data)h(Scaling)f(and)f(Unde\014ned)f
+(Pixel)i(P)m(arameters)43 b(.)j(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(106)136 3811 y(9.5)94
+b(Sp)s(ecialized)32 b(FITS)d(Primary)h(Arra)m(y)h(or)f(IMA)m(GE)h
+(Extension)g(I/O)f(Routines)55 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)
+40 b(107)136 3975 y(9.6)94 b(Sp)s(ecialized)32 b(FITS)d(ASCI)s(I)g(and)
+h(Binary)g(T)-8 b(able)31 b(Routines)87 b(.)46 b(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(110)345
+4138 y(9.6.1)106 b(General)32 b(Column)d(Routines)51
+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(110)345
+4302 y(9.6.2)106 b(Lo)m(w-Lev)m(el)33 b(T)-8 b(able)31
+b(Access)g(Routines)40 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(112)345 4465 y(9.6.3)106 b(W)-8 b(rite)32 b(Column)e(Data)i(Routines)
+52 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(112)345
+4629 y(9.6.4)106 b(Read)31 b(Column)e(Data)j(Routines)72
+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(113)0 4896
+y Fi(10)67 b(Extended)35 b(File)f(Name)h(Syn)m(tax)2278
+b(117)136 5060 y Fj(10.1)49 b(Ov)m(erview)84 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(117)136 5223 y(10.2)49 b(Filet)m(yp)s(e)62
+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(120)345 5387
+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(120)345 5550 y(10.2.2)61
+b(Notes)32 b(ab)s(out)e(the)h(stream)f(\014let)m(yp)s(e)h(driv)m(er)54
+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(121)345 5714 y(10.2.3)61 b(Notes)32
+b(ab)s(out)e(the)h(gsiftp)f(\014let)m(yp)s(e)83 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(122)p eop end
+%%Page: 6 6
+TeXDict begin 6 5 bop 0 299 a Fj(vi)3311 b Fh(CONTENTS)345
+555 y Fj(10.2.4)61 b(Notes)32 b(ab)s(out)e(the)h(ro)s(ot)f(\014let)m
+(yp)s(e)68 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(122)345 716 y(10.2.5)61 b(Notes)32 b(ab)s(out)e(the)h(shmem)e
+(\014let)m(yp)s(e:)70 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(124)136 876 y(10.3)49 b(Base)32 b(Filename)90 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(124)136 1037 y(10.4)49 b(Output)30 b(File)h(Name)g
+(when)f(Op)s(ening)f(an)h(Existing)h(File)81 b(.)45 b(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(126)136 1197 y(10.5)49 b(T)-8 b(emplate)32 b(File)g(Name)f(when)e
+(Creating)i(a)g(New)f(File)57 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g
+(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40 b(128)136
+1358 y(10.6)49 b(Image)32 b(Tile-Compression)e(Sp)s(eci\014cation)91
+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(128)136 1518
+y(10.7)49 b(HDU)32 b(Lo)s(cation)f(Sp)s(eci\014cation)47
+b(.)e(.)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(128)136 1678 y(10.8)49 b(Image)32 b(Section)39 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(130)136 1839 y(10.9)49 b(Image)32
+b(T)-8 b(ransform)29 b(Filters)54 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(131)136 1999 y(10.10)t(Column)30
+b(and)g(Keyw)m(ord)g(Filtering)h(Sp)s(eci\014cation)91
+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(132)136 2160 y(10.11)t(Ro)m(w)31
+b(Filtering)h(Sp)s(eci\014cation)82 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(134)345 2320 y(10.11.1)16
+b(General)32 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(135)345 2481 y(10.11.2)16
+b(Bit)32 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(138)345 2641 y(10.11.3)16
+b(V)-8 b(ector)32 b(Columns)92 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(138)345 2802 y(10.11.4)16
+b(Go)s(o)s(d)30 b(Time)h(In)m(terv)-5 b(al)31 b(Filtering)62
+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(140)345
+2962 y(10.11.5)16 b(Spatial)31 b(Region)h(Filtering)59
+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(141)345 3123 y(10.11.6)16 b(Example)31 b(Ro)m(w)g(Filters)h(.)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(143)136 3283 y(10.12)35 b(Binning)30 b(or)g(Histogramming)i(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(144)0
+3536 y Fi(11)32 b(T)-9 b(emplate)35 b(Files)2933 b(147)136
+3696 y Fj(11.1)49 b(Detailed)33 b(T)-8 b(emplate)31 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(147)136 3857 y(11.2)49 b(Auto-indexing)31 b(of)g(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(148)136 4017 y(11.3)49 b(T)-8 b(emplate)32 b(P)m(arser)f(Directiv)m
+(es)87 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(149)136 4178 y(11.4)49 b(F)-8 b(ormal)32 b(T)-8 b(emplate)32
+b(Syn)m(tax)i(.)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(149)136 4338 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(150)136 4498 y(11.6)49
+b(Examples)72 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(150)0
+4751 y Fi(12)67 b(Lo)s(cal)35 b(FITS)g(Con)m(v)m(en)m(tions)2462
+b(153)136 4912 y Fj(12.1)49 b(64-Bit)33 b(Long)e(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(153)136 5072 y(12.2)49 b(Long)31 b(String)f(Keyw)m(ord)g(V)
+-8 b(alues.)65 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(153)136 5232 y(12.3)49 b(Arra)m(ys)31 b(of)f(Fixed-Length)i
+(Strings)d(in)h(Binary)h(T)-8 b(ables)78 b(.)46 b(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)40
+b(155)136 5393 y(12.4)49 b(Keyw)m(ord)31 b(Units)f(Strings)41
+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(155)136 5553 y(12.5)49 b(HIERAR)m(CH)31 b(Con)m(v)m(en)m(tion)h
+(for)e(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(156)136 5714
+y(12.6)49 b(Tile-Compressed)31 b(Image)g(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(156)p eop end
+%%Page: 7 7
+TeXDict begin 7 6 bop 0 299 a Fh(CONTENTS)3284 b Fj(vii)0
+555 y Fi(13)67 b(Optimizing)35 b(Programs)2589 b(159)136
+715 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(159)136
+876 y(13.2)49 b(Optimization)32 b(Strategies)77 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(160)0 1127 y Fi(A)57 b(Index)35 b(of)g(Routines)2789
+b(165)0 1378 y(B)62 b(P)m(arameter)35 b(De\014nitions)2598
+b(171)0 1629 y(C)60 b(CFITSIO)33 b(Error)i(Status)f(Co)s(des)2255
+b(177)p eop end
+%%Page: 8 8
+TeXDict begin 8 7 bop 0 299 a Fj(viii)3261 b Fh(CONTENTS)p
+eop end
+%%Page: 1 9
+TeXDict begin 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)i(a)g(mac)m
+(hine-indep)s(enden)m(t)g(library)f(of)h(routines)f(for)h(reading)g
+(and)f(writing)g(data)i(\014les)e(in)h(the)0 2608 y(FITS)35
+b(\(Flexible)i(Image)f(T)-8 b(ransp)s(ort)34 b(System\))h(data)h
+(format.)56 b(It)35 b(can)h(also)g(read)f(IRAF)h(format)f(image)i
+(\014les)0 2721 y(and)f(ra)m(w)h(binary)f(data)h(arra)m(ys)g(b)m(y)g
+(con)m(v)m(erting)i(them)d(on)h(the)g(\015y)f(in)m(to)i(a)f(virtual)g
+(FITS)f(format)h(\014le.)60 b(This)0 2833 y(library)32
+b(is)h(written)g(in)f(ANSI)h(C)f(and)g(pro)m(vides)h(a)g(p)s(o)m(w)m
+(erful)f(y)m(et)i(simple)f(in)m(terface)h(for)f(accessing)h(FITS)e
+(\014les)0 2946 y(whic)m(h)k(will)h(run)e(on)h(most)h(commonly)g(used)f
+(computers)g(and)g(w)m(orkstations.)60 b(CFITSIO)35 b(supp)s(orts)f
+(all)k(the)0 3059 y(features)26 b(describ)s(ed)e(in)h(the)g(o\016cial)i
+(NOST)d(de\014nition)h(of)h(the)f(FITS)g(format)h(and)e(can)i(read)f
+(and)g(write)h(all)g(the)0 3172 y(curren)m(tly)c(de\014ned)e(t)m(yp)s
+(es)i(of)g(extensions,)i(including)d(ASCI)s(I)g(tables)h(\(T)-8
+b(ABLE\),)23 b(Binary)f(tables)h(\(BINT)-8 b(ABLE\))0
+3285 y(and)27 b(IMA)m(GE)h(extensions.)40 b(The)27 b(CFITSIO)f
+(routines)h(insulate)h(the)f(programmer)g(from)g(ha)m(ving)g(to)h(deal)
+g(with)0 3398 y(the)d(complicated)h(formatting)g(details)f(in)f(the)h
+(FITS)f(\014le,)i(ho)m(w)m(ev)m(er,)i(it)d(is)f(assumed)g(that)h(users)
+f(ha)m(v)m(e)i(a)f(general)0 3511 y(kno)m(wledge)31 b(ab)s(out)f(the)h
+(structure)f(and)g(usage)h(of)f(FITS)g(\014les.)0 3671
+y(CFITSIO)k(also)j(con)m(tains)h(a)e(set)h(of)f(F)-8
+b(ortran)36 b(callable)i(wrapp)s(er)d(routines)g(whic)m(h)h(allo)m(w)i
+(F)-8 b(ortran)36 b(programs)0 3784 y(to)31 b(call)g(the)f(CFITSIO)e
+(routines.)41 b(See)30 b(the)g(companion)g(\\FITSIO)f(User's)h(Guide")g
+(for)g(the)g(de\014nition)g(of)g(the)0 3897 y(F)-8 b(ortran)39
+b(subroutine)d(calling)k(sequences.)63 b(These)38 b(wrapp)s(ers)e
+(replace)j(the)f(older)g(F)-8 b(ortran)39 b(FITSIO)d(library)0
+4010 y(whic)m(h)30 b(is)h(no)f(longer)h(supp)s(orted.)0
+4170 y(The)20 b(CFITSIO)f(pac)m(k)-5 b(age)23 b(w)m(as)e(initially)i
+(dev)m(elop)s(ed)e(b)m(y)f(the)h(HEASAR)m(C)g(\(High)h(Energy)e
+(Astroph)m(ysics)h(Science)0 4283 y(Arc)m(hiv)m(e)35
+b(Researc)m(h)g(Cen)m(ter\))f(at)h(the)f(NASA)g(Go)s(ddard)e(Space)j
+(Fligh)m(t)g(Cen)m(ter)f(to)h(con)m(v)m(ert)g(v)-5 b(arious)34
+b(existing)0 4396 y(and)25 b(newly)h(acquired)g(astronomical)i(data)e
+(sets)h(in)m(to)g(FITS)e(format)h(and)f(to)i(further)e(analyze)i(data)g
+(already)f(in)0 4509 y(FITS)h(format.)41 b(New)28 b(features)g(con)m
+(tin)m(ue)h(to)g(b)s(e)e(added)h(to)g(CFITSIO)f(in)g(large)i(part)f
+(due)g(to)g(con)m(tributions)h(of)0 4622 y(ideas)k(or)g(actual)h(co)s
+(de)f(from)f(users)g(of)h(the)g(pac)m(k)-5 b(age.)49
+b(The)33 b(In)m(tegral)h(Science)f(Data)h(Cen)m(ter)f(in)g
+(Switzerland,)0 4734 y(and)g(the)g(XMM/ESTEC)h(pro)5
+b(ject)34 b(in)f(The)g(Netherlands)g(made)g(esp)s(ecially)i
+(signi\014can)m(t)f(con)m(tributions)g(that)0 4847 y(resulted)c(in)g
+(man)m(y)h(of)f(the)h(new)f(features)g(that)h(app)s(eared)f(in)g(v2.0)i
+(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)i(v)m(ersion)f
+(of)g(the)f(CFITSIO)f(source)i(co)s(de,)h(do)s(cumen)m(tation,)i(and)21
+b(example)j(programs)e(are)h(a)m(v)-5 b(ailable)0 5714
+y(on)30 b(the)h(W)-8 b(orld-Wide)32 b(W)-8 b(eb)31 b(or)f(via)h(anon)m
+(ymous)f(ftp)g(from:)1927 5942 y(1)p eop end
+%%Page: 2 10
+TeXDict begin 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 959 y Fj(An)m(y)28 b(questions,)g(bug)f(rep)s(orts,)
+h(or)f(suggested)i(enhancemen)m(ts)f(related)g(to)h(the)e(CFITSIO)f
+(pac)m(k)-5 b(age)30 b(should)d(b)s(e)0 1072 y(sen)m(t)k(to)g(the)g
+(primary)e(author:)382 1362 y Fe(Dr.)47 b(William)f(Pence)810
+b(Telephone:)92 b(\(301\))47 b(286-4599)382 1475 y(HEASARC,)e(Code)i
+(662)811 b(E-mail:)45 b(William.D.Pence@nasa.gov)382
+1588 y(NASA/Goddard)f(Space)j(Flight)f(Center)382 1701
+y(Greenbelt,)f(MD)i(20771,)f(USA)0 1992 y Fj(This)40
+b(User's)i(Guide)f(assumes)g(that)h(readers)f(already)g(ha)m(v)m(e)i(a)
+f(general)g(understanding)d(of)j(the)f(de\014nition)0
+2104 y(and)31 b(structure)g(of)h(FITS)e(format)i(\014les.)44
+b(F)-8 b(urther)32 b(information)f(ab)s(out)h(FITS)f(formats)g(is)h(a)m
+(v)-5 b(ailable)34 b(from)d(the)0 2217 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,)i(the)f('NOST)f(FITS)g(Standard')0 2330
+y(giv)m(es)j(the)g(authoritativ)m(e)h(de\014nition)e(of)g(the)g(FITS)g
+(data)h(format,)g(and)f(the)g(`FITS)g(User's)g(Guide')g(pro)m(vides)0
+2443 y(additional)d(historical)h(bac)m(kground)e(and)g(practical)i
+(advice)f(on)f(using)g(FITS)g(\014les.)0 2603 y(The)38
+b(HEASAR)m(C)g(also)i(pro)m(vides)e(a)h(v)m(ery)g(sophisticated)h(FITS)
+d(\014le)i(analysis)g(program)f(called)i(`Fv')f(whic)m(h)0
+2716 y(can)34 b(b)s(e)f(used)g(to)h(displa)m(y)g(and)f(edit)h(the)g
+(con)m(ten)m(ts)i(of)e(an)m(y)g(FITS)f(\014le)g(as)h(w)m(ell)h(as)f
+(construct)g(new)f(FITS)g(\014les)0 2829 y(from)j(scratc)m(h.)61
+b(The)36 b(displa)m(y)h(functions)f(in)g(Fv)h(allo)m(w)h(users)e(to)i
+(in)m(teractiv)m(ely)h(adjust)d(the)h(brigh)m(tness)g(and)0
+2942 y(con)m(trast)h(of)f(images,)i(pan,)f(zo)s(om,)h(and)d(blink)g
+(images,)k(and)c(measure)h(the)f(p)s(ositions)h(and)f(brigh)m(tnesses)h
+(of)0 3055 y(ob)5 b(jects)33 b(within)f(images.)47 b(FITS)31
+b(tables)i(can)g(b)s(e)e(displa)m(y)m(ed)i(lik)m(e)h(a)e(spread)g
+(sheet,)h(and)f(then)f(mo)s(di\014ed)g(using)0 3168 y(p)s(o)m(w)m
+(erful)26 b(calculator)j(and)c(sorting)i(functions.)39
+b(Fv)27 b(is)f(freely)h(a)m(v)-5 b(ailable)29 b(for)d(most)h(Unix)f
+(platforms,)i(Mac)f(PCs,)0 3281 y(and)34 b(Windo)m(ws)g(PCs.)52
+b(CFITSIO)33 b(users)h(ma)m(y)h(also)g(b)s(e)f(in)m(terested)i(in)e
+(the)g(FTOOLS)f(pac)m(k)-5 b(age)37 b(of)d(programs)0
+3394 y(that)27 b(can)f(b)s(e)g(used)f(to)i(manipulate)g(and)e(analyze)j
+(FITS)d(format)i(\014les.)39 b(Fv)27 b(and)e(FTOOLS)g(are)i(a)m(v)-5
+b(ailable)28 b(from)0 3507 y(their)i(resp)s(ectiv)m(e)i(W)-8
+b(eb)31 b(sites)g(at:)382 3797 y Fe(http://fv.gsfc.nasa.gov)382
+3910 y(http://heasarc.gsfc.nasa)o(.go)o(v/ft)o(ools)0
+4280 y Ff(1.3)135 b(Ac)l(kno)l(wledgmen)l(ts)0 4538 y
+Fj(The)27 b(dev)m(elopmen)m(t)h(of)g(the)f(man)m(y)g(p)s(o)m(w)m(erful)
+g(features)h(in)f(CFITSIO)e(w)m(as)j(made)f(p)s(ossible)g(through)f
+(collab)s(ora-)0 4650 y(tions)33 b(with)e(man)m(y)i(p)s(eople)f(or)g
+(organizations)i(from)e(around)f(the)h(w)m(orld.)46 b(The)32
+b(follo)m(wing)h(in)f(particular)h(ha)m(v)m(e)0 4763
+y(made)d(esp)s(ecially)i(signi\014can)m(t)f(con)m(tributions:)0
+4924 y(Programmers)25 b(from)h(the)f(In)m(tegral)i(Science)g(Data)g
+(Cen)m(ter,)g(Switzerland)f(\(namely)-8 b(,)28 b(Jurek)c(Bork)m(o)m
+(wski,)29 b(Bruce)0 5036 y(O'Neel,)34 b(and)e(Don)h(Jennings\),)f
+(designed)g(the)h(concept)g(for)f(the)h(plug-in)f(I/O)g(driv)m(ers)g
+(that)h(w)m(as)g(in)m(tro)s(duced)0 5149 y(with)i(CFITSIO)e(2.0.)56
+b(The)34 b(use)h(of)g(`driv)m(ers')g(greatly)h(simpli\014ed)f(the)g(lo)
+m(w-lev)m(el)j(I/O,)d(whic)m(h)f(in)h(turn)f(made)0 5262
+y(other)40 b(new)f(features)i(in)e(CFITSIO)f(\(e.g.,)45
+b(supp)s(ort)38 b(for)h(compressed)h(FITS)f(\014les)h(and)f(supp)s(ort)
+f(for)i(IRAF)0 5375 y(format)32 b(image)g(\014les\))g(m)m(uc)m(h)f
+(easier)i(to)f(implemen)m(t.)44 b(Jurek)31 b(Bork)m(o)m(wski)h(wrote)g
+(the)g(Shared)e(Memory)i(driv)m(er,)0 5488 y(and)23 b(Bruce)i(O'Neel)g
+(wrote)f(the)g(driv)m(ers)g(for)f(accessing)j(FITS)d(\014les)h(o)m(v)m
+(er)h(the)f(net)m(w)m(ork)h(using)e(the)i(FTP)-8 b(,)24
+b(HTTP)-8 b(,)0 5601 y(and)26 b(R)m(OOT)g(proto)s(cols.)41
+b(Also,)28 b(in)e(2009,)k(Bruce)d(O'Neel)h(w)m(as)f(the)g(k)m(ey)g(dev)
+m(elop)s(er)g(of)g(the)g(thread-safe)g(v)m(ersion)0 5714
+y(of)k(CFITSIO.)p eop end
+%%Page: 3 11
+TeXDict begin 3 10 bop 0 299 a Fh(1.3.)72 b(A)m(CKNO)m(WLEDGMENTS)2623
+b Fj(3)0 555 y(The)45 b(ISDC)g(also)h(pro)m(vided)f(the)h(template)h
+(parsing)e(routines)g(\(written)h(b)m(y)f(Jurek)g(Bork)m(o)m(wski\))i
+(and)e(the)0 668 y(hierarc)m(hical)39 b(grouping)d(routines)h
+(\(written)h(b)m(y)f(Don)h(Jennings\).)60 b(The)37 b(ISDC)f(D)m(AL)i
+(\(Data)h(Access)f(La)m(y)m(er\))0 781 y(routines)30
+b(are)h(la)m(y)m(ered)h(on)e(top)h(of)f(CFITSIO)f(and)h(mak)m(e)h
+(extensiv)m(e)h(use)e(of)h(these)g(features.)0 941 y(Giuliano)g(T)-8
+b(a\013oni)31 b(and)f(Andrea)g(Barisani,)i(at)f(INAF,)g(Univ)m(ersit)m
+(y)h(of)e(T)-8 b(rieste,)32 b(Italy)-8 b(,)32 b(implemen)m(ted)e(the)h
+(I/O)0 1054 y(driv)m(er)f(routines)g(for)h(accessing)g(FITS)f(\014les)g
+(on)h(the)f(computational)i(grids)e(using)g(the)h(gridftp)e(proto)s
+(col.)0 1214 y(Uw)m(e)c(Lammers)e(\(XMM/ESA/ESTEC,)h(The)g
+(Netherlands\))g(designed)g(the)g(high-p)s(erformance)f(lexical)j
+(pars-)0 1327 y(ing)42 b(algorithm)h(that)f(is)g(used)f(to)i(do)e
+(on-the-\015y)h(\014ltering)g(of)g(FITS)f(tables.)76
+b(This)41 b(algorithm)i(essen)m(tially)0 1440 y(pre-compiles)36
+b(the)g(user-supplied)e(selection)k(expression)d(in)m(to)i(a)f(form)g
+(that)g(can)g(b)s(e)f(rapidly)g(ev)-5 b(aluated)37 b(for)0
+1553 y(eac)m(h)31 b(ro)m(w.)40 b(P)m(eter)31 b(Wilson)f(\(RSTX,)f
+(NASA/GSF)m(C\))i(then)e(wrote)h(the)g(parsing)f(routines)g(used)g(b)m
+(y)g(CFITSIO)0 1666 y(based)i(on)f(Lammers')h(design,)g(com)m(bined)g
+(with)g(other)g(tec)m(hniques)g(suc)m(h)g(as)g(the)g(CFITSIO)f
+(iterator)i(routine)0 1779 y(to)g(further)e(enhance)h(the)h(data)g(pro)
+s(cessing)f(throughput.)42 b(This)31 b(e\013ort)h(also)g(b)s
+(ene\014ted)e(from)h(a)h(m)m(uc)m(h)f(earlier)0 1892
+y(lexical)25 b(parsing)f(routine)f(that)h(w)m(as)g(dev)m(elop)s(ed)g(b)
+m(y)g(Ken)m(t)g(Blac)m(kburn)f(\(NASA/GSF)m(C\).)i(More)g(recen)m(tly)
+-8 b(,)27 b(Craig)0 2005 y(Markw)m(ardt)i(\(NASA/GSF)m(C\))g(implemen)m
+(ted)g(additional)g(functions)f(\(median,)h(a)m(v)m(erage,)j(stddev\))c
+(and)g(other)0 2118 y(enhancemen)m(ts)j(to)g(the)g(lexical)h(parser.)0
+2278 y(The)40 b(CFITSIO)g(iterator)i(function)e(is)h(lo)s(osely)h
+(based)f(on)f(similar)i(ideas)f(dev)m(elop)s(ed)g(for)g(the)g(XMM)g
+(Data)0 2391 y(Access)31 b(La)m(y)m(er.)0 2551 y(P)m(eter)25
+b(Wilson)g(\(RSTX,)f(NASA/GSF)m(C\))h(wrote)g(the)f(complete)i(set)e
+(of)h(F)-8 b(ortran-callable)27 b(wrapp)s(ers)22 b(for)i(all)h(the)0
+2664 y(CFITSIO)k(routines,)h(whic)m(h)g(in)g(turn)g(rely)g(on)h(the)f
+(CF)m(OR)-8 b(TRAN)31 b(macro)g(dev)m(elop)s(ed)g(b)m(y)f(Burkhard)f
+(Buro)m(w.)0 2824 y(The)h(syn)m(tax)i(used)e(b)m(y)h(CFITSIO)f(for)g
+(\014ltering)i(or)f(binning)e(input)h(FITS)h(\014les)g(is)g(based)f(on)
+h(ideas)h(dev)m(elop)s(ed)0 2937 y(for)41 b(the)g(AXAF)h(Science)g(Cen)
+m(ter)g(Data)h(Mo)s(del)e(b)m(y)g(Jonathan)g(McDo)m(w)m(ell,)47
+b(An)m(tonella)c(F)-8 b(ruscione,)45 b(Aneta)0 3050 y(Siemigino)m(wsk)
+-5 b(a)27 b(and)e(Bill)i(Jo)m(y)m(e.)41 b(See)26 b(h)m
+(ttp://heasarc.gsfc.nasa.go)m(v/do)s(cs/journal/axa)q(f7.h)m(t)q(ml)32
+b(for)25 b(further)0 3163 y(description)30 b(of)h(the)g(AXAF)g(Data)h
+(Mo)s(del.)0 3323 y(The)j(\014le)g(decompression)g(co)s(de)g(w)m(ere)h
+(tak)m(en)g(directly)g(from)e(the)i(gzip)f(\(GNU)h(zip\))g(program)f
+(dev)m(elop)s(ed)g(b)m(y)0 3436 y(Jean-loup)30 b(Gailly)i(and)e
+(others.)0 3596 y(The)e(new)h(compressed)g(image)h(data)g(format)f
+(\(where)g(the)g(image)h(is)f(tiled)h(and)e(the)h(compressed)g(b)m(yte)
+h(stream)0 3709 y(from)k(eac)m(h)i(tile)h(is)d(stored)h(in)g(a)g
+(binary)f(table\))j(w)m(as)e(implemen)m(ted)g(in)g(collab)s(oration)i
+(with)d(Ric)m(hard)h(White)0 3822 y(\(STScI\),)30 b(P)m(erry)g
+(Green\014eld)h(\(STScI\))f(and)f(Doug)i(T)-8 b(o)s(dy)30
+b(\(NO)m(A)m(O\).)0 3982 y(Doug)h(Mink)g(\(SA)m(O\))f(pro)m(vided)g
+(the)h(routines)f(for)g(con)m(v)m(erting)j(IRAF)d(format)h(images)g(in)
+m(to)h(FITS)d(format.)0 4142 y(Martin)k(Reinec)m(k)m(e)i(\(Max)f(Planc)
+m(k)f(Institute,)h(Garc)m(hing\)\))g(pro)m(vided)f(the)g(mo)s
+(di\014cations)f(to)i(cfortran.h)e(that)0 4255 y(are)d(necessary)h(to)f
+(supp)s(ort)e(64-bit)k(in)m(teger)f(v)-5 b(alues)29 b(when)f(calling)i
+(C)f(routines)g(from)f(fortran)h(programs.)39 b(The)0
+4368 y(cfortran.h)30 b(macros)h(w)m(ere)g(originally)h(dev)m(elop)s(ed)
+e(b)m(y)h(Burkhard)e(Buro)m(w)h(\(CERN\).)0 4528 y(Julian)f(T)-8
+b(a)m(ylor)31 b(\(ESO,)e(Garc)m(hing\))i(pro)m(vided)e(the)g(fast)h(b)m
+(yte-sw)m(apping)g(algorithms)h(that)f(use)f(the)h(SSE2)f(and)0
+4641 y(SSSE3)g(mac)m(hine)i(instructions)f(a)m(v)-5 b(ailable)33
+b(on)d(x86)p 1784 4641 28 4 v 34 w(64)h(CPUs.)0 4801
+y(In)c(addition,)i(man)m(y)f(other)g(p)s(eople)g(ha)m(v)m(e)h(made)f(v)
+-5 b(aluable)29 b(con)m(tributions)f(to)h(the)f(dev)m(elopmen)m(t)h(of)
+f(CFITSIO.)0 4914 y(These)i(include)g(\(with)h(ap)s(ologies)h(to)f
+(others)f(that)h(ma)m(y)g(ha)m(v)m(e)h(inadv)m(erten)m(tly)g(b)s(een)d
+(omitted\):)0 5074 y(Stev)m(e)g(Allen,)g(Carl)f(Ak)m(erlof,)h(Keith)f
+(Arnaud,)g(Morten)g(Krabb)s(e)e(Barfo)s(ed,)j(Ken)m(t)f(Blac)m(kburn,)h
+(G)f(Bo)s(dammer,)0 5187 y(Romk)m(e)h(Bon)m(tek)m(o)s(e,)i(Lucio)d
+(Chiapp)s(etti,)g(Keith)g(Costorf,)g(Robin)g(Corb)s(et,)g(John)e(Da)m
+(vis,)k(Ric)m(hard)e(Fink,)h(Ning)0 5300 y(Gan,)i(Emily)f(Greene,)h
+(Gretc)m(hen)g(Green,)f(Jo)s(e)g(Harrington,)h(Cheng)f(Ho,)h(Phil)f(Ho)
+s(dge,)g(Jim)g(Ingham,)g(Y)-8 b(oshi-)0 5413 y(tak)j(a)44
+b(Ishisaki,)i(Diab)e(Jerius,)h(Mark)f(Levine,)i(T)-8
+b(o)s(dd)42 b(Karak)-5 b(askian,)47 b(Edw)m(ard)42 b(King,)k(Scott)e
+(Ko)s(c)m(h,)i(Claire)0 5526 y(Larkin,)32 b(Rob)g(Managan,)i(Eric)e
+(Mandel,)h(Ric)m(hard)f(Mathar,)h(John)e(Matto)m(x,)k(Carsten)d(Mey)m
+(er,)i(Emi)d(Miy)m(ata,)0 5639 y(Stefan)39 b(Mo)s(c)m(hnac)m(ki,)k(Mik)
+m(e)e(Noble,)h(Oliv)m(er)e(Ob)s(erdorf,)f(Cliv)m(e)i(P)m(age,)i(Arvind)
+38 b(P)m(armar,)j(Je\013)f(P)m(edelt)m(y)-8 b(,)43 b(Tim)p
+eop end
+%%Page: 4 12
+TeXDict begin 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(earson,)40 b(Philipp)s(e)c
+(Prugniel,)j(Maren)e(Purv)m(es,)i(Scott)g(Randall,)g(Chris)d(Rogers,)k
+(Arnold)d(Rots,)i(Rob)e(Sea-)0 668 y(man,)23 b(Barry)e(Sc)m(hlesinger,)
+i(Robin)e(Stebbins,)h(Andrew)d(Szymk)m(o)m(wiak,)25 b(Allyn)c(T)-8
+b(ennan)m(t,)23 b(P)m(eter)f(T)-8 b(eub)s(en,)22 b(James)0
+781 y(Theiler,)k(Doug)g(T)-8 b(o)s(dy)g(,)25 b(Shiro)f(Ueno,)j(Stev)m
+(e)f(W)-8 b(alton,)28 b(Arc)m(hie)d(W)-8 b(arno)s(c)m(k,)27
+b(Alan)e(W)-8 b(atson,)28 b(Dan)d(Whipple,)h(Wim)0 894
+y(Wimmers,)31 b(P)m(eter)g(Y)-8 b(oung,)31 b(Jianjun)e(Xu,)h(and)g
+(Nelson)h(Zarate.)0 1228 y Ff(1.4)135 b(Legal)46 b(Stu\013)0
+1478 y Fj(Cop)m(yrigh)m(t)37 b(\(Unpublished{all)g(righ)m(ts)g(reserv)m
+(ed)g(under)e(the)i(cop)m(yrigh)m(t)h(la)m(ws)f(of)g(the)g(United)g
+(States\),)j(U.S.)0 1591 y(Go)m(v)m(ernmen)m(t)30 b(as)g(represen)m
+(ted)e(b)m(y)h(the)g(Administrator)g(of)g(the)g(National)h(Aeronautics)
+g(and)e(Space)h(Adminis-)0 1704 y(tration.)42 b(No)31
+b(cop)m(yrigh)m(t)g(is)g(claimed)g(in)f(the)h(United)f(States)h(under)e
+(Title)j(17,)f(U.S.)f(Co)s(de.)0 1864 y(P)m(ermission)g(to)g(freely)f
+(use,)h(cop)m(y)-8 b(,)31 b(mo)s(dify)-8 b(,)29 b(and)g(distribute)g
+(this)g(soft)m(w)m(are)i(and)e(its)h(do)s(cumen)m(tation)g(without)0
+1977 y(fee)f(is)f(hereb)m(y)g(gran)m(ted,)i(pro)m(vided)e(that)h(this)f
+(cop)m(yrigh)m(t)i(notice)f(and)f(disclaimer)h(of)f(w)m(arran)m(t)m(y)i
+(app)s(ears)d(in)h(all)0 2090 y(copies.)0 2250 y(DISCLAIMER:)0
+2410 y(THE)33 b(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
+2523 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 2636 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 2749 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 2862 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
+2974 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 3087 y(SOFTW)-10 b(ARE)31 b(WILL)h(BE)g(ERR)m(OR)g
+(FREE.)g(IN)g(NO)g(EVENT)f(SHALL)g(NASA)h(BE)g(LIABLE)g(F)m(OR)g(ANY)0
+3200 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 3313 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
+3426 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 3539 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 3652 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 3765
+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 3878 y(VICES)29 b(PR)m(O)m(VIDED)j(HEREUNDER.")p
+eop end
+%%Page: 5 13
+TeXDict begin 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)
+h(con)m(tained)g(in)f(ab)s(out)g(40)h(C)f(source)h(\014les)f(\(*.c\))i
+(and)e(header)g(\014les)g(\(*.h\).)93 b(On)0 2579 y(V)-10
+b(AX/VMS)31 b(systems)g(2)f(assem)m(bly-co)s(de)i(\014les)e
+(\(vmsieeed.mar)h(and)f(vmsieeer.mar\))i(are)e(also)i(needed.)0
+2739 y(CFITSIO)d(has)h(curren)m(tly)g(b)s(een)g(tested)h(on)f(the)h
+(follo)m(wing)h(platforms)e(\(not)h(up-to-date\):)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)j(probably)e(run)f(on)i(most)g(other)h
+(Unix)e(platforms.)40 b(Cra)m(y)28 b(sup)s(ercomputers)e(are)j(curren)m
+(tly)f(not)0 5211 y(supp)s(orted.)0 5495 y Fd(2.1.1)112
+b(Unix)39 b(Systems)0 5714 y Fj(The)30 b(CFITSIO)f(library)h(is)g
+(built)g(on)h(Unix)f(systems)g(b)m(y)g(t)m(yping:)1927
+5942 y(5)p eop end
+%%Page: 6 14
+TeXDict begin 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])d([--enable-reentrant])764 668 y([--enable-sse2])h
+([--enable-ssse3])48 781 y(>)95 b(make)476 b(\(or)95
+b('make)46 b(shared'\))48 894 y(>)95 b(make)47 b(install)93
+b(\(this)46 b(step)h(is)g(optional\))0 1128 y Fj(at)24
+b(the)g(op)s(erating)g(system)g(prompt.)38 b(The)23 b(con\014gure)g
+(command)g(customizes)i(the)f(Mak)m(e\014le)h(for)f(the)g(particular)0
+1241 y(system,)g(then)d(the)g(`mak)m(e')i(command)e(compiles)h(the)f
+(source)h(\014les)f(and)g(builds)f(the)h(library)-8 b(.)38
+b(T)m(yp)s(e)21 b(`./con\014gure')0 1354 y(and)34 b(not)h(simply)f
+(`con\014gure')h(to)h(ensure)e(that)h(the)g(con\014gure)g(script)f(in)h
+(the)g(curren)m(t)f(directory)h(is)g(run)f(and)0 1467
+y(not)29 b(some)g(other)g(system-wide)g(con\014gure)f(script.)40
+b(The)29 b(optional)h('pre\014x')e(argumen)m(t)h(to)g(con\014gure)g
+(giv)m(es)h(the)0 1580 y(path)e(to)i(the)f(directory)g(where)f(the)h
+(CFITSIO)f(library)g(and)g(include)h(\014les)f(should)g(b)s(e)g
+(installed)i(via)f(the)g(later)0 1692 y('mak)m(e)j(install')f(command.)
+41 b(F)-8 b(or)31 b(example,)143 1926 y Fe(>)48 b(./configure)c
+(--prefix=/usr1/local)0 2160 y Fj(will)25 b(cause)h(the)f('mak)m(e)h
+(install')g(command)f(to)h(cop)m(y)g(the)f(CFITSIO)e(lib)s(c\014tsio)i
+(\014le)h(to)f(/usr1/lo)s(cal/lib)i(and)e(the)0 2273
+y(necessary)33 b(include)e(\014les)i(to)f(/usr1/lo)s(cal/include)j
+(\(assuming)d(of)g(course)g(that)h(the)f(pro)s(cess)g(has)g(p)s
+(ermission)0 2386 y(to)f(write)g(to)g(these)g(directories\).)0
+2546 y(The)42 b(optional)i({enable-reen)m(tran)m(t)g(\015ag)f(will)g
+(attempt)h(to)f(con\014gure)f(CFITSIO)f(so)i(that)g(it)g(can)g(b)s(e)f
+(used)0 2659 y(in)35 b(m)m(ulti-threaded)g(programs.)54
+b(See)35 b(the)g("Using)g(CFITSIO)e(in)i(Multi-threaded)g(En)m
+(vironmen)m(ts")h(section,)0 2772 y(b)s(elo)m(w,)31 b(for)f(more)0
+2932 y(The)24 b(optional)i({enable-sse2)g(and)e({enable-ssse3)i
+(\015ags)e(will)h(cause)g(con\014gure)f(to)h(attempt)h(to)f(build)e
+(CFITSIO)0 3045 y(using)29 b(faster)i(b)m(yte-sw)m(apping)f
+(algorithms.)42 b(See)30 b(the)g("Optimizing)h(Programs")f(c)m(hapter)h
+(of)f(this)g(man)m(ual)g(for)0 3158 y(more)h(information)f(ab)s(out)g
+(these)h(options.)0 3318 y(The)d('mak)m(e)h(shared')f(option)h(builds)e
+(a)i(shared)e(or)i(dynamic)f(v)m(ersion)h(of)f(the)h(CFITSIO)d(library)
+-8 b(.)40 b(When)28 b(using)0 3431 y(the)f(shared)f(library)h(the)g
+(executable)h(co)s(de)f(is)g(not)g(copied)g(in)m(to)h(y)m(our)f
+(program)g(at)g(link)g(time)g(and)g(instead)g(the)0 3544
+y(program)g(lo)s(cates)i(the)f(necessary)g(library)f(co)s(de)h(at)g
+(run)e(time,)j(normally)f(through)e(LD)p 3065 3544 28
+4 v 33 w(LIBRAR)-8 b(Y)p 3514 3544 V 34 w(P)g(A)g(TH)28
+b(or)0 3657 y(some)j(other)f(metho)s(d.)41 b(The)29 b(adv)-5
+b(an)m(tages)33 b(of)d(using)g(a)h(shared)e(library)h(are:)143
+3891 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 4004 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
+4117 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 4230 y(enough)f(to)h(share)g(copies)f(of)h
+(the)g(shared)f(library)g(at)h(run)g(time.)143 4343 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 4456 y(library)f(can)h(be)g(installed)e(without)h
+(relinking)f(all)i(the)g(software)334 4568 y(that)g(uses)f(it)i(\(as)e
+(long)h(as)g(the)g(subroutine)e(names)i(and)f(calling)334
+4681 y(sequences)f(remain)h(unchanged\).)143 4794 y(4.)95
+b(No)47 b(run-time)f(penalty.)0 5028 y Fj(The)30 b(disadv)-5
+b(an)m(tages)32 b(are:)143 5262 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
+5375 y(specially)f(or)h(have)f(LD_LIBRARY_PATH)e(set)j(right.)143
+5488 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 5601 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
+5714 y(either)f(really)h(slow)f(or)h(really)f(heavily)g(loaded.)p
+eop end
+%%Page: 7 15
+TeXDict begin 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(On)32 b(Mac)i(OS)e(X)i
+(platforms)f(the)g('mak)m(e)h(shared')f(command)f(w)m(orks)h(lik)m(e)i
+(on)e(other)g(UNIX)g(platforms,)h(but)f(a)0 668 y(.dylib)f(\014le)g
+(will)g(b)s(e)f(created)i(instead)g(of)f(.so.)46 b(If)31
+b(installed)i(in)f(a)g(nonstandard)f(lo)s(cation,)j(add)d(its)i(lo)s
+(cation)g(to)0 781 y(the)e(D)m(YLD)p 422 781 28 4 v 34
+w(LIBRAR)-8 b(Y)p 872 781 V 33 w(P)g(A)g(TH)31 b(en)m(vironmen)m(t)g(v)
+-5 b(ariable)31 b(so)g(that)g(the)f(library)g(can)h(b)s(e)f(found)f(at)
+i(run)e(time.)0 941 y(On)h(HP/UX)i(systems,)g(the)f(en)m(vironmen)m(t)h
+(v)-5 b(ariable)32 b(CFLA)m(GS)f(should)f(b)s(e)h(set)g(to)h(-Ae)g(b)s
+(efore)f(running)e(con-)0 1054 y(\014gure)h(to)h(enable)g("extended)g
+(ANSI")f(features.)0 1214 y(By)h(default,)h(a)f(set)h(of)f(F)-8
+b(ortran-callable)34 b(wrapp)s(er)29 b(routines)i(are)g(also)h(built)f
+(and)f(included)h(in)f(the)h(CFITSIO)0 1327 y(library)-8
+b(.)70 b(If)40 b(these)g(wrapp)s(er)f(routines)h(are)g(not)h(needed)e
+(\(i.e.,)45 b(the)40 b(CFITSIO)f(library)g(will)i(not)f(b)s(e)g(link)m
+(ed)0 1440 y(to)d(an)m(y)f(F)-8 b(ortran)37 b(applications)g(whic)m(h)f
+(call)h(FITSIO)e(subroutines\))g(then)h(they)g(ma)m(y)h(b)s(e)e
+(omitted)i(from)f(the)0 1553 y(build)28 b(b)m(y)i(t)m(yping)g('mak)m(e)
+g(all-no\014tsio')i(instead)d(of)h(simply)f(t)m(yping)h('mak)m(e'.)42
+b(This)28 b(will)i(reduce)f(the)h(size)g(of)g(the)0 1666
+y(CFITSIO)f(library)h(sligh)m(tly)-8 b(.)0 1826 y(It)33
+b(ma)m(y)g(not)g(b)s(e)f(p)s(ossible)g(to)h(statically)i(link)e
+(programs)f(that)h(use)g(CFITSIO)e(on)h(some)h(platforms)g(\(namely)-8
+b(,)0 1939 y(on)28 b(Solaris)h(2.6\))h(due)e(to)h(the)g(net)m(w)m(ork)g
+(driv)m(ers)f(\(whic)m(h)h(pro)m(vide)g(FTP)f(and)g(HTTP)g(access)h(to)
+h(FITS)d(\014les\).)41 b(It)0 2052 y(is)33 b(p)s(ossible)f(to)i(mak)m
+(e)f(b)s(oth)g(a)g(dynamic)f(and)g(a)i(static)g(v)m(ersion)f(of)g(the)g
+(CFITSIO)e(library)-8 b(,)34 b(but)e(net)m(w)m(ork)i(\014le)0
+2165 y(access)e(will)e(not)h(b)s(e)f(p)s(ossible)g(using)g(the)g
+(static)i(v)m(ersion.)0 2627 y Fd(2.1.2)112 b(VMS)0 2880
+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 2880 V 34 w(g\015oat.com)h(command)e(\014le)g(ma)m(y)h(b)s
+(e)f(executed)h(to)0 2993 y(build)35 b(the)i(c\014tsio.olb)g(ob)5
+b(ject)37 b(library)f(using)g(the)g(default)h(G-\015oating)g(p)s(oin)m
+(t)g(option)f(for)g(double)g(v)-5 b(ariables.)0 3106
+y(The)37 b(mak)m(e)p 405 3106 V 33 w(d\015oat.com)i(and)d(mak)m(e)p
+1279 3106 V 34 w(ieee.com)j(\014les)f(ma)m(y)f(b)s(e)g(used)f(instead)i
+(to)g(build)e(the)h(library)g(with)g(the)0 3219 y(other)26
+b(\015oating)i(p)s(oin)m(t)e(options.)39 b(Note)28 b(that)f(the)f
+(getcwd)h(function)f(that)h(is)f(used)f(in)h(the)h(group.c)f(mo)s(dule)
+f(ma)m(y)0 3332 y(require)44 b(that)i(programs)e(using)g(CFITSIO)f(b)s
+(e)h(link)m(ed)i(with)e(the)h(ALPHA$LIBRAR)-8 b(Y:V)e(AX)m(CR)i(TL.OLB)
+0 3445 y(library)g(.)41 b(See)30 b(the)h(example)g(link)f(line)h(in)f
+(the)h(next)f(section)i(of)e(this)h(do)s(cumen)m(t.)0
+3907 y Fd(2.1.3)112 b(Windo)m(ws)38 b(PCs)0 4161 y Fj(A)28
+b(precompiled)g(DLL)g(v)m(ersion)g(of)g(CFITSIO)e(is)i(a)m(v)-5
+b(ailable)31 b(for)c(IBM-PC)h(users)g(of)g(the)g(Borland)g(or)g
+(Microsoft)0 4274 y(Visual)46 b(C++)e(compilers)i(in)f(the)h(\014les)f
+(c\014tsio)s(dll)p 1799 4274 V 34 w(3xxx)p 2022 4274
+V 33 w(b)s(orland.zip)f(and)h(c\014tsio)s(dll)p 3075
+4274 V 33 w(3xxx)p 3297 4274 V 33 w(v)m(cc.zip,)51 b(where)0
+4386 y('3xxx')45 b(represen)m(ts)f(the)g(curren)m(t)g(release)i(n)m(um)
+m(b)s(er.)81 b(These)44 b(zip)g(arc)m(hiv)m(es)h(also)h(con)m(tains)f
+(other)f(\014les)h(and)0 4499 y(instructions)30 b(on)g(ho)m(w)h(to)g
+(use)f(the)h(CFITSIO)d(DLL)j(library)-8 b(.)0 4659 y(The)28
+b(CFITSIO)g(library)g(ma)m(y)h(also)h(b)s(e)e(built)h(from)f(the)h
+(source)g(co)s(de)g(using)g(the)g(mak)m(e\014le.b)s(c)g(or)g(mak)m
+(e\014le.v)m(cc)0 4772 y(\014les.)55 b(Finally)-8 b(,)38
+b(the)d(mak)m(ep)s(c.bat)h(\014le)f(giv)m(es)i(an)e(example)h(of)f
+(building)f(CFITSIO)g(with)g(the)i(Borland)f(C++)0 4885
+y(v4.5)c(or)g(v5.5)g(compiler)g(using)f(older)h(DOS)f(commands.)0
+5348 y Fd(2.1.4)112 b(Macin)m(tosh)39 b(PCs)0 5601 y
+Fj(When)20 b(building)f(on)i(Mac)g(OS-X,)f(users)g(should)f(follo)m(w)i
+(the)g(Unix)f(instructions,)i(ab)s(o)m(v)m(e.)39 b(See)20
+b(the)h(README.MacOS)0 5714 y(\014le)30 b(for)h(instructions)f(on)g
+(building)g(a)g(Univ)m(ersal)i(Binary)e(that)h(supp)s(orts)e(b)s(oth)g
+(In)m(tel)i(and)f(P)m(o)m(w)m(erPC)h(CPUs.)p eop end
+%%Page: 8 16
+TeXDict begin 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 Ff(2.2)135 b(T)-11 b(esting)46 b(the)f(Library)0
+805 y Fj(The)40 b(CFITSIO)e(library)i(should)f(b)s(e)g(tested)i(b)m(y)f
+(building)f(and)g(running)g(the)h(testprog.c)h(program)f(that)h(is)0
+918 y(included)30 b(with)g(the)g(release.)42 b(On)30
+b(Unix)g(systems,)h(t)m(yp)s(e:)191 1148 y Fe(\045)47
+b(make)g(testprog)191 1261 y(\045)g(testprog)f(>)h(testprog.lis)191
+1374 y(\045)g(diff)g(testprog.lis)d(testprog.out)191
+1487 y(\045)j(cmp)g(testprog.fit)e(testprog.std)0 1717
+y Fj(On)30 b(VMS)g(systems,)g(\(assuming)h(cc)g(is)f(the)h(name)f(of)h
+(the)f(C)g(compiler)h(command\),)g(t)m(yp)s(e:)191 1947
+y Fe($)47 b(cc)h(testprog.c)191 2060 y($)f(link)g(testprog,)e
+(cfitsio/lib,)g(alpha$library:vaxcrtl/l)o(ib)191 2173
+y($)i(run)g(testprog)0 2402 y Fj(The)42 b(test)h(program)f(should)f
+(pro)s(duce)g(a)i(FITS)e(\014le)i(called)g(`testprog.\014t')h(that)f
+(is)f(iden)m(tical)i(to)f(the)f(`test-)0 2515 y(prog.std')35
+b(FITS)e(\014le)i(included)e(with)h(this)g(release.)54
+b(The)34 b(diagnostic)i(messages)f(\(whic)m(h)g(w)m(ere)g(pip)s(ed)e
+(to)i(the)0 2628 y(\014le)h(testprog.lis)i(in)e(the)h(Unix)f(example\))
+h(should)e(b)s(e)h(iden)m(tical)i(to)f(the)f(listing)h(con)m(tained)h
+(in)e(the)g(\014le)h(test-)0 2741 y(prog.out.)63 b(The)37
+b('di\013)7 b(')38 b(and)f('cmp')h(commands)g(sho)m(wn)f(ab)s(o)m(v)m
+(e)i(should)d(not)i(rep)s(ort)f(an)m(y)h(di\013erences)g(in)g(the)0
+2854 y(\014les.)65 b(\(There)38 b(ma)m(y)h(b)s(e)f(some)h(minor)f
+(format)h(di\013erences,)i(suc)m(h)d(as)h(the)g(presence)f(or)h
+(absence)g(of)f(leading)0 2967 y(zeros,)31 b(or)g(3)f(digit)i(exp)s
+(onen)m(ts)e(in)g(n)m(um)m(b)s(ers,)f(whic)m(h)h(can)h(b)s(e)f
+(ignored\).)0 3127 y(The)e(F)-8 b(ortran)30 b(wrapp)s(ers)d(in)h
+(CFITSIO)f(ma)m(y)j(b)s(e)e(tested)h(with)g(the)g(testf77)h(program)f
+(on)g(Unix)f(systems)h(with:)191 3357 y Fe(\045)47 b(f77)g(-o)g
+(testf77)f(testf77.f)g(-L.)g(-lcfitsio)g(-lnsl)g(-lsocket)95
+3470 y(or)191 3583 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 3696 y(or)191
+3809 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 4035 y(\045)i(testf77)f(>)i
+(testf77.lis)191 4147 y(\045)f(diff)g(testf77.lis)e(testf77.out)191
+4260 y(\045)i(cmp)g(testf77.fit)e(testf77.std)0 4490
+y Fj(On)31 b(mac)m(hines)h(running)f(SUN)g(O/S,)h(F)-8
+b(ortran)33 b(programs)e(m)m(ust)h(b)s(e)f(compiled)h(with)g(the)g('-f)
+7 b(')32 b(option)h(to)f(force)0 4603 y(double)25 b(precision)h(v)-5
+b(ariables)26 b(to)g(b)s(e)f(aligned)h(on)g(8-b)m(yte)h(b)s(oundarys)c
+(to)j(mak)m(e)h(the)e(fortran-declared)h(v)-5 b(ariables)0
+4716 y(compatible)34 b(with)e(C.)g(A)h(similar)g(compiler)g(option)g
+(ma)m(y)g(b)s(e)f(required)g(on)g(other)h(platforms.)48
+b(F)-8 b(ailing)34 b(to)f(use)0 4829 y(this)26 b(option)g(ma)m(y)g
+(cause)h(the)f(program)f(to)i(crash)e(on)h(FITSIO)f(routines)g(that)i
+(read)f(or)f(write)h(double)g(precision)0 4942 y(v)-5
+b(ariables.)0 5102 y(Also)31 b(note)g(that)f(on)g(some)h(systems,)f
+(the)h(output)e(listing)i(of)g(the)f(testf77)i(program)d(ma)m(y)i
+(di\013er)f(sligh)m(tly)h(from)0 5215 y(the)g(testf77.std)h(template,)g
+(if)f(leading)g(zeros)g(are)g(not)g(prin)m(ted)f(b)m(y)h(default)g(b)s
+(efore)f(the)h(decimal)g(p)s(oin)m(t)g(when)0 5328 y(using)f(F)h
+(format.)0 5488 y(A)37 b(few)f(other)g(utilit)m(y)i(programs)e(are)h
+(included)f(with)g(CFITSIO;)f(the)i(\014rst)e(four)h(of)g(this)h
+(programs)f(can)h(b)s(e)0 5601 y(compiled)e(an)g(link)m(ed)g(b)m(y)g(t)
+m(yping)g(`mak)m(e)h(program)p 1815 5601 28 4 v 33 w(name')f(where)f
+(`program)p 2746 5601 V 33 w(name')h(is)g(the)g(actual)h(name)f(of)0
+5714 y(the)c(program:)p eop end
+%%Page: 9 17
+TeXDict begin 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)191 555 y
+Fe(speed)46 b(-)i(measures)d(the)i(maximum)f(throughput)f(\(in)i(MB)g
+(per)g(second\))668 668 y(for)g(writing)f(and)h(reading)f(FITS)g(files)
+h(with)f(CFITSIO.)191 894 y(listhead)f(-)j(lists)e(all)h(the)g(header)f
+(keywords)g(in)h(any)g(FITS)f(file)191 1120 y(fitscopy)f(-)j(copies)e
+(any)h(FITS)g(file)f(\(especially)f(useful)h(in)h(conjunction)811
+1233 y(with)g(the)g(CFITSIO's)e(extended)h(input)g(filename)g
+(syntax\).)191 1458 y(cookbook)f(-)j(a)f(sample)f(program)g(that)h
+(performs)e(common)i(read)f(and)811 1571 y(write)h(operations)e(on)i(a)
+g(FITS)g(file.)191 1797 y(iter_a,)f(iter_b,)g(iter_c)g(-)h(examples)f
+(of)h(the)g(CFITSIO)f(iterator)f(routine)0 2167 y Ff(2.3)135
+b(Linking)45 b(Programs)h(with)f(CFITSIO)0 2425 y Fj(When)25
+b(linking)h(applications)h(soft)m(w)m(are)g(with)e(the)h(CFITSIO)e
+(library)-8 b(,)27 b(sev)m(eral)g(system)f(libraries)g(usually)f(need)0
+2538 y(to)36 b(b)s(e)f(sp)s(eci\014ed)g(on)g(the)g(link)h(command)f
+(line.)56 b(On)34 b(Unix)i(systems,)h(the)e(most)h(reliable)g(w)m(a)m
+(y)h(to)f(determine)0 2651 y(what)26 b(libraries)h(are)f(required)g(is)
+g(to)h(t)m(yp)s(e)f('mak)m(e)i(testprog')f(and)f(see)h(what)f
+(libraries)h(the)f(con\014gure)g(script)g(has)0 2764
+y(added.)39 b(The)25 b(t)m(ypical)j(libraries)e(that)g(need)g(to)g(b)s
+(e)g(added)f(are)h(-lm)h(\(the)f(math)g(library\))g(and)f(-lnsl)h(and)g
+(-lso)s(c)m(k)m(et)0 2877 y(\(needed)k(only)g(for)g(FTP)g(and)f(HTTP)g
+(\014le)h(access\).)43 b(These)30 b(latter)h(2)f(libraries)g(are)h(not)
+f(needed)g(on)g(VMS)g(and)0 2989 y(Windo)m(ws)g(platforms,)h(b)s
+(ecause)f(FTP)h(\014le)f(access)i(is)e(not)h(curren)m(tly)f(supp)s
+(orted)f(on)h(those)h(platforms.)0 3150 y(Note)i(that)g(when)e
+(upgrading)g(to)i(a)f(new)m(er)g(v)m(ersion)g(of)g(CFITSIO)f(it)h(is)g
+(usually)g(necessary)g(to)h(recompile,)h(as)0 3263 y(w)m(ell)d(as)g
+(relink,)g(the)f(programs)g(that)h(use)f(CFITSIO,)f(b)s(ecause)i(the)f
+(de\014nitions)g(in)g(\014tsio.h)h(often)f(c)m(hange.)0
+3633 y Ff(2.4)135 b(Using)46 b(CFITSIO)e(in)h(Multi-threaded)g(En)l
+(vironmen)l(ts)0 3890 y Fj(CFITSIO)d(can)h(b)s(e)g(used)f(either)i
+(with)e(the)i(POSIX)e(pthreads)g(in)m(terface)j(or)e(the)h(Op)s(enMP)d
+(in)m(terface)k(for)0 4003 y(m)m(ulti-threaded)g(parallel)g(programs.)
+81 b(When)43 b(used)h(in)f(a)i(m)m(ulti-threaded)f(en)m(vironmen)m(t,)k
+(the)c(CFITSIO)0 4116 y(library)26 b(*m)m(ust*)h(b)s(e)e(built)h(using)
+g(the)g(-D)p 1426 4116 28 4 v 34 w(REENTRANT)f(compiler)i(directiv)m
+(e.)41 b(This)25 b(can)i(b)s(e)e(done)h(using)g(the)0
+4229 y(follo)m(wing)32 b(build)d(commands:)95 4520 y
+Fe(>./configure)45 b(--enable-reentrant)95 4633 y(>)j(make)0
+4924 y Fj(A)32 b(function)g(called)i(\014ts)p 845 4924
+V 32 w(is)p 938 4924 V 33 w(reen)m(tran)m(t)f(is)g(a)m(v)-5
+b(ailable)34 b(to)f(test)h(whether)d(or)i(not)f(CFITSIO)f(w)m(as)h
+(compiled)h(with)0 5036 y(the)28 b(-D)p 258 5036 V 34
+w(REENTRANT)f(directiv)m(e.)42 b(When)28 b(this)g(feature)g(is)g
+(enabled,)h(m)m(ultiple)g(threads)e(can)i(call)g(an)m(y)g(of)f(the)0
+5149 y(CFITSIO)k(routines)h(to)h(sim)m(ultaneously)g(read)f(or)h(write)
+f(separate)h(FITS)f(\014les.)49 b(Multiple)34 b(threads)f(can)h(also)0
+5262 y(read)29 b(data)h(from)e(the)h(same)h(FITS)e(\014le)h(sim)m
+(ultaneously)-8 b(,)31 b(as)e(long)h(as)f(the)g(\014le)g(w)m(as)h(op)s
+(ened)e(indep)s(enden)m(tly)g(b)m(y)0 5375 y(eac)m(h)37
+b(thread.)58 b(This)35 b(relies)i(on)f(the)g(op)s(erating)h(system)f
+(to)h(correctly)g(deal)g(with)f(reading)g(the)g(same)h(\014le)f(b)m(y)0
+5488 y(m)m(ultiple)30 b(pro)s(cesses.)41 b(Di\013eren)m(t)30
+b(threads)g(should)e(not)i(share)f(the)h(same)g('\014ts\014le')g(p)s
+(oin)m(ter)f(to)i(read)e(an)h(op)s(ened)0 5601 y(FITS)40
+b(\014le,)j(unless)d(lo)s(c)m(ks)h(are)g(placed)f(around)g(the)g(calls)
+i(to)f(the)g(CFITSIO)d(reading)j(routines.)71 b(Di\013eren)m(t)0
+5714 y(threads)30 b(should)f(nev)m(er)i(try)f(to)h(write)g(to)g(the)g
+(same)f(FITS)g(\014le.)p eop end
+%%Page: 10 18
+TeXDict begin 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 Ff(2.5)135 b(Getting)46 b(Started)g(with)f(CFITSIO)0
+810 y Fj(In)27 b(order)h(to)g(e\013ectiv)m(ely)j(use)d(the)g(CFITSIO)e
+(library)i(it)g(is)g(recommended)g(that)g(new)f(users)h(b)s(egin)f(b)m
+(y)h(reading)0 923 y(the)g(\\CFITSIO)g(Quic)m(k)g(Start)g(Guide".)41
+b(It)28 b(con)m(tains)h(all)h(the)e(basic)h(information)f(needed)g(to)h
+(write)f(programs)0 1036 y(that)c(p)s(erform)f(most)h(t)m(yp)s(es)g(of)
+g(op)s(erations)g(on)g(FITS)f(\014les.)39 b(The)23 b(set)i(of)f
+(example)g(FITS)g(utilit)m(y)h(programs)e(that)0 1149
+y(are)29 b(a)m(v)-5 b(ailable)31 b(from)d(the)g(CFITSIO)f(w)m(eb)i
+(site)g(are)g(also)g(v)m(ery)g(useful)f(for)g(learning)h(ho)m(w)f(to)h
+(use)f(CFITSIO.)f(T)-8 b(o)0 1262 y(learn)23 b(ev)m(en)g(more)g(ab)s
+(out)f(the)h(capabilities)h(of)f(the)g(CFITSIO)e(library)h(the)h(follo)
+m(wing)h(steps)e(are)h(recommended:)0 1422 y(1.)41 b(Read)31
+b(the)f(follo)m(wing)i(short)e(`FITS)g(Primer')g(c)m(hapter)h(for)f(an)
+h(o)m(v)m(erview)h(of)e(the)h(structure)f(of)g(FITS)g(\014les.)0
+1582 y(2.)40 b(Review)28 b(the)f(Programming)g(Guidelines)h(in)f
+(Chapter)f(4)i(to)g(b)s(ecome)f(familiar)h(with)f(the)h(con)m(v)m(en)m
+(tions)h(used)0 1695 y(b)m(y)h(the)h(CFITSIO)e(in)m(terface.)0
+1855 y(3.)74 b(Refer)41 b(to)h(the)g(co)s(okb)s(o)s(ok.c,)j
+(listhead.c,)h(and)40 b(\014tscop)m(y)-8 b(.c)43 b(programs)e(that)h
+(are)g(included)e(with)h(this)h(re-)0 1968 y(lease)g(for)e(examples)h
+(of)g(routines)f(that)h(p)s(erform)e(v)-5 b(arious)41
+b(common)g(FITS)f(\014le)g(op)s(erations.)72 b(T)m(yp)s(e)40
+b('mak)m(e)0 2081 y(program)p 339 2081 28 4 v 33 w(name')30
+b(to)h(compile)h(and)d(link)i(these)g(programs)f(on)g(Unix)g(systems.)0
+2241 y(4.)40 b(W)-8 b(rite)30 b(a)e(simple)g(program)g(to)g(read)g(or)g
+(write)g(a)h(FITS)e(\014le)h(using)g(the)g(Basic)h(In)m(terface)g
+(routines)f(describ)s(ed)0 2354 y(in)i(Chapter)g(5.)0
+2514 y(5.)79 b(Scan)43 b(through)f(the)h(more)g(sp)s(ecialized)i
+(routines)d(that)i(are)f(describ)s(ed)f(in)h(the)g(follo)m(wing)i(c)m
+(hapters)e(to)0 2627 y(b)s(ecome)31 b(familiar)g(with)f(the)h
+(functionalit)m(y)g(that)g(they)g(pro)m(vide.)0 2986
+y Ff(2.6)135 b(Example)46 b(Program)0 3241 y Fj(The)c(follo)m(wing)j
+(listing)f(sho)m(ws)e(an)h(example)h(of)f(ho)m(w)g(to)g(use)g(the)g
+(CFITSIO)f(routines)g(in)h(a)g(C)g(program.)0 3354 y(Refer)26
+b(to)g(the)g(co)s(okb)s(o)s(ok.c)g(program)f(that)i(is)e(included)g
+(with)g(the)h(CFITSIO)e(distribution)h(for)g(other)h(example)0
+3466 y(routines.)0 3627 y(This)38 b(program)h(creates)h(a)f(new)f(FITS)
+g(\014le,)k(con)m(taining)e(a)f(FITS)f(image.)68 b(An)38
+b(`EXPOSURE')h(k)m(eyw)m(ord)g(is)0 3740 y(written)27
+b(to)g(the)f(header,)i(then)e(the)h(image)g(data)h(are)f(written)f(to)h
+(the)g(FITS)f(\014le)g(b)s(efore)h(closing)g(the)g(FITS)f(\014le.)0
+4020 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 4133 y(main\(\))0
+4246 y({)191 4359 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
+4472 y(int)h(status,)f(ii,)h(jj;)191 4585 y(long)94 b(fpixel)46
+b(=)i(1,)f(naxis)f(=)i(2,)f(nelements,)e(exposure;)191
+4698 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
+4811 y(short)g(array[200][300];)191 5036 y(status)g(=)h(0;)429
+b(/*)48 b(initialize)d(status)h(before)g(calling)g(fitsio)g(routines)f
+(*/)191 5149 y(fits_create_file\(&fptr,)c("testfile.fits",)j
+(&status\);)140 b(/*)48 b(create)e(new)h(file)f(*/)191
+5375 y(/*)h(Create)f(the)h(primary)f(array)g(image)h(\(16-bit)e(short)i
+(integer)f(pixels)g(*/)191 5488 y(fits_create_img\(fptr,)c(SHORT_IMG,)j
+(naxis,)h(naxes,)g(&status\);)191 5714 y(/*)h(Write)f(a)i(keyword;)d
+(must)i(pass)g(the)g(ADDRESS)e(of)j(the)f(value)f(*/)p
+eop end
+%%Page: 11 19
+TeXDict begin 11 18 bop 0 299 a Fh(2.6.)72 b(EXAMPLE)31
+b(PR)m(OGRAM)2618 b Fj(11)191 555 y Fe(exposure)45 b(=)j(1500.;)191
+668 y(fits_update_key\(fptr,)42 b(TLONG,)k("EXPOSURE",)f(&exposure,)430
+781 y("Total)h(Exposure)f(Time",)h(&status\);)191 1007
+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 1120 y(for)h(\(jj)g(=)g(0;)g(jj)h(<)
+f(naxes[1];)e(jj++\))382 1233 y(for)i(\(ii)g(=)g(0;)g(ii)g(<)h
+(naxes[0];)d(ii++\))573 1346 y(array[jj][ii])f(=)j(ii)h(+)f(jj;)191
+1571 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 1797 y(/*)g(Write)f(the)h
+(array)g(of)g(integers)e(to)j(the)f(image)f(*/)191 1910
+y(fits_write_img\(fptr,)c(TSHORT,)k(fpixel,)g(nelements,)f(array[0],)g
+(&status\);)191 2136 y(fits_close_file\(fptr,)d(&status\);)570
+b(/*)47 b(close)g(the)g(file)f(*/)191 2362 y(fits_report_error\(stderr)
+o(,)c(status\);)93 b(/*)47 b(print)g(out)g(any)f(error)h(messages)e(*/)
+191 2475 y(return\()h(status)g(\);)0 2588 y(})p eop end
+%%Page: 12 20
+TeXDict begin 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 end
+%%Page: 13 21
+TeXDict begin 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)23 b(section)j(giv)m
+(es)f(a)g(brief)e(o)m(v)m(erview)j(of)e(the)h(structure)e(of)i(FITS)e
+(\014les.)38 b(Users)24 b(should)g(refer)f(to)i(the)g(do)s(cumen-)0
+2293 y(tation)j(a)m(v)-5 b(ailable)30 b(from)d(the)g(NOST,)f(as)i
+(describ)s(ed)e(in)h(the)g(in)m(tro)s(duction,)h(for)f(more)g(detailed)
+i(information)e(on)0 2406 y(FITS)j(formats.)0 2566 y(FITS)e(w)m(as)h
+(\014rst)g(dev)m(elop)s(ed)g(in)f(the)h(late)i(1970's)g(as)e(a)g
+(standard)f(data)i(in)m(terc)m(hange)g(format)f(b)s(et)m(w)m(een)h(v)-5
+b(arious)0 2679 y(astronomical)36 b(observ)-5 b(atories.)52
+b(Since)34 b(then)g(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)h(data)f
+(analysis)g(soft)m(w)m(are)h(pac)m(k)-5 b(ages.)0 2952
+y(A)34 b(FITS)f(\014le)g(consists)h(of)g(one)g(or)g(more)g(Header)g(+)f
+(Data)i(Units)f(\(HDUs\),)i(where)d(the)h(\014rst)f(HDU)h(is)g(called)0
+3065 y(the)j(`Primary)f(HDU',)i(or)f(`Primary)f(Arra)m(y'.)60
+b(The)36 b(primary)g(arra)m(y)h(con)m(tains)h(an)e(N-dimensional)i
+(arra)m(y)f(of)0 3177 y(pixels,)30 b(suc)m(h)g(as)g(a)h(1-D)g(sp)s
+(ectrum,)e(a)h(2-D)h(image,)h(or)e(a)g(3-D)i(data)e(cub)s(e.)40
+b(Six)30 b(di\013eren)m(t)g(primary)f(data)i(t)m(yp)s(es)0
+3290 y(are)j(supp)s(orted:)44 b(Unsigned)33 b(8-bit)h(b)m(ytes,)h
+(16-bit,)g(32-bit,)h(and)c(64-bit)j(signed)e(in)m(tegers,)i(and)e(32)h
+(and)f(64-bit)0 3403 y(\015oating)28 b(p)s(oin)m(t)e(reals.)40
+b(FITS)27 b(also)g(has)g(a)g(con)m(v)m(en)m(tion)i(for)d(storing)i(16)f
+(and)f(32-bit)i(unsigned)e(in)m(tegers)i(\(see)g(the)0
+3516 y(later)k(section)h(en)m(titled)g(`Unsigned)e(In)m(tegers')h(for)f
+(more)h(details\).)44 b(The)31 b(primary)g(HDU)h(ma)m(y)g(also)g
+(consist)g(of)0 3629 y(only)e(a)h(header)f(with)h(a)f(n)m(ull)h(arra)m
+(y)f(con)m(taining)i(no)f(data)g(pixels.)0 3789 y(An)m(y)i(n)m(um)m(b)s
+(er)e(of)h(additional)i(HDUs)f(ma)m(y)g(follo)m(w)h(the)e(primary)g
+(arra)m(y;)i(these)f(additional)h(HDUs)f(are)g(called)0
+3902 y(FITS)d(`extensions'.)41 b(There)30 b(are)h(curren)m(tly)f(3)h(t)
+m(yp)s(es)g(of)f(extensions)h(de\014ned)e(b)m(y)h(the)h(FITS)f
+(standard:)136 4171 y Fc(\017)46 b Fj(Image)31 b(Extension)g(-)g(a)f
+(N-dimensional)h(arra)m(y)g(of)g(pixels,)g(lik)m(e)g(in)f(a)h(primary)e
+(arra)m(y)136 4368 y Fc(\017)46 b Fj(ASCI)s(I)29 b(T)-8
+b(able)31 b(Extension)g(-)f(ro)m(ws)h(and)e(columns)h(of)h(data)g(in)f
+(ASCI)s(I)f(c)m(haracter)j(format)136 4564 y Fc(\017)46
+b Fj(Binary)31 b(T)-8 b(able)31 b(Extension)f(-)h(ro)m(ws)f(and)g
+(columns)g(of)h(data)g(in)f(binary)f(represen)m(tation)0
+4833 y(In)k(eac)m(h)i(case)g(the)f(HDU)h(consists)g(of)f(an)g(ASCI)s(I)
+e(Header)i(Unit)h(follo)m(w)m(ed)g(b)m(y)f(an)g(optional)h(Data)g
+(Unit.)52 b(F)-8 b(or)0 4946 y(historical)37 b(reasons,)g(eac)m(h)f
+(Header)g(or)g(Data)h(unit)e(m)m(ust)g(b)s(e)g(an)g(exact)i(m)m
+(ultiple)f(of)g(2880)h(8-bit)f(b)m(ytes)g(long.)0 5059
+y(An)m(y)30 b(un)m(used)g(space)g(is)h(padded)e(with)h(\014ll)g(c)m
+(haracters)i(\(ASCI)s(I)d(blanks)h(or)h(zeros\).)0 5219
+y(Eac)m(h)i(Header)f(Unit)h(consists)g(of)f(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')
+g(whic)m(h)0 5332 y(ha)m(v)m(e)f(the)e(general)i(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 end
+%%Page: 14 22
+TeXDict begin 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)g(and)e
+(can)h(only)h(con)m(tain)g(upp)s(ercase)e(letters,)k(the)0
+668 y(digits)25 b(0-9,)i(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)f(\(usually\))h
+(follo)m(w)m(ed)i(b)m(y)d(an)0 781 y(equals)29 b(sign)g(and)f(a)g
+(space)i(c)m(haracter)g(\(=)e(\))h(in)f(columns)h(9)g(-)f(10)i(of)f
+(the)f(record,)h(follo)m(w)m(ed)i(b)m(y)d(the)h(v)-5
+b(alue)29 b(of)g(the)0 894 y(k)m(eyw)m(ord)34 b(whic)m(h)g(ma)m(y)g(b)s
+(e)f(either)h(an)g(in)m(teger,)i(a)e(\015oating)g(p)s(oin)m(t)g(n)m(um)
+m(b)s(er,)g(a)g(c)m(haracter)h(string)e(\(enclosed)i(in)0
+1007 y(single)28 b(quotes\),)i(or)e(a)g(b)s(o)s(olean)g(v)-5
+b(alue)28 b(\(the)g(letter)h(T)f(or)f(F\).)i(A)f(k)m(eyw)m(ord)g(ma)m
+(y)h(also)f(ha)m(v)m(e)h(a)g(n)m(ull)e(or)h(unde\014ned)0
+1120 y(v)-5 b(alue)31 b(if)f(there)h(is)f(no)g(sp)s(eci\014ed)g(v)-5
+b(alue)31 b(string,)g(as)f(in)g(the)h(second)f(example,)i(ab)s(o)m(v)m
+(e)0 1280 y(The)42 b(last)h(k)m(eyw)m(ord)g(in)f(the)h(header)f(is)g
+(alw)m(a)m(ys)i(the)f(`END')g(k)m(eyw)m(ord)g(whic)m(h)f(has)g(no)h(v)
+-5 b(alue)42 b(or)h(commen)m(t)0 1393 y(\014elds.)d(There)30
+b(are)h(man)m(y)f(rules)g(go)m(v)m(erning)i(the)e(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)f(is)h(b)s(etter)f(to)h(rely)f(on)g
+(standard)g(in)m(terface)h(soft)m(w)m(are)h(lik)m(e)f(CFITSIO)e(to)i
+(correctly)h(construct)0 1619 y(or)h(to)h(parse)g(the)f(k)m(eyw)m(ord)h
+(records)f(rather)g(than)h(try)f(to)h(deal)g(directly)g(with)f(the)g
+(ra)m(w)h(FITS)f(formats.)0 1779 y(Eac)m(h)37 b(Header)g(Unit)f(b)s
+(egins)g(with)g(a)g(series)h(of)f(required)g(k)m(eyw)m(ords)g(whic)m(h)
+g(dep)s(end)f(on)h(the)g(t)m(yp)s(e)h(of)f(HDU.)0 1892
+y(These)31 b(required)g(k)m(eyw)m(ords)h(sp)s(ecify)g(the)f(size)i(and)
+e(format)h(of)g(the)g(follo)m(wing)h(Data)g(Unit.)45
+b(The)31 b(header)g(ma)m(y)0 2005 y(con)m(tain)h(other)f(optional)g(k)m
+(eyw)m(ords)g(to)h(describ)s(e)e(other)g(asp)s(ects)h(of)g(the)g(data,)
+g(suc)m(h)g(as)g(the)f(units)g(or)h(scaling)0 2118 y(v)-5
+b(alues.)44 b(Other)31 b(COMMENT)g(or)g(HISTOR)-8 b(Y)30
+b(k)m(eyw)m(ords)i(are)g(also)g(frequen)m(tly)g(added)e(to)i(further)e
+(do)s(cumen)m(t)0 2230 y(the)h(data)g(\014le.)0 2391
+y(The)36 b(optional)h(Data)h(Unit)f(immediately)g(follo)m(ws)h(the)e
+(last)h(2880-b)m(yte)i(blo)s(c)m(k)e(in)f(the)g(Header)h(Unit.)59
+b(Some)0 2503 y(HDUs)31 b(do)f(not)h(ha)m(v)m(e)g(a)g(Data)h(Unit)f
+(and)f(only)g(consist)h(of)g(the)f(Header)h(Unit.)0 2664
+y(If)24 b(there)i(is)f(more)g(than)f(one)h(HDU)h(in)f(the)g(FITS)f
+(\014le,)i(then)f(the)g(Header)h(Unit)f(of)g(the)g(next)g(HDU)h
+(immediately)0 2777 y(follo)m(ws)g(the)e(last)i(2880-b)m(yte)h(blo)s(c)
+m(k)e(of)g(the)f(previous)g(Data)j(Unit)d(\(or)h(Header)g(Unit)g(if)f
+(there)h(is)g(no)f(Data)i(Unit\).)0 2937 y(The)k(main)g(required)g(k)m
+(eyw)m(ords)g(in)g(FITS)g(primary)g(arra)m(ys)g(or)h(image)g
+(extensions)g(are:)136 3172 y Fc(\017)46 b Fj(BITPIX)32
+b({)g(de\014nes)e(the)i(data)g(t)m(yp)s(e)g(of)g(the)g(arra)m(y:)43
+b(8,)33 b(16,)g(32,)g(64,)g(-32,)g(-64)g(for)e(unsigned)f(8{bit)j(b)m
+(yte,)227 3284 y(16{bit)41 b(signed)f(in)m(teger,)j(32{bit)f(signed)d
+(in)m(teger,)44 b(32{bit)d(IEEE)e(\015oating)h(p)s(oin)m(t,)i(and)e
+(64{bit)h(IEEE)227 3397 y(double)30 b(precision)h(\015oating)g(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)g(in)g(the)
+h(arra)m(y)-8 b(,)31 b(usually)f(0,)h(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)g(of)g(eac)m(h)g(dimension.)0
+4008 y(FITS)e(tables)i(start)g(with)f(the)g(k)m(eyw)m(ord)g(XTENSION)g
+(=)f(`T)-8 b(ABLE')31 b(\(for)f(ASCI)s(I)f(tables\))i(or)f(XTENSION)f
+(=)0 4120 y(`BINT)-8 b(ABLE')32 b(\(for)e(binary)g(tables\))h(and)f(ha)
+m(v)m(e)i(the)e(follo)m(wing)i(main)e(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)g(or)h(columns)f(in)g(the)g(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)f
+(the)g(table)136 4731 y Fc(\017)46 b Fj(TTYPEn)29 b({)i(for)f(eac)m(h)i
+(column)e(\(n)g(ranges)h(from)f(1)g(to)h(TFIELDS\))g(giv)m(es)g(the)g
+(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)g(units)f(of)g
+(the)h(column)f(\(optional\))0 5341 y(Users)k(should)f(refer)h(to)h
+(the)f(FITS)g(Supp)s(ort)e(O\016ce)i(at)h Fe(http://fits.gsfc.nasa.gov)
+27 b Fj(for)34 b(further)f(infor-)0 5454 y(mation)e(ab)s(out)f(the)h
+(FITS)e(format)i(and)f(related)h(soft)m(w)m(are)h(pac)m(k)-5
+b(ages.)p eop end
+%%Page: 15 23
+TeXDict begin 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)k(m)m(ust)e(include)g(the)h
+(\014tsio.h)f(header)g(\014le)h(with)f(the)g(state-)0
+2579 y(men)m(t)95 2818 y Fe(#include)46 b("fitsio.h")0
+3057 y Fj(This)30 b(header)h(\014le)h(con)m(tains)g(the)f(protot)m(yp)s
+(es)h(for)f(all)h(the)f(CFITSIO)f(user)g(in)m(terface)j(routines)e(as)g
+(w)m(ell)h(as)g(the)0 3170 y(de\014nitions)g(of)g(v)-5
+b(arious)32 b(constan)m(ts)h(used)e(in)h(the)h(in)m(terface.)47
+b(It)32 b(also)h(de\014nes)e(a)i(C)f(structure)f(of)h(t)m(yp)s(e)h
+(`\014ts\014le')0 3283 y(that)j(is)g(used)f(b)m(y)g(CFITSIO)f(to)j
+(store)f(the)g(relev)-5 b(an)m(t)37 b(parameters)f(that)g(de\014ne)f
+(the)h(format)g(of)g(a)g(particular)0 3396 y(FITS)c(\014le.)48
+b(Application)34 b(programs)f(m)m(ust)g(de\014ne)f(a)h(p)s(oin)m(ter)g
+(to)g(this)g(structure)g(for)f(eac)m(h)i(FITS)e(\014le)h(that)h(is)0
+3508 y(to)i(b)s(e)f(op)s(ened.)56 b(This)35 b(structure)g(is)h
+(initialized)h(\(i.e.,)i(memory)c(is)h(allo)s(cated)h(for)f(the)g
+(structure\))f(when)g(the)0 3621 y(FITS)h(\014le)g(is)h(\014rst)e(op)s
+(ened)h(or)g(created)i(with)e(the)g(\014ts)p 1949 3621
+28 4 v 33 w(op)s(en)p 2172 3621 V 32 w(\014le)g(or)h(\014ts)p
+2596 3621 V 32 w(create)p 2864 3621 V 34 w(\014le)g(routines.)59
+b(This)35 b(\014ts\014le)0 3734 y(p)s(oin)m(ter)c(is)h(then)f(passed)g
+(as)g(the)h(\014rst)e(argumen)m(t)i(to)g(ev)m(ery)g(other)g(CFITSIO)d
+(routine)j(that)g(op)s(erates)g(on)f(the)0 3847 y(FITS)h(\014le.)48
+b(Application)34 b(programs)f(m)m(ust)g(not)g(directly)g(read)g(or)g
+(write)g(elemen)m(ts)h(in)f(this)g(\014ts\014le)f(structure)0
+3960 y(b)s(ecause)e(the)h(de\014nition)f(of)h(the)f(structure)g(ma)m(y)
+h(c)m(hange)g(in)g(future)e(v)m(ersions)i(of)f(CFITSIO.)0
+4120 y(A)45 b(n)m(um)m(b)s(er)e(of)i(sym)m(b)s(olic)g(constan)m(ts)h
+(are)f(also)g(de\014ned)f(in)g(\014tsio.h)h(for)f(the)h(con)m(v)m
+(enience)i(of)e(application)0 4233 y(programmers.)55
+b(Use)35 b(of)h(these)f(sym)m(b)s(olic)h(constan)m(ts)g(rather)f(than)g
+(the)h(actual)g(n)m(umeric)f(v)-5 b(alue)36 b(will)f(help)g(to)0
+4346 y(mak)m(e)c(the)g(source)f(co)s(de)h(more)g(readable)f(and)g
+(easier)i(for)e(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 end
+%%Page: 16 24
+TeXDict begin 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(LONGLONG_IMG)f(64)95 b(/*)47 b(64-bit)141
+b(signed)46 b(integers)g(*/)95 2023 y(#define)g(FLOAT_IMG)141
+b(-32)95 b(/*)47 b(32-bit)f(single)g(precision)f(floating)h(point)g(*/)
+95 2136 y(#define)g(DOUBLE_IMG)93 b(-64)i(/*)47 b(64-bit)f(double)g
+(precision)f(floating)h(point)g(*/)95 2362 y(The)h(following)f(4)h
+(data)g(type)f(codes)h(are)g(also)f(supported)g(by)h(CFITSIO:)95
+2475 y(#define)f(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(TLONG)381 b(41)95 b(/*)47 b(signed)f(long,)905
+b(*/)95 4507 y(#define)46 b(TLONGLONG)189 b(81)95 b(/*)47
+b(64-bit)f(long)h(signed)f(integer)f('K')i(*/)95 4620
+y(#define)f(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 end
+%%Page: 17 25
+TeXDict begin 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 781 y(The)47 b(following)f(data)g(type)h
+(code)g(is)g(only)f(for)h(use)g(with)g(fits\\_get\\_coltype)95
+894 y(#define)f(TINT32BIT)189 b(41)95 b(/*)47 b(signed)f(32-bit)g(int,)
+428 b('J')47 b(*/)0 1233 y(HDU)g(type)g(code)f(values)g(\(value)g
+(returned)g(when)h(moving)f(to)h(new)g(HDU\):)95 1458
+y(#define)f(IMAGE_HDU)93 b(0)i(/*)48 b(Primary)d(Array)i(or)g(IMAGE)f
+(HDU)h(*/)95 1571 y(#define)f(ASCII_TBL)93 b(1)i(/*)48
+b(ASCII)94 b(table)46 b(HDU)h(*/)95 1684 y(#define)f(BINARY_TBL)f(2)95
+b(/*)48 b(Binary)e(table)g(HDU)h(*/)95 1797 y(#define)f(ANY_HDU)142
+b(-1)94 b(/*)48 b(matches)d(any)i(type)g(of)g(HDU)g(*/)0
+2023 y(Column)f(name)h(and)g(string)f(matching)f(case-sensitivity:)95
+2249 y(#define)h(CASESEN)142 b(1)g(/*)48 b(do)f(case-sensitive)d
+(string)i(match)g(*/)95 2362 y(#define)g(CASEINSEN)g(0)142
+b(/*)48 b(do)f(case-insensitive)c(string)j(match)h(*/)0
+2588 y(Logical)f(states)g(\(if)h(TRUE)f(and)h(FALSE)g(are)g(not)g
+(already)e(defined\):)95 2813 y(#define)h(TRUE)h(1)95
+2926 y(#define)f(FALSE)h(0)0 3152 y(Values)f(to)h(represent)f
+(undefined)f(floating)g(point)i(numbers:)95 3378 y(#define)f
+(FLOATNULLVALUE)92 b(-9.11912E-36F)95 3491 y(#define)46
+b(DOUBLENULLVALUE)e(-9.1191291391491E-36)0 3717 y(Image)i(compression)f
+(algorithm)g(definitions)95 3942 y(#define)h(RICE_1)333
+b(11)95 4055 y(#define)46 b(GZIP_1)333 b(21)95 4168 y(#define)46
+b(PLIO_1)333 b(31)95 4281 y(#define)46 b(HCOMPRESS_1)93
+b(41)0 4664 y Ff(4.2)135 b(Curren)l(t)46 b(Header)f(Data)h(Unit)g
+(\(CHDU\))0 4924 y Fj(The)37 b(concept)h(of)g(the)f(Curren)m(t)g
+(Header)g(and)g(Data)i(Unit,)h(or)d(CHDU,)h(is)f(fundamen)m(tal)h(to)g
+(the)f(use)g(of)h(the)0 5036 y(CFITSIO)31 b(library)-8
+b(.)46 b(A)32 b(simple)h(FITS)e(image)j(ma)m(y)f(only)f(con)m(tain)i(a)
+e(single)h(Header)g(and)f(Data)h(unit)f(\(HDU\),)0 5149
+y(but)39 b(in)g(general)i(FITS)e(\014les)h(can)g(con)m(tain)h(m)m
+(ultiple)g(Header)f(Data)h(Units)f(\(also)h(kno)m(wn)e(as)h
+(`extensions'\),)0 5262 y(concatenated)c(one)f(after)f(the)h(other)f
+(in)g(the)g(\014le.)53 b(The)33 b(user)h(can)g(sp)s(ecify)g(whic)m(h)g
+(HDU)h(should)e(b)s(e)g(initially)0 5375 y(op)s(ened)j(at)i(run)d(time)
+j(b)m(y)f(giving)h(the)f(HDU)h(name)f(or)g(n)m(um)m(b)s(er)f(after)h
+(the)g(ro)s(ot)h(\014le)f(name.)60 b(F)-8 b(or)38 b(example,)0
+5488 y('m)m(y\014le.\014ts[4]')i(op)s(ens)d(the)h(5th)h(HDU)g(in)f(the)
+g(\014le)g(\(note)h(that)g(the)f(n)m(um)m(b)s(ering)f(starts)i(with)f
+(0\),)j(and)c('m)m(y-)0 5601 y(\014le.\014ts[EVENTS])k(op)s(ens)f(the)h
+(HDU)h(with)e(the)h(name)g('EVENTS')g(\(as)g(de\014ned)f(b)m(y)h(the)g
+(EXTNAME)g(or)0 5714 y(HDUNAME)35 b(k)m(eyw)m(ords\).)50
+b(If)33 b(no)g(HDU)h(is)f(sp)s(eci\014ed)g(then)g(CFITSIO)e(op)s(ens)i
+(the)g(\014rst)g(HDU)h(\(the)g(primary)p eop end
+%%Page: 18 26
+TeXDict begin 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 Fj(arra)m(y\))24
+b(b)m(y)e(default.)39 b(The)22 b(CFITSIO)f(routines)i(whic)m(h)g(read)f
+(and)g(write)i(data)f(only)g(op)s(erate)g(within)g(the)g(op)s(ened)0
+668 y(HDU,)32 b(Other)e(CFITSIO)f(routines)i(are)g(pro)m(vided)f(to)i
+(mo)m(v)m(e)g(to)f(and)f(op)s(en)g(an)m(y)h(other)g(existing)h(HDU)f
+(within)0 781 y(the)g(FITS)e(\014le)i(or)f(to)h(app)s(end)e(or)h
+(insert)g(new)g(HDUs)h(in)f(the)h(FITS)f(\014le.)0 1111
+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 1361 y Fj(Most)33 b(of)f(the)g
+(CFITSIO)f(routines)h(ha)m(v)m(e)h(b)s(oth)e(a)i(short)e(name)h(as)h(w)
+m(ell)g(as)f(a)g(longer)h(descriptiv)m(e)g(name.)45 b(The)0
+1474 y(short)32 b(name)g(is)g(only)g(5)h(or)f(6)g(c)m(haracters)h(long)
+g(and)f(is)g(similar)g(to)h(the)f(subroutine)f(name)h(in)g(the)g(F)-8
+b(ortran-77)0 1587 y(v)m(ersion)38 b(of)g(FITSIO.)f(The)h(longer)g
+(name)g(is)g(more)g(descriptiv)m(e)h(and)e(it)h(is)g(recommended)g
+(that)g(it)h(b)s(e)e(used)0 1699 y(instead)31 b(of)f(the)h(short)f
+(name)g(to)h(more)g(clearly)h(do)s(cumen)m(t)e(the)g(source)h(co)s(de.)
+0 1860 y(Man)m(y)c(of)f(the)g(CFITSIO)f(routines)h(come)h(in)e
+(families)i(whic)m(h)f(di\013er)g(only)g(in)g(the)g(data)h(t)m(yp)s(e)f
+(of)g(the)g(asso)s(ciated)0 1973 y(parameter\(s\).)45
+b(The)31 b(data)h(t)m(yp)s(e)g(of)g(these)g(routines)f(is)h(indicated)g
+(b)m(y)f(the)h(su\016x)e(of)i(the)g(routine)f(name.)44
+b(The)0 2085 y(short)27 b(routine)h(names)g(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)h('\013pkyj'\))g
+(while)f(the)h(long)g(routine)g(names)0 2198 y(ha)m(v)m(e)k(a)e(4)h(c)m
+(haracter)h(or)e(longer)h(su\016x)f(as)g(sho)m(wn)g(in)g(the)h(follo)m
+(wing)h(table:)191 2432 y Fe(Long)285 b(Short)94 b(Data)191
+2545 y(Names)237 b(Names)94 b(Type)191 2658 y(-----)237
+b(-----)94 b(----)191 2771 y(_bit)381 b(x)190 b(bit)191
+2883 y(_byt)381 b(b)190 b(unsigned)46 b(byte)191 2996
+y(_sbyt)333 b(sb)142 b(signed)46 b(byte)191 3109 y(_sht)381
+b(i)190 b(short)47 b(integer)191 3222 y(_lng)381 b(j)190
+b(long)47 b(integer)191 3335 y(_lnglng)237 b(jj)142 b(8-byte)46
+b(LONGLONG)g(integer)g(\(see)g(note)h(below\))191 3448
+y(_usht)333 b(ui)142 b(unsigned)46 b(short)g(integer)191
+3561 y(_ulng)333 b(uj)142 b(unsigned)46 b(long)g(integer)191
+3674 y(_uint)333 b(uk)142 b(unsigned)46 b(int)h(integer)191
+3787 y(_int)381 b(k)190 b(int)47 b(integer)191 3900 y(_flt)381
+b(e)190 b(real)47 b(exponential)e(floating)g(point)i(\(float\))191
+4013 y(_fixflt)237 b(f)190 b(real)47 b(fixed-decimal)d(format)i
+(floating)g(point)g(\(float\))191 4125 y(_dbl)381 b(d)190
+b(double)46 b(precision)g(real)g(floating-point)e(\(double\))191
+4238 y(_fixdbl)237 b(g)190 b(double)46 b(precision)g(fixed-format)e
+(floating)i(point)g(\(double\))191 4351 y(_cmp)381 b(c)190
+b(complex)46 b(reals)g(\(pairs)h(of)g(float)f(values\))191
+4464 y(_fixcmp)237 b(fc)142 b(complex)46 b(reals,)g(fixed-format)f
+(floating)g(point)191 4577 y(_dblcmp)237 b(m)190 b(double)46
+b(precision)g(complex)f(\(pairs)i(of)g(double)f(values\))191
+4690 y(_fixdblcmp)93 b(fm)142 b(double)46 b(precision)g(complex,)f
+(fixed-format)g(floating)g(point)191 4803 y(_log)381
+b(l)190 b(logical)46 b(\(int\))191 4916 y(_str)381 b(s)190
+b(character)46 b(string)0 5149 y Fj(The)32 b(logical)j(data)f(t)m(yp)s
+(e)f(corresp)s(onds)e(to)j(`in)m(t')f(for)g(logical)i(k)m(eyw)m(ord)e
+(v)-5 b(alues,)34 b(and)e(`b)m(yte')i(for)f(logical)i(binary)0
+5262 y(table)40 b(columns.)67 b(In)39 b(other)g(w)m(ords,)i(the)f(v)-5
+b(alue)39 b(when)g(writing)g(a)h(logical)h(k)m(eyw)m(ord)f(m)m(ust)f(b)
+s(e)g(stored)g(in)g(an)0 5375 y(`in)m(t')g(v)-5 b(ariable,)40
+b(and)e(m)m(ust)f(b)s(e)g(stored)h(in)g(a)g(`c)m(har')h(arra)m(y)f
+(when)f(reading)h(or)f(writing)h(to)h(`L')f(columns)f(in)h(a)0
+5488 y(binary)c(table.)56 b(Implicit)35 b(data)h(t)m(yp)s(e)f(con)m(v)m
+(ersion)i(is)e(not)g(supp)s(orted)e(for)i(logical)j(table)e(columns,)g
+(but)e(is)h(for)0 5601 y(k)m(eyw)m(ords,)30 b(so)f(a)h(logical)h(k)m
+(eyw)m(ord)f(ma)m(y)f(b)s(e)g(read)f(and)h(cast)h(to)g(an)m(y)f(n)m
+(umerical)h(data)f(t)m(yp)s(e;)h(a)g(returned)d(v)-5
+b(alue)0 5714 y(=)30 b(0)h(indicates)g(false,)g(and)f(an)m(y)h(other)f
+(v)-5 b(alue)31 b(=)f(true.)p eop end
+%%Page: 19 27
+TeXDict begin 19 26 bop 0 299 a Fh(4.3.)72 b(FUNCTION)30
+b(NAMES)h(AND)g(V)-10 b(ARIABLE)30 b(D)m(A)-8 b(T)g(A)g(TYPES)1409
+b Fj(19)0 555 y(The)24 b(`in)m(t')i(data)g(t)m(yp)s(e)f(ma)m(y)h(b)s(e)
+e(2)h(b)m(ytes)h(long)f(on)g(some)g(old)g(PC)g(compilers,)h(but)f
+(otherwise)g(it)g(is)g(nearly)g(alw)m(a)m(ys)0 668 y(4)i(b)m(ytes)g
+(long.)40 b(Some)27 b(64-bit)h(mac)m(hines,)g(lik)m(e)g(the)f
+(Alpha/OSF,)g(de\014ne)f(the)h(`short',)h(`in)m(t',)h(and)d(`long')i
+(in)m(teger)0 781 y(data)j(t)m(yp)s(es)f(to)i(b)s(e)d(2,)i(4,)g(and)f
+(8)h(b)m(ytes)g(long,)g(resp)s(ectiv)m(ely)-8 b(.)0 941
+y(Because)40 b(there)e(is)h(no)f(univ)m(ersal)h(C)f(compiler)g
+(standard)g(for)g(the)h(name)f(of)h(the)f(8-b)m(yte)i(in)m(teger)g
+(datat)m(yp)s(e,)0 1054 y(the)33 b(\014tsio.h)h(include)f(\014le)g(t)m
+(yp)s(edef)7 b('s)33 b('LONGLONG')h(to)g(b)s(e)e(equiv)-5
+b(alen)m(t)35 b(to)f(an)f(appropriate)g(8-b)m(yte)i(in)m(teger)0
+1167 y(data)c(t)m(yp)s(e)g(on)f(eac)m(h)i(supp)s(orted)d(platform.)41
+b(F)-8 b(or)31 b(maxim)m(um)f(soft)m(w)m(are)i(p)s(ortabilit)m(y)g(it)f
+(is)f(recommended)g(that)0 1280 y(this)g(LONGLONG)g(datat)m(yp)s(e)h(b)
+s(e)e(used)g(to)i(de\014ne)e(8-b)m(yte)i(in)m(teger)h(v)-5
+b(ariables)30 b(rather)g(than)g(using)f(the)i(nativ)m(e)0
+1393 y(data)h(t)m(yp)s(e)g(name)f(on)h(a)f(particular)h(platform.)44
+b(On)31 b(most)h(32-bit)g(Unix)g(and)e(Mac)j(OS-X)e(op)s(erating)h
+(systems)0 1506 y(LONGLONG)h(is)f(equiv)-5 b(alen)m(t)34
+b(to)f(the)g(in)m(trinsic)g('long)g(long')h(8-b)m(yte)g(in)m(teger)f
+(datat)m(yp)s(e.)49 b(On)31 b(64-bit)j(systems)0 1619
+y(\(whic)m(h)e(curren)m(tly)g(includes)f(Alpha)h(OSF/1,)g(64-bit)h(Sun)
+e(Solaris,)h(64-bit)h(SGI)f(MIPS,)f(and)g(64-bit)i(Itanium)0
+1732 y(and)28 b(Opteron)g(PC)h(systems\),)g(LONGLONG)g(is)g(simply)f(t)
+m(yp)s(edef)7 b('ed)29 b(to)g(b)s(e)g(equiv)-5 b(alen)m(t)30
+b(to)f('long'.)42 b(Microsoft)0 1844 y(Visual)33 b(C++)e(V)-8
+b(ersion)33 b(6.0)g(do)s(es)f(not)g(de\014ne)g(a)h('long)g(long')g
+(data)g(t)m(yp)s(e,)g(so)f(LONGLONG)h(is)f(t)m(yp)s(edef)7
+b('ed)32 b(to)0 1957 y(b)s(e)e(equiv)-5 b(alen)m(t)32
+b(to)f(the)f(')p 853 1957 28 4 v 887 1957 V 66 w(in)m(t64')i(data)f(t)m
+(yp)s(e)g(on)f(32-bit)h(windo)m(ws)f(systems)h(when)e(using)h(Visual)h
+(C++.)0 2118 y(A)j(related)h(issue)e(that)i(a\013ects)g(the)f(p)s
+(ortabilit)m(y)g(of)g(soft)m(w)m(are)i(is)d(ho)m(w)h(to)h(prin)m(t)e
+(out)h(the)g(v)-5 b(alue)34 b(of)g(a)g('LONG-)0 2230
+y(LONG')e(v)-5 b(ariable)32 b(with)f(prin)m(tf.)44 b(Dev)m(elop)s(ers)
+33 b(ma)m(y)f(\014nd)e(it)i(con)m(v)m(enien)m(t)h(to)g(use)e(the)h
+(follo)m(wing)h(prepro)s(cessing)0 2343 y(statemen)m(ts)f(in)e(their)h
+(C)f(programs)g(to)h(handle)f(this)g(in)g(a)h(mac)m(hine-p)s(ortable)g
+(manner:)0 2593 y Fe(#if)47 b(defined\(_MSC_VER\))c(/*)k(Microsoft)e
+(Visual)i(C++)f(*/)477 2706 y(printf\("\045I64d",)e(longlongvalue\);)0
+2932 y(#elif)i(\(USE_LL_SUFFIX)e(==)j(1\))477 3045 y
+(printf\("\045lld",)d(longlongvalue\);)0 3271 y(#else)477
+3384 y(printf\("\045ld",)g(longlongvalue\);)0 3496 y(#endif)0
+3746 y Fj(Similarly)-8 b(,)32 b(the)f(name)g(of)g(the)h(C)e(utilit)m(y)
+j(routine)e(that)g(con)m(v)m(erts)i(a)e(c)m(haracter)i(string)d(of)i
+(digits)f(in)m(to)h(a)g(8-b)m(yte)0 3859 y(in)m(teger)g(v)-5
+b(alue)31 b(is)f(platform)g(dep)s(enden)m(t:)0 4109 y
+Fe(#if)47 b(defined\(_MSC_VER\))c(/*)k(Microsoft)e(Visual)i(C++)f(*/)
+286 4222 y(/*)i(VC++)e(6.0)h(does)g(not)g(seem)f(to)h(have)g(an)g
+(8-byte)f(conversion)f(routine)h(*/)0 4448 y(#elif)g(\(USE_LL_SUFFIX)e
+(==)j(1\))477 4561 y(longlongvalue)d(=)k(atoll\(*string\);)0
+4787 y(#else)477 4899 y(longlongvalue)c(=)k(atol\(*string\);)0
+5012 y(#endif)0 5262 y Fj(When)23 b(dealing)h(with)f(the)h(FITS)f(b)m
+(yte)h(data)g(t)m(yp)s(e)f(it)h(is)g(imp)s(ortan)m(t)f(to)h(remem)m(b)s
+(er)f(that)h(the)g(ra)m(w)f(v)-5 b(alues)24 b(\(b)s(efore)0
+5375 y(an)m(y)h(scaling)g(b)m(y)f(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\))25
+b(in)f(b)m(yte)h(arra)m(ys)0 5488 y(\(BITPIX)37 b(=)f(8\))h(or)f(b)m
+(yte)i(columns)e(\(TF)m(ORMn)h(=)f('B'\))h(are)g(in)m(terpreted)g(as)g
+(unsigned)e(b)m(ytes)i(with)g(v)-5 b(alues)0 5601 y(ranging)34
+b(from)g(0)g(to)h(255.)53 b(Some)34 b(C)g(compilers)h(de\014ne)e(a)h
+('c)m(har')h(v)-5 b(ariable)35 b(as)g(signed,)g(so)f(it)h(is)f(imp)s
+(ortan)m(t)g(to)0 5714 y(explicitly)e(declare)f(a)g(n)m(umeric)f(c)m
+(har)h(v)-5 b(ariable)31 b(as)g('unsigned)e(c)m(har')i(to)g(a)m(v)m
+(oid)h(an)m(y)f(am)m(biguit)m(y)p eop end
+%%Page: 20 28
+TeXDict begin 20 27 bop 0 299 a Fj(20)1763 b Fh(CHAPTER)29
+b(4.)112 b(PR)m(OGRAMMING)32 b(GUIDELINES)0 555 y Fj(One)22
+b(feature)h(of)g(the)g(CFITSIO)e(routines)i(is)f(that)i(they)f(can)g
+(op)s(erate)g(on)f(a)h(`X')h(\(bit\))f(column)g(in)f(a)h(binary)f
+(table)0 668 y(as)33 b(though)f(it)h(w)m(ere)g(a)g(`B')g(\(b)m(yte\))h
+(column.)47 b(F)-8 b(or)33 b(example)g(a)g(`11X')h(data)f(t)m(yp)s(e)g
+(column)f(can)h(b)s(e)f(in)m(terpreted)0 781 y(the)c(same)h(as)f(a)g
+(`2B')i(column)e(\(i.e.,)i(2)e(unsigned)f(8-bit)i(b)m(ytes\).)41
+b(In)27 b(some)i(instances,)g(it)f(can)h(b)s(e)e(more)h(e\016cien)m(t)0
+894 y(to)j(read)f(and)g(write)h(whole)f(b)m(ytes)h(at)g(a)g(time,)g
+(rather)g(than)f(reading)g(or)h(writing)f(eac)m(h)i(individual)d(bit.)0
+1054 y(The)36 b(complex)i(and)e(double)h(precision)g(complex)h(data)g
+(t)m(yp)s(es)f(are)g(not)g(directly)h(supp)s(orted)d(in)i(ANSI)f(C)h
+(so)0 1167 y(these)g(data)g(t)m(yp)s(es)f(should)f(b)s(e)h(in)m
+(terpreted)h(as)f(pairs)g(of)h(\015oat)g(or)f(double)g(v)-5
+b(alues,)38 b(resp)s(ectiv)m(ely)-8 b(,)40 b(where)c(the)0
+1280 y(\014rst)30 b(v)-5 b(alue)30 b(in)h(eac)m(h)g(pair)f(is)h(the)f
+(real)h(part,)g(and)e(the)i(second)f(is)h(the)f(imaginary)h(part.)0
+1606 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 1856 y Fj(Although)33 b(FITS)f(do)s(es)g(not)h
+(directly)h(supp)s(ort)d(unsigned)g(in)m(tegers)j(as)f(one)g(of)g(its)h
+(fundamen)m(tal)e(data)i(t)m(yp)s(es,)0 1969 y(FITS)27
+b(can)h(still)h(b)s(e)e(used)g(to)i(e\016cien)m(tly)h(store)e(unsigned)
+f(in)m(teger)i(data)g(v)-5 b(alues)28 b(in)g(images)h(and)e(binary)g
+(tables.)0 2082 y(The)42 b(con)m(v)m(en)m(tion)j(used)d(in)g(FITS)g
+(\014les)h(is)f(to)i(store)f(the)g(unsigned)e(in)m(tegers)j(as)f
+(signed)g(in)m(tegers)h(with)e(an)0 2195 y(asso)s(ciated)34
+b(o\013set)f(\(sp)s(eci\014ed)f(b)m(y)g(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,)g(to)g(store)g
+(unsigned)0 2308 y(16-bit)g(in)m(teger)g(v)-5 b(alues)32
+b(in)f(a)h(FITS)f(image)i(the)e(image)i(w)m(ould)f(b)s(e)e(de\014ned)h
+(as)h(a)g(signed)f(16-bit)i(in)m(teger)g(\(with)0 2421
+y(BITPIX)c(k)m(eyw)m(ord)g(=)g(SHOR)-8 b(T)p 1132 2421
+28 4 v 32 w(IMG)30 b(=)e(16\))j(with)d(the)i(k)m(eyw)m(ords)f(BSCALE)f
+(=)h(1.0)h(and)f(BZER)m(O)g(=)f(32768.)0 2534 y(Th)m(us)34
+b(the)h(unsigned)f(v)-5 b(alues)35 b(of)g(0,)i(32768,)h(and)d(65535,)j
+(for)d(example,)i(are)e(ph)m(ysically)h(stored)f(in)g(the)g(FITS)0
+2647 y(image)40 b(as)e(-32768,)43 b(0,)e(and)d(32767,)k(resp)s(ectiv)m
+(ely;)i(CFITSIO)37 b(automatically)k(adds)c(the)i(BZER)m(O)f(o\013set)h
+(to)0 2759 y(these)g(v)-5 b(alues)39 b(when)f(they)g(are)h(read.)65
+b(Similarly)-8 b(,)42 b(in)c(the)h(case)h(of)e(unsigned)g(32-bit)i(in)m
+(tegers)f(the)g(BITPIX)0 2872 y(k)m(eyw)m(ord)c(w)m(ould)f(b)s(e)g
+(equal)h(to)h(LONG)p 1392 2872 V 32 w(IMG)f(=)g(32)g(and)f(BZER)m(O)g
+(w)m(ould)h(b)s(e)f(equal)h(to)g(2147483648)k(\(i.e.)55
+b(2)0 2985 y(raised)30 b(to)h(the)g(31st)g(p)s(o)m(w)m(er\).)0
+3145 y(The)j(CFITSIO)g(in)m(terface)i(routines)f(will)g(e\016cien)m
+(tly)i(and)d(transparen)m(tly)i(apply)e(the)h(appropriate)g(o\013set)h
+(in)0 3258 y(these)29 b(cases)h(so)f(in)g(general)h(application)g
+(programs)f(do)g(not)g(need)f(to)i(b)s(e)e(concerned)h(with)g(ho)m(w)g
+(the)g(unsigned)0 3371 y(v)-5 b(alues)44 b(are)h(actually)h(stored)e
+(in)f(the)i(FITS)e(\014le.)82 b(As)44 b(a)g(con)m(v)m(enience)j(for)c
+(users,)k(CFITSIO)c(has)h(sev)m(eral)0 3484 y(prede\014ned)19
+b(constan)m(ts)j(for)f(the)g(v)-5 b(alue)21 b(of)g(BITPIX)g(\(USHOR)-8
+b(T)p 2189 3484 V 33 w(IMG,)21 b(ULONG)p 2790 3484 V
+33 w(IMG\))h(and)e(for)h(the)g(TF)m(ORMn)0 3597 y(v)-5
+b(alue)36 b(in)f(the)h(case)g(of)g(binary)f(tables)h(\(`U')h(and)e
+(`V'\))h(whic)m(h)f(programmers)g(can)h(use)f(when)g(creating)i(FITS)0
+3710 y(\014les)i(con)m(taining)h(unsigned)e(in)m(teger)i(v)-5
+b(alues.)66 b(The)39 b(follo)m(wing)h(co)s(de)f(fragmen)m(t)g
+(illustrates)h(ho)m(w)f(to)h(write)f(a)0 3823 y(FITS)30
+b(1-D)h(primary)f(arra)m(y)g(of)h(unsigned)e(16-bit)j(in)m(tegers:)286
+4034 y Fe(unsigned)46 b(short)g(uarray[100];)286 4147
+y(int)h(naxis,)f(status;)286 4260 y(long)h(naxes[10],)e(group,)h
+(firstelem,)f(nelements;)334 4373 y(...)286 4486 y(status)h(=)i(0;)286
+4599 y(naxis)f(=)g(1;)286 4712 y(naxes[0])f(=)h(100;)286
+4825 y(fits_create_img\(fptr,)42 b(USHORT_IMG,)j(naxis,)h(naxes,)g
+(&status\);)286 5051 y(firstelem)g(=)h(1;)286 5164 y(nelements)f(=)h
+(100;)286 5276 y(fits_write_img\(fptr,)c(TUSHORT,)i(firstelem,)g
+(nelements,)1241 5389 y(uarray,)h(&status\);)334 5502
+y(...)0 5714 y Fj(In)40 b(the)h(ab)s(o)m(v)m(e)i(example,)h(the)e(2nd)e
+(parameter)h(in)g(\014ts)p 1998 5714 V 33 w(create)p
+2267 5714 V 34 w(img)g(tells)h(CFITSIO)e(to)i(write)f(the)g(header)p
+eop end
+%%Page: 21 29
+TeXDict begin 21 28 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(21)0 555 y(k)m(eyw)m(ords)34 b(appropriate)g(for)f(an)g(arra)m(y)i
+(of)e(16-bit)i(unsigned)e(in)m(tegers)i(\(i.e.,)h(BITPIX)d(=)g(16)i
+(and)e(BZER)m(O)g(=)0 668 y(32768\).)41 b(Then)23 b(the)h(\014ts)p
+834 668 28 4 v 32 w(write)p 1068 668 V 33 w(img)h(routine)f(writes)f
+(the)i(arra)m(y)f(of)g(unsigned)f(short)g(in)m(tegers)i(\(uarra)m(y\))g
+(in)m(to)g(the)0 781 y(primary)f(arra)m(y)h(of)g(the)g(FITS)f(\014le.)
+39 b(Similarly)-8 b(,)27 b(a)e(32-bit)i(unsigned)c(in)m(teger)j(image)h
+(ma)m(y)e(b)s(e)f(created)i(b)m(y)f(setting)0 894 y(the)34
+b(second)f(parameter)h(in)f(\014ts)p 1130 894 V 33 w(create)p
+1399 894 V 34 w(img)h(equal)g(to)g(`ULONG)p 2330 894
+V 33 w(IMG')g(and)f(b)m(y)h(calling)g(the)g(\014ts)p
+3491 894 V 33 w(write)p 3726 894 V 33 w(img)0 1007 y(routine)j(with)f
+(the)h(second)f(parameter)h(=)f(TULONG)h(to)g(write)g(the)f(arra)m(y)h
+(of)g(unsigned)f(long)h(image)h(pixel)0 1120 y(v)-5 b(alues.)0
+1280 y(An)27 b(analogous)h(set)f(of)g(routines)g(are)g(a)m(v)-5
+b(ailable)30 b(for)c(reading)h(or)g(writing)g(unsigned)f(in)m(teger)i
+(v)-5 b(alues)28 b(and)e(signed)0 1393 y(b)m(yte)i(v)-5
+b(alues)28 b(in)g(a)g(FITS)f(binary)g(table)i(extension.)40
+b(When)28 b(sp)s(ecifying)f(the)h(TF)m(ORMn)g(k)m(eyw)m(ord)g(v)-5
+b(alue)28 b(whic)m(h)0 1506 y(de\014nes)36 b(the)h(format)g(of)g(a)h
+(column,)g(CFITSIO)d(recognized)k(3)e(additional)h(data)f(t)m(yp)s(e)g
+(co)s(des)g(b)s(esides)f(those)0 1619 y(already)30 b(de\014ned)f(in)g
+(the)h(FITS)f(standard:)40 b(`U')30 b(meaning)g(a)g(16-bit)h(unsigned)e
+(in)m(teger)i(column,)f(`V')g(for)g(a)g(32-)0 1732 y(bit)c(unsigned)e
+(in)m(teger)j(column,)g(and)e('S')g(for)g(a)h(signed)g(b)m(yte)g
+(column.)39 b(These)25 b(non-standard)g(data)h(t)m(yp)s(e)g(co)s(des)0
+1844 y(are)36 b(not)g(actually)i(written)e(in)m(to)g(the)g(FITS)g
+(\014le)f(but)h(instead)g(are)g(just)f(used)g(in)m(ternally)i(within)e
+(CFITSIO.)0 1957 y(The)30 b(follo)m(wing)i(co)s(de)e(fragmen)m(t)h
+(illustrates)h(ho)m(w)e(to)h(use)f(these)h(features:)286
+2214 y Fe(unsigned)46 b(short)g(uarray[100];)286 2327
+y(unsigned)g(int)95 b(varray[100];)286 2552 y(int)47
+b(colnum,)f(tfields,)g(status;)286 2665 y(long)h(nrows,)f(firstrow,)f
+(firstelem,)g(nelements,)g(pcount;)286 2891 y(char)i(extname[])e(=)j
+("Test_table";)521 b(/*)47 b(extension)f(name)g(*/)286
+3117 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 3230 y(char)h(*ttype[])f(=)h
+({)g("Col_1",)f("Col_2",)g("Col_3")f(};)286 3343 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 3456 y(char)h(*tunit[])f(=)h({)g(")h(",)381
+b(")48 b(",)190 b(")47 b(")h(};)334 3569 y(...)525 3794
+y(/*)f(write)g(the)f(header)h(keywords)e(*/)286 3907
+y(status)94 b(=)48 b(0;)286 4020 y(nrows)142 b(=)48 b(1;)286
+4133 y(tfields)e(=)i(3)286 4246 y(pcount)94 b(=)48 b(0;)286
+4359 y(fits_create_tbl\(fptr,)42 b(BINARY_TBL,)j(nrows,)h(tfields,)g
+(ttype,)g(tform,)764 4472 y(tunit,)g(extname,)f(&status\);)525
+4698 y(/*)i(write)g(the)f(unsigned)g(shorts)g(to)h(the)g(1st)g(column)f
+(*/)286 4811 y(colnum)190 b(=)47 b(1;)286 4924 y(firstrow)94
+b(=)47 b(1;)286 5036 y(firstelem)f(=)h(1;)286 5149 y(nelements)f(=)h
+(100;)286 5262 y(fits_write_col\(fptr,)c(TUSHORT,)i(colnum,)h
+(firstrow,)f(firstelem,)668 5375 y(nelements,)g(uarray,)h(&status\);)
+525 5601 y(/*)h(now)g(write)f(the)h(unsigned)f(longs)g(to)h(the)g(2nd)g
+(column)f(*/)286 5714 y(colnum)190 b(=)47 b(2;)p eop
+end
+%%Page: 22 30
+TeXDict begin 22 29 bop 0 299 a Fj(22)1763 b Fh(CHAPTER)29
+b(4.)112 b(PR)m(OGRAMMING)32 b(GUIDELINES)286 555 y Fe
+(fits_write_col\(fptr,)43 b(TUINT,)j(colnum,)g(firstrow,)f(firstelem,)
+668 668 y(nelements,)g(varray,)h(&status\);)334 781 y(...)0
+1027 y Fj(Note)22 b(that)g(the)f(non-standard)f(TF)m(ORM)h(v)-5
+b(alues)21 b(for)g(the)g(3)g(columns,)i(`U')e(and)g(`V',)h(tell)g
+(CFITSIO)d(to)j(write)f(the)0 1140 y(k)m(eyw)m(ords)27
+b(appropriate)f(for)g(unsigned)f(16-bit)j(and)d(unsigned)h(32-bit)h(in)
+m(tegers,)i(resp)s(ectiv)m(ely)e(\(i.e.,)i(TF)m(ORMn)0
+1252 y(=)39 b('1I')i(and)e(TZER)m(On)f(=)h(32678)j(for)e(unsigned)e
+(16-bit)j(in)m(tegers,)j(and)39 b(TF)m(ORMn)h(=)f('1J')h(and)f(TZER)m
+(On)0 1365 y(=)c(2147483648)40 b(for)35 b(unsigned)f(32-bit)i(in)m
+(tegers\).)57 b(The)35 b('S')g(TF)m(ORMn)g(v)-5 b(alue)36
+b(tells)h(CFITSIO)c(to)j(write)g(the)0 1478 y(k)m(eyw)m(ords)30
+b(appropriate)g(for)g(a)g(signed)g(8-bit)h(b)m(yte)f(column)g(with)f
+(TF)m(ORMn)h(=)g('1B')h(and)e(TZER)m(On)g(=)g(-128.)0
+1591 y(The)h(calls)h(to)h(\014ts)p 628 1591 28 4 v 32
+w(write)p 862 1591 V 33 w(col)f(then)f(write)h(the)g(arra)m(ys)f(of)h
+(unsigned)e(in)m(teger)j(v)-5 b(alues)31 b(to)g(the)f(columns.)0
+1923 y Ff(4.5)135 b(Dealing)47 b(with)e(Character)h(Strings)0
+2173 y Fj(The)36 b(c)m(haracter)j(string)d(v)-5 b(alues)38
+b(in)e(a)h(FITS)f(header)h(or)g(in)f(an)h(ASCI)s(I)e(column)i(in)f(a)i
+(FITS)e(table)h(extension)0 2286 y(are)i(generally)i(padded)d(out)h
+(with)g(non-signi\014can)m(t)h(space)f(c)m(haracters)i(\(ASCI)s(I)d
+(32\))i(to)g(\014ll)f(up)f(the)h(header)0 2399 y(record)33
+b(or)h(the)f(column)h(width.)49 b(When)33 b(reading)h(a)g(FITS)e
+(string)i(v)-5 b(alue,)35 b(the)e(CFITSIO)f(routines)i(will)f(strip)0
+2512 y(o\013)38 b(these)f(non-signi\014can)m(t)h(trailing)g(spaces)f
+(and)g(will)g(return)f(a)i(n)m(ull-terminated)g(string)f(v)-5
+b(alue)37 b(con)m(taining)0 2624 y(only)d(the)g(signi\014can)m(t)g(c)m
+(haracters.)52 b(Leading)34 b(spaces)g(in)g(a)g(FITS)f(string)g(are)h
+(considered)g(signi\014can)m(t.)52 b(If)33 b(the)0 2737
+y(string)i(con)m(tains)h(all)g(blanks,)g(then)e(CFITSIO)g(will)h
+(return)f(a)h(single)g(blank)g(c)m(haracter,)j(i.e,)f(the)e(\014rst)f
+(blank)0 2850 y(is)c(considered)f(to)i(b)s(e)e(signi\014can)m(t,)i
+(since)f(it)g(distinguishes)g(the)g(string)f(from)h(a)g(n)m(ull)f(or)h
+(unde\014ned)e(string,)i(but)0 2963 y(the)h(remaining)f(trailing)h
+(spaces)g(are)g(not)g(signi\014can)m(t.)0 3123 y(Similarly)-8
+b(,)41 b(when)c(writing)h(string)g(v)-5 b(alues)38 b(to)h(a)g(FITS)e
+(\014le)h(the)g(CFITSIO)f(routines)h(exp)s(ect)g(to)h(get)g(a)g(n)m
+(ull-)0 3236 y(terminated)33 b(string)g(as)g(input;)g(CFITSIO)e(will)i
+(pad)f(the)h(string)g(with)f(blanks)g(if)h(necessary)g(when)f(writing)g
+(it)0 3349 y(to)f(the)g(FITS)e(\014le.)0 3509 y(When)j(calling)i
+(CFITSIO)d(routines)i(that)g(return)e(a)i(c)m(haracter)h(string)f(it)g
+(is)f(vital)i(that)f(the)g(size)g(of)g(the)g(c)m(har)0
+3622 y(arra)m(y)38 b(b)s(e)g(large)h(enough)e(to)i(hold)e(the)h(en)m
+(tire)h(string)f(of)g(c)m(haracters,)k(otherwise)c(CFITSIO)e(will)i(o)m
+(v)m(erwrite)0 3735 y(whatev)m(er)d(memory)e(lo)s(cations)i(follo)m(w)g
+(the)f(c)m(har)h(arra)m(y)-8 b(,)35 b(p)s(ossibly)e(causing)h(the)g
+(program)g(to)g(execute)h(incor-)0 3848 y(rectly)-8 b(.)42
+b(This)30 b(t)m(yp)s(e)g(of)h(error)f(can)h(b)s(e)f(di\016cult)g(to)h
+(debug,)f(so)h(programmers)f(should)f(alw)m(a)m(ys)j(ensure)e(that)h
+(the)0 3961 y(c)m(har)c(arra)m(ys)g(are)g(allo)s(cated)i(enough)d
+(space)i(to)f(hold)g(the)f(longest)i(p)s(ossible)f(string,)g
+Fi(including)h Fj(the)f(terminat-)0 4074 y(ing)k(NULL)g(c)m(haracter.)
+45 b(The)30 b(\014tsio.h)h(\014le)h(con)m(tains)g(the)f(follo)m(wing)i
+(de\014ned)d(constan)m(ts)i(whic)m(h)f(programmers)0
+4187 y(are)g(strongly)g(encouraged)g(to)g(use)f(whenev)m(er)g(they)h
+(are)f(allo)s(cating)j(space)e(for)f(c)m(har)h(arra)m(ys:)0
+4432 y Fe(#define)46 b(FLEN_FILENAME)e(1025)j(/*)g(max)g(length)f(of)h
+(a)g(filename)f(*/)0 4545 y(#define)g(FLEN_KEYWORD)140
+b(72)95 b(/*)47 b(max)g(length)f(of)h(a)g(keyword)94
+b(*/)0 4658 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 4771
+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 4884 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 4997 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
+5110 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 5355 y Fj(F)-8
+b(or)23 b(example,)h(when)d(declaring)i(a)f(c)m(har)g(arra)m(y)h(to)f
+(hold)g(the)g(v)-5 b(alue)22 b(string)g(of)g(FITS)f(k)m(eyw)m(ord,)k
+(use)c(the)h(follo)m(wing)0 5468 y(statemen)m(t:)191
+5714 y Fe(char)47 b(value[FLEN_VALUE];)p eop end
+%%Page: 23 31
+TeXDict begin 23 30 bop 0 299 a Fh(4.6.)72 b(IMPLICIT)29
+b(D)m(A)-8 b(T)g(A)32 b(TYPE)e(CONVERSION)1938 b Fj(23)0
+555 y(Note)41 b(that)f(FLEN)p 686 555 28 4 v 33 w(KEYW)m(ORD)g(is)f
+(longer)h(than)f(needed)g(for)g(the)h(nominal)f(8-c)m(haracter)j(k)m
+(eyw)m(ord)e(name)0 668 y(b)s(ecause)30 b(the)h(HIERAR)m(CH)f(con)m(v)m
+(en)m(tion)j(supp)s(orts)28 b(longer)j(k)m(eyw)m(ord)g(names.)0
+999 y Ff(4.6)135 b(Implicit)46 b(Data)g(T)l(yp)t(e)f(Con)l(v)l(ersion)0
+1249 y Fj(The)29 b(CFITSIO)e(routines)i(that)h(read)f(and)f(write)i(n)m
+(umerical)f(data)h(can)g(p)s(erform)d(implicit)j(data)g(t)m(yp)s(e)f
+(con)m(v)m(er-)0 1362 y(sion.)39 b(This)25 b(means)h(that)g(the)g(data)
+g(t)m(yp)s(e)g(of)g(the)g(v)-5 b(ariable)26 b(or)g(arra)m(y)g(in)f(the)
+h(program)g(do)s(es)f(not)h(need)f(to)i(b)s(e)e(the)0
+1475 y(same)g(as)f(the)h(data)g(t)m(yp)s(e)g(of)f(the)h(v)-5
+b(alue)25 b(in)f(the)g(FITS)g(\014le.)39 b(Data)26 b(t)m(yp)s(e)f(con)m
+(v)m(ersion)g(is)g(supp)s(orted)d(for)i(n)m(umerical)0
+1588 y(and)37 b(string)g(data)g(t)m(yp)s(es)h(\(if)f(the)g(string)g
+(con)m(tains)i(a)e(v)-5 b(alid)38 b(n)m(um)m(b)s(er)e(enclosed)h(in)g
+(quotes\))h(when)e(reading)i(a)0 1701 y(FITS)30 b(header)h(k)m(eyw)m
+(ord)g(v)-5 b(alue)31 b(and)f(for)h(n)m(umeric)g(v)-5
+b(alues)31 b(when)f(reading)h(or)f(writing)h(v)-5 b(alues)31
+b(in)g(the)g(primary)0 1814 y(arra)m(y)24 b(or)g(a)h(table)f(column.)39
+b(CFITSIO)22 b(returns)h(status)h(=)f(NUM)p 2267 1814
+V 34 w(O)m(VERFLO)m(W)i(if)e(the)h(con)m(v)m(erted)i(data)e(v)-5
+b(alue)0 1927 y(exceeds)33 b(the)g(range)g(of)g(the)f(output)g(data)i
+(t)m(yp)s(e.)47 b(Implicit)33 b(data)g(t)m(yp)s(e)g(con)m(v)m(ersion)h
+(is)e(not)h(supp)s(orted)d(within)0 2039 y(binary)g(tables)h(for)f
+(string,)g(logical,)k(complex,)d(or)f(double)g(complex)h(data)g(t)m(yp)
+s(es.)0 2200 y(In)g(addition,)h(an)m(y)f(table)h(column)f(ma)m(y)h(b)s
+(e)f(read)g(as)h(if)f(it)h(con)m(tained)g(string)f(v)-5
+b(alues.)44 b(In)31 b(the)g(case)i(of)e(n)m(umeric)0
+2313 y(columns)f(the)h(returned)e(string)h(will)h(b)s(e)f(formatted)h
+(using)e(the)i(TDISPn)e(displa)m(y)i(format)f(if)h(it)g(exists.)0
+2643 y Ff(4.7)135 b(Data)46 b(Scaling)0 2894 y Fj(When)38
+b(reading)f(n)m(umerical)i(data)f(v)-5 b(alues)38 b(in)f(the)h(primary)
+f(arra)m(y)h(or)g(a)g(table)h(column,)h(the)d(v)-5 b(alues)38
+b(will)h(b)s(e)0 3006 y(scaled)f(automatically)j(b)m(y)c(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)38 b(if)0 3119 y(they)31 b(are)f(presen)m(t)h(in)f(the)g
+(header.)41 b(The)30 b(scaled)h(data)g(that)g(is)f(returned)g(to)h(the)
+f(reading)h(program)f(will)h(ha)m(v)m(e)382 3361 y Fe(output)46
+b(value)g(=)i(\(FITS)e(value\))g(*)i(BSCALE)e(+)h(BZERO)0
+3603 y Fj(\(a)30 b(corresp)s(onding)e(form)m(ula)h(using)g(TSCALn)e
+(and)i(TZER)m(On)e(is)i(used)g(when)f(reading)h(from)g(table)h
+(columns\).)0 3716 y(In)h(the)i(case)g(of)f(in)m(teger)h(output)f(v)-5
+b(alues)32 b(the)h(\015oating)g(p)s(oin)m(t)f(scaled)g(v)-5
+b(alue)33 b(is)f(truncated)g(to)h(an)f(in)m(teger)h(\(not)0
+3828 y(rounded)i(to)j(the)f(nearest)h(in)m(teger\).)62
+b(The)36 b(\014ts)p 1673 3828 V 32 w(set)p 1816 3828
+V 34 w(bscale)i(and)e(\014ts)p 2430 3828 V 32 w(set)p
+2573 3828 V 34 w(tscale)i(routines)f(\(describ)s(ed)f(in)h(the)0
+3941 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)i(the)e(scaling)h(parameters)f(de\014ned)f(in)h(the)g
+(header)g(\(e.g.,)i(to)0 4054 y(turn)e(o\013)i(the)g(scaling)g(so)g
+(that)g(the)f(program)g(can)h(read)f(the)h(ra)m(w)f(unscaled)h(v)-5
+b(alues)30 b(from)g(the)h(FITS)e(\014le\).)0 4214 y(When)44
+b(writing)h(n)m(umerical)g(data)g(to)g(the)g(primary)f(arra)m(y)h(or)f
+(to)h(a)g(table)h(column)e(the)h(data)g(v)-5 b(alues)45
+b(will)0 4327 y(generally)29 b(b)s(e)f(automatically)j(in)m(v)m(ersely)
+f(scaled)f(b)m(y)f(the)g(v)-5 b(alue)29 b(of)f(the)h(BSCALE)e(and)h
+(BZER)m(O)g(\(or)h(TSCALn)0 4440 y(and)35 b(TZER)m(On\))f(k)m(eyw)m
+(ord)i(v)-5 b(alues)35 b(if)h(they)f(they)g(exist)i(in)e(the)g(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
+4553 y(written)31 b(to)h(the)g(header)f(b)s(efore)g(an)m(y)g(data)h(is)
+g(written)f(for)g(them)g(to)h(ha)m(v)m(e)h(an)m(y)e(immediate)i
+(e\013ect.)45 b(One)30 b(ma)m(y)0 4666 y(also)h(use)g(the)f(\014ts)p
+623 4666 V 33 w(set)p 767 4666 V 33 w(bscale)i(and)d(\014ts)p
+1367 4666 V 33 w(set)p 1511 4666 V 33 w(tscale)j(routines)f(to)g
+(de\014ne)f(or)g(o)m(v)m(erride)i(the)f(scaling)g(k)m(eyw)m(ords)g(in)0
+4779 y(the)e(header)g(\(e.g.,)i(to)e(turn)f(o\013)h(the)g(scaling)h(so)
+f(that)h(the)f(program)f(can)h(write)g(the)g(ra)m(w)g(unscaled)g(v)-5
+b(alues)29 b(in)m(to)0 4892 y(the)d(FITS)g(\014le\).)40
+b(If)25 b(scaling)i(is)g(p)s(erformed,)e(the)i(in)m(v)m(erse)g(scaled)g
+(output)e(v)-5 b(alue)27 b(that)g(is)f(written)g(in)m(to)h(the)g(FITS)0
+5005 y(\014le)j(will)h(ha)m(v)m(e)430 5246 y Fe(FITS)46
+b(value)h(=)g(\(\(input)f(value\))g(-)h(BZERO\))f(/)i(BSCALE)0
+5488 y Fj(\(a)39 b(corresp)s(onding)d(form)m(ula)i(using)g(TSCALn)e
+(and)h(TZER)m(On)g(is)h(used)f(when)f(writing)i(to)h(table)g
+(columns\).)0 5601 y(Rounding)34 b(to)i(the)g(nearest)g(in)m(teger,)i
+(rather)d(than)g(truncation,)j(is)d(p)s(erformed)f(when)g(writing)h(in)
+m(teger)i(data)0 5714 y(t)m(yp)s(es)30 b(to)i(the)e(FITS)g(\014le.)p
+eop end
+%%Page: 24 32
+TeXDict begin 24 31 bop 0 299 a Fj(24)1763 b Fh(CHAPTER)29
+b(4.)112 b(PR)m(OGRAMMING)32 b(GUIDELINES)0 555 y Ff(4.8)135
+b(Supp)t(ort)44 b(for)h(IEEE)h(Sp)t(ecial)f(V)-11 b(alues)0
+807 y Fj(The)26 b(ANSI/IEEE-754)h(\015oating-p)s(oin)m(t)h(n)m(um)m(b)s
+(er)d(standard)g(de\014nes)h(certain)h(sp)s(ecial)g(v)-5
+b(alues)26 b(that)h(are)g(used)e(to)0 920 y(represen)m(t)j(suc)m(h)g
+(quan)m(tities)h(as)f(Not-a-Num)m(b)s(er)h(\(NaN\),)h(denormalized,)f
+(under\015o)m(w,)e(o)m(v)m(er\015o)m(w,)j(and)d(in\014nit)m(y)-8
+b(.)0 1033 y(\(See)29 b(the)f(App)s(endix)e(in)i(the)g(NOST)g(FITS)f
+(standard)g(or)h(the)g(NOST)g(FITS)f(User's)h(Guide)g(for)g(a)g(list)h
+(of)f(these)0 1146 y(v)-5 b(alues\).)55 b(The)34 b(CFITSIO)f(routines)i
+(that)g(read)g(\015oating)g(p)s(oin)m(t)g(data)h(in)e(FITS)g(\014les)h
+(recognize)h(these)g(IEEE)0 1259 y(sp)s(ecial)k(v)-5
+b(alues)39 b(and)g(b)m(y)g(default)g(in)m(terpret)h(the)f(o)m(v)m
+(er\015o)m(w)i(and)d(in\014nit)m(y)h(v)-5 b(alues)40
+b(as)f(b)s(eing)g(equiv)-5 b(alen)m(t)41 b(to)f(a)0 1372
+y(NaN,)35 b(and)e(con)m(v)m(ert)i(the)f(under\015o)m(w)e(and)h
+(denormalized)h(v)-5 b(alues)34 b(in)m(to)h(zeros.)51
+b(In)33 b(some)h(cases)h(programmers)0 1485 y(ma)m(y)42
+b(w)m(an)m(t)g(access)g(to)g(the)g(ra)m(w)f(IEEE)g(v)-5
+b(alues,)44 b(without)d(an)m(y)h(mo)s(di\014cation)g(b)m(y)f(CFITSIO.)f
+(This)g(can)i(b)s(e)0 1598 y(done)35 b(b)m(y)h(calling)h(the)e(\014ts)p
+935 1598 28 4 v 33 w(read)p 1140 1598 V 32 w(img)h(or)g(\014ts)p
+1593 1598 V 32 w(read)p 1797 1598 V 33 w(col)g(routines)g(while)f(sp)s
+(ecifying)g(0.0)i(as)f(the)f(v)-5 b(alue)36 b(of)g(the)0
+1711 y(NULL)-10 b(V)g(AL)37 b(parameter.)63 b(This)36
+b(will)i(force)g(CFITSIO)e(to)i(simply)f(pass)g(the)g(IEEE)g(v)-5
+b(alues)38 b(through)f(to)h(the)0 1824 y(application)24
+b(program)f(without)g(an)m(y)h(mo)s(di\014cation.)38
+b(This)23 b(is)g(not)g(fully)g(supp)s(orted)e(on)i(V)-10
+b(AX/VMS)24 b(mac)m(hines,)0 1937 y(ho)m(w)m(ev)m(er,)k(where)c(there)h
+(is)g(no)f(easy)i(w)m(a)m(y)g(to)f(b)m(ypass)g(the)g(default)g(in)m
+(terpretation)h(of)f(the)g(IEEE)f(sp)s(ecial)h(v)-5 b(alues.)0
+2049 y(This)27 b(is)i(also)g(not)f(supp)s(orted)e(when)i(reading)g
+(\015oating-p)s(oin)m(t)h(images)g(that)g(ha)m(v)m(e)h(b)s(een)d
+(compressed)h(with)g(the)0 2162 y(FITS)33 b(tiled)h(image)g
+(compression)f(con)m(v)m(en)m(tion)j(that)e(is)f(discussed)g(in)g
+(section)h(5.6;)i(the)e(pixels)f(v)-5 b(alues)34 b(in)f(tile)0
+2275 y(compressed)d(images)i(are)f(represen)m(ted)g(b)m(y)g(scaled)g
+(in)m(tegers,)h(and)e(a)i(reserv)m(ed)e(in)m(teger)j(v)-5
+b(alue)31 b(\(not)g(a)g(NaN\))h(is)0 2388 y(used)e(to)h(represen)m(t)f
+(unde\014ned)e(pixels.)0 2732 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
+2984 y Fj(Nearly)36 b(all)g(the)g(CFITSIO)e(routines)h(return)f(an)h
+(error)g(status)h(v)-5 b(alue)35 b(in)g(2)h(w)m(a)m(ys:)51
+b(as)36 b(the)f(v)-5 b(alue)36 b(of)g(the)f(last)0 3097
+y(parameter)29 b(in)f(the)g(function)g(call,)j(and)d(as)g(the)h
+(returned)e(v)-5 b(alue)29 b(of)f(the)h(function)f(itself.)41
+b(This)27 b(pro)m(vides)i(some)0 3210 y(\015exibilit)m(y)37
+b(in)e(the)h(w)m(a)m(y)h(programmers)e(can)h(test)h(if)f(an)f(error)h
+(o)s(ccurred,)g(as)g(illustrated)h(in)e(the)h(follo)m(wing)i(2)0
+3323 y(co)s(de)31 b(fragmen)m(ts:)191 3592 y Fe(if)47
+b(\()h(fits_write_record\(fptr,)41 b(card,)46 b(&status\))g(\))430
+3704 y(printf\(")f(Error)h(occurred)g(while)g(writing)g(keyword."\);)0
+3930 y(or,)191 4156 y(fits_write_record\(fptr,)41 b(card,)47
+b(&status\);)191 4269 y(if)g(\()h(status)e(\))430 4382
+y(printf\(")f(Error)h(occurred)g(while)g(writing)g(keyword."\);)0
+4650 y Fj(A)27 b(listing)h(of)g(all)g(the)f(CFITSIO)f(status)i(co)s(de)
+f(v)-5 b(alues)28 b(is)f(giv)m(en)h(at)g(the)g(end)e(of)i(this)f(do)s
+(cumen)m(t.)39 b(Programmers)0 4763 y(are)33 b(encouraged)g(to)g(use)f
+(the)h(sym)m(b)s(olic)f(mnemonics)g(\(de\014ned)g(in)g(\014tsio.h\))h
+(rather)f(than)g(the)h(actual)h(in)m(teger)0 4876 y(status)d(v)-5
+b(alues)30 b(to)i(impro)m(v)m(e)f(the)f(readabilit)m(y)i(of)f(their)f
+(co)s(de.)0 5036 y(The)i(CFITSIO)f(library)g(uses)h(an)g(`inherited)h
+(status')g(con)m(v)m(en)m(tion)h(for)e(the)h(status)f(parameter)h(whic)
+m(h)f(means)0 5149 y(that)37 b(if)f(a)h(routine)f(is)h(called)g(with)f
+(a)h(p)s(ositiv)m(e)g(input)f(v)-5 b(alue)36 b(of)h(the)g(status)f
+(parameter)h(as)g(input,)g(then)f(the)0 5262 y(routine)j(will)f(exit)i
+(immediately)g(without)e(c)m(hanging)i(the)e(v)-5 b(alue)39
+b(of)g(the)g(status)g(parameter.)65 b(Th)m(us,)40 b(if)f(one)0
+5375 y(passes)24 b(the)h(status)g(v)-5 b(alue)25 b(returned)f(from)g
+(eac)m(h)i(CFITSIO)d(routine)h(as)h(input)f(to)h(the)g(next)g(CFITSIO)e
+(routine,)0 5488 y(then)28 b(whenev)m(er)g(an)g(error)g(is)h(detected)g
+(all)h(further)d(CFITSIO)f(pro)s(cessing)i(will)h(cease.)42
+b(This)27 b(con)m(v)m(en)m(tion)k(can)0 5601 y(simplify)h(the)h(error)f
+(c)m(hec)m(king)j(in)d(application)i(programs)e(b)s(ecause)h(it)g(is)g
+(not)g(necessary)g(to)g(c)m(hec)m(k)i(the)d(v)-5 b(alue)0
+5714 y(of)30 b(the)g(status)h(parameter)f(after)h(ev)m(ery)g(single)f
+(CFITSIO)f(routine)h(call.)42 b(If)30 b(a)g(program)g(con)m(tains)h(a)g
+(sequence)p eop end
+%%Page: 25 33
+TeXDict begin 25 32 bop 0 299 a Fh(4.10.)73 b(V)-10 b(ARIABLE-LENGTH)31
+b(ARRA)-8 b(YS)30 b(IN)g(BINAR)-8 b(Y)32 b(T)-8 b(ABLES)1327
+b Fj(25)0 555 y(of)28 b(sev)m(eral)i(CFITSIO)d(calls,)j(one)e(can)h
+(just)e(c)m(hec)m(k)j(the)f(status)f(v)-5 b(alue)29 b(after)g(the)f
+(last)h(call.)41 b(Since)29 b(the)f(returned)0 668 y(status)33
+b(v)-5 b(alues)33 b(are)g(generally)h(distinctiv)m(e,)h(it)f(should)d
+(b)s(e)i(p)s(ossible)f(to)h(determine)g(whic)m(h)g(routine)g
+(originally)0 781 y(returned)c(the)i(error)f(status.)0
+941 y(CFITSIO)c(also)i(main)m(tains)h(an)e(in)m(ternal)h(stac)m(k)h(of)
+f(error)f(messages)h(\(80-c)m(haracter)j(maxim)m(um)c(length\))h(whic)m
+(h)0 1054 y(in)36 b(man)m(y)g(cases)h(pro)m(vide)f(a)g(more)g(detailed)
+i(explanation)f(of)f(the)g(cause)h(of)f(the)g(error)g(than)f(is)h(pro)m
+(vided)g(b)m(y)0 1167 y(the)k(error)e(status)i(n)m(um)m(b)s(er)e
+(alone.)69 b(It)39 b(is)h(recommended)f(that)g(the)h(error)f(message)h
+(stac)m(k)h(b)s(e)e(prin)m(ted)g(out)0 1280 y(whenev)m(er)g(a)g
+(program)g(detects)h(a)f(CFITSIO)e(error.)66 b(The)38
+b(function)h(\014ts)p 2653 1280 28 4 v 32 w(rep)s(ort)p
+2931 1280 V 32 w(error)g(will)g(prin)m(t)g(out)g(the)0
+1393 y(en)m(tire)31 b(error)e(message)h(stac)m(k,)i(or)d(alternativ)m
+(ely)k(one)d(ma)m(y)g(call)h(\014ts)p 2376 1393 V 32
+w(read)p 2580 1393 V 33 w(errmsg)e(to)h(get)h(the)f(error)f(messages)0
+1506 y(one)i(at)g(a)g(time.)0 1879 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 2138 y Fj(CFITSIO)33 b(pro)m(vides)i(easy-to-use)h(supp)s
+(ort)d(for)i(reading)g(and)f(writing)h(data)g(in)g(v)-5
+b(ariable)35 b(length)g(\014elds)g(of)g(a)0 2251 y(binary)g(table.)56
+b(The)35 b(v)-5 b(ariable)36 b(length)f(columns)g(ha)m(v)m(e)i(TF)m
+(ORMn)e(k)m(eyw)m(ord)h(v)-5 b(alues)35 b(of)h(the)f(form)g
+(`1Pt\(len\)')0 2363 y(where)25 b(`t')i(is)e(the)h(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')i(is)e(an)h(in)m(teger)h(sp)s(ecifying)e(the)h(maxim)m(um)0
+2476 y(length)k(of)f(the)h(v)m(ector)h(in)e(the)h(table.)41
+b(\(CFITSIO)28 b(also)j(supp)s(orts)c(the)j(exp)s(erimen)m(tal)g('Q')g
+(datat)m(yp)s(e,)h(whic)m(h)e(is)0 2589 y(iden)m(tical)37
+b(to)e(the)g('P')g(t)m(yp)s(e)g(except)h(that)g(is)f(supp)s(orts)e(is)h
+(a)i(64-bit)g(address)e(space)h(and)f(hence)h(m)m(uc)m(h)g(larger)0
+2702 y(data)28 b(structures\).)40 b(If)27 b(the)h(v)-5
+b(alue)28 b(of)g(`len')g(is)f(not)h(sp)s(eci\014ed)f(when)g(the)g
+(table)i(is)f(created)g(\(e.g.,)i(if)e(the)g(TF)m(ORM)0
+2815 y(k)m(eyw)m(ord)d(v)-5 b(alue)26 b(is)f(simply)g(sp)s(eci\014ed)f
+(as)h('1PE')h(instead)f(of)g('1PE\(400\))j(\),)e(then)f(CFITSIO)f(will)
+h(automatically)0 2928 y(scan)34 b(the)g(table)h(when)e(it)h(is)g
+(closed)h(to)f(determine)g(the)g(maxim)m(um)g(length)h(of)f(the)g(v)m
+(ector)h(and)e(will)i(app)s(end)0 3041 y(this)30 b(v)-5
+b(alue)31 b(to)g(the)g(TF)m(ORMn)f(v)-5 b(alue.)0 3201
+y(The)29 b(same)h(routines)g(that)g(read)f(and)g(write)h(data)g(in)g
+(an)f(ordinary)g(\014xed)g(length)h(binary)f(table)h(extension)h(are)0
+3314 y(also)41 b(used)d(for)i(v)-5 b(ariable)40 b(length)g(\014elds,)h
+(ho)m(w)m(ev)m(er,)j(the)c(routine)f(parameters)h(tak)m(e)h(on)f(a)g
+(sligh)m(tly)g(di\013eren)m(t)0 3427 y(in)m(terpretation)32
+b(as)e(describ)s(ed)g(b)s(elo)m(w.)0 3587 y(All)37 b(the)f(data)h(in)f
+(a)h(v)-5 b(ariable)37 b(length)f(\014eld)g(is)g(written)h(in)m(to)g
+(an)f(area)h(called)h(the)e(`heap')g(whic)m(h)g(follo)m(ws)i(the)0
+3700 y(main)31 b(\014xed-length)h(FITS)e(binary)h(table.)44
+b(The)31 b(size)h(of)f(the)h(heap,)f(in)g(b)m(ytes,)h(is)g(sp)s
+(eci\014ed)e(b)m(y)h(the)h(PCOUNT)0 3813 y(k)m(eyw)m(ord)21
+b(in)f(the)h(FITS)f(header.)37 b(When)20 b(creating)i(a)f(new)f(binary)
+g(table,)j(the)e(initial)h(v)-5 b(alue)21 b(of)f(PCOUNT)g(should)0
+3926 y(usually)27 b(b)s(e)h(set)g(to)g(zero.)41 b(CFITSIO)26
+b(will)i(recompute)g(the)g(size)g(of)g(the)g(heap)g(as)g(the)g(data)g
+(is)g(written)f(and)h(will)0 4039 y(automatically)g(up)s(date)c(the)i
+(PCOUNT)e(k)m(eyw)m(ord)h(v)-5 b(alue)26 b(when)e(the)h(table)h(is)f
+(closed.)40 b(When)25 b(writing)g(v)-5 b(ariable)0 4152
+y(length)34 b(data)g(to)g(a)g(table,)i(CFITSIO)c(will)h(automatically)k
+(extend)c(the)h(size)g(of)g(the)g(heap)f(area)h(if)g(necessary)-8
+b(,)0 4264 y(so)31 b(that)g(an)m(y)f(follo)m(wing)i(HDUs)f(do)f(not)h
+(get)h(o)m(v)m(erwritten.)0 4425 y(By)e(default)f(the)h(heap)f(data)i
+(area)f(starts)g(immediately)h(after)f(the)f(last)i(ro)m(w)e(of)h(the)g
+(\014xed-length)f(table.)42 b(This)0 4538 y(default)27
+b(starting)g(lo)s(cation)i(ma)m(y)e(b)s(e)f(o)m(v)m(erridden)h(b)m(y)g
+(the)g(THEAP)f(k)m(eyw)m(ord,)i(but)f(this)f(is)h(not)g(recommended.)0
+4650 y(If)34 b(additional)h(ro)m(ws)f(of)g(data)h(are)g(added)e(to)i
+(the)f(table,)j(CFITSIO)32 b(will)j(automatically)i(shift)c(the)i(the)f
+(heap)0 4763 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)i(is)e(ob)m(viously)i(b)s(e)e(more)h(e\016cien)m(t)h
+(to)f(initially)h(create)h(the)0 4876 y(table)31 b(with)e(the)h
+(necessary)g(n)m(um)m(b)s(er)f(of)h(blank)f(ro)m(ws,)h(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
+4989 y(mo)m(v)m(ed.)0 5149 y(When)36 b(writing)g(ro)m(w)g(of)h(data)f
+(to)h(a)g(v)-5 b(ariable)37 b(length)f(\014eld)g(the)g(en)m(tire)i
+(arra)m(y)e(of)g(v)-5 b(alues)37 b(for)f(a)g(giv)m(en)i(ro)m(w)e(of)0
+5262 y(the)30 b(table)h(m)m(ust)e(b)s(e)h(written)g(with)f(a)h(single)h
+(call)g(to)f(\014ts)p 1986 5262 V 33 w(write)p 2221 5262
+V 33 w(col.)42 b(The)29 b(total)i(length)g(of)f(the)g(arra)m(y)g(is)g
+(giv)m(en)0 5375 y(b)m(y)j(nelemen)m(ts)h(+)f(\014rstelem)g(-)g(1.)49
+b(Additional)34 b(elemen)m(ts)h(cannot)e(b)s(e)g(app)s(ended)e(to)j(an)
+f(existing)h(v)m(ector)h(at)f(a)0 5488 y(later)c(time)g(since)g(an)m(y)
+g(attempt)g(to)g(do)g(so)f(will)h(simply)f(o)m(v)m(erwrite)i(all)f(the)
+f(previously)h(written)f(data)h(and)f(the)0 5601 y(new)36
+b(data)h(will)g(b)s(e)f(written)g(to)h(a)g(new)f(area)h(of)g(the)g
+(heap.)58 b(The)36 b(\014ts)p 2496 5601 V 33 w(compress)p
+2889 5601 V 32 w(heap)g(routine)h(is)f(pro)m(vided)0
+5714 y(to)h(compress)g(the)g(heap)g(and)f(reco)m(v)m(er)i(an)m(y)f(un)m
+(used)f(space.)60 b(T)-8 b(o)37 b(a)m(v)m(oid)i(ha)m(ving)e(to)h(deal)f
+(with)f(this)h(issue,)h(it)p eop end
+%%Page: 26 34
+TeXDict begin 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(is)f(recommended)h
+(that)g(ro)m(ws)f(in)g(a)h(v)-5 b(ariable)32 b(length)g(\014eld)f
+(should)f(only)i(b)s(e)f(written)g(once.)45 b(An)31 b(exception)h(to)0
+668 y(this)e(general)h(rule)f(o)s(ccurs)g(when)f(setting)i(elemen)m(ts)
+h(of)e(an)g(arra)m(y)g(as)h(unde\014ned.)38 b(It)30 b(is)h(allo)m(w)m
+(ed)h(to)e(\014rst)g(write)0 781 y(a)e(dumm)m(y)f(v)-5
+b(alue)28 b(in)m(to)h(the)f(arra)m(y)h(with)e(\014ts)p
+1534 781 28 4 v 33 w(write)p 1769 781 V 33 w(col,)j(and)d(then)g(call)j
+(\014ts)p 2632 781 V 32 w(write)p 2866 781 V 33 w(col)p
+3009 781 V 34 w(n)m(ul)d(to)i(\015ag)f(the)g(desired)0
+894 y(elemen)m(ts)h(as)f(unde\014ned.)38 b(Note)29 b(that)g(the)f(ro)m
+(ws)g(of)g(a)g(table,)i(whether)d(\014xed)g(or)h(v)-5
+b(ariable)29 b(length,)g(do)f(not)g(ha)m(v)m(e)0 1007
+y(to)j(b)s(e)f(written)g(consecutiv)m(ely)j(and)d(ma)m(y)h(b)s(e)e
+(written)i(in)f(an)m(y)h(order.)0 1167 y(When)40 b(writing)h(to)g(a)g
+(v)-5 b(ariable)41 b(length)g(ASCI)s(I)e(c)m(haracter)j(\014eld)e
+(\(e.g.,)45 b(TF)m(ORM)c(=)f('1P)-8 b(A'\))43 b(only)d(a)h(single)0
+1280 y(c)m(haracter)22 b(string)e(can)h(b)s(e)e(written.)38
+b(The)20 b(`\014rstelem')g(and)g(`nelemen)m(ts')i(parameter)e(v)-5
+b(alues)21 b(in)f(the)g(\014ts)p 3526 1280 V 33 w(write)p
+3761 1280 V 33 w(col)0 1393 y(routine)35 b(are)h(ignored)f(and)f(the)i
+(n)m(um)m(b)s(er)d(of)j(c)m(haracters)g(to)g(write)f(is)h(simply)e
+(determined)h(b)m(y)g(the)g(length)h(of)0 1506 y(the)31
+b(input)e(n)m(ull-terminated)i(c)m(haracter)h(string.)0
+1666 y(The)21 b(\014ts)p 305 1666 V 33 w(write)p 540
+1666 V 33 w(descript)g(routine)h(is)f(useful)g(in)g(situations)i(where)
+e(m)m(ultiple)h(ro)m(ws)g(of)g(a)g(v)-5 b(ariable)22
+b(length)g(column)0 1779 y(ha)m(v)m(e)32 b(the)e(iden)m(tical)i(arra)m
+(y)f(of)g(v)-5 b(alues.)41 b(One)30 b(can)g(simply)g(write)h(the)f
+(arra)m(y)h(once)g(for)g(the)f(\014rst)g(ro)m(w,)g(and)g(then)0
+1892 y(use)c(\014ts)p 280 1892 V 32 w(write)p 514 1892
+V 33 w(descript)g(to)g(write)g(the)g(same)h(descriptor)e(v)-5
+b(alues)27 b(in)m(to)g(the)f(other)g(ro)m(ws;)h(all)g(the)f(ro)m(ws)g
+(will)g(then)0 2005 y(p)s(oin)m(t)k(to)h(the)g(same)g(storage)h(lo)s
+(cation)g(th)m(us)e(sa)m(ving)h(disk)f(space.)0 2165
+y(When)35 b(reading)g(from)f(a)i(v)-5 b(ariable)35 b(length)h(arra)m(y)
+f(\014eld)g(one)g(can)g(only)h(read)e(as)i(man)m(y)f(elemen)m(ts)h(as)f
+(actually)0 2278 y(exist)i(in)e(that)i(ro)m(w)e(of)h(the)g(table;)k
+(reading)c(do)s(es)g(not)g(automatically)i(con)m(tin)m(ue)f(with)f(the)
+g(next)g(ro)m(w)g(of)g(the)0 2391 y(table)29 b(as)f(o)s(ccurs)g(when)f
+(reading)h(an)g(ordinary)g(\014xed)f(length)h(table)h(\014eld.)40
+b(A)m(ttempts)29 b(to)g(read)f(more)g(than)g(this)0 2503
+y(will)k(cause)h(an)e(error)h(status)g(to)g(b)s(e)f(returned.)44
+b(One)32 b(can)g(determine)g(the)g(n)m(um)m(b)s(er)e(of)i(elemen)m(ts)h
+(in)f(eac)m(h)h(ro)m(w)0 2616 y(of)e(a)f(v)-5 b(ariable)31
+b(column)g(with)f(the)g(\014ts)p 1329 2616 V 33 w(read)p
+1534 2616 V 32 w(descript)h(routine.)0 3218 y Ff(4.11)136
+b(Multiple)45 b(Access)g(to)g(the)g(Same)h(FITS)d(File)0
+3521 y Fj(CFITSIO)35 b(supp)s(orts)g(sim)m(ultaneous)i(read)f(and)g
+(write)h(access)g(to)h(m)m(ultiple)f(HDUs)g(in)f(the)h(same)g(FITS)f
+(\014le.)0 3634 y(Th)m(us,)26 b(one)f(can)h(op)s(en)f(the)h(same)f
+(FITS)g(\014le)h(t)m(wice)h(within)d(a)i(single)g(program)g(and)e(mo)m
+(v)m(e)j(to)g(2)e(di\013eren)m(t)h(HDUs)0 3747 y(in)d(the)h(\014le,)h
+(and)e(then)g(read)h(and)f(write)h(data)g(or)f(k)m(eyw)m(ords)h(to)h
+(the)e(2)h(extensions)g(just)f(as)h(if)g(one)f(w)m(ere)h(accessing)0
+3860 y(2)k(completely)h(separate)g(FITS)e(\014les.)40
+b(Since)27 b(in)h(general)g(it)g(is)g(not)g(p)s(ossible)f(to)i(ph)m
+(ysically)f(op)s(en)f(the)h(same)g(\014le)0 3973 y(t)m(wice)e(and)e
+(then)g(exp)s(ect)h(to)g(b)s(e)f(able)h(to)h(sim)m(ultaneously)f(\(or)g
+(in)f(alternating)i(succession\))g(write)e(to)i(2)e(di\013eren)m(t)0
+4086 y(lo)s(cations)35 b(in)f(the)g(\014le,)h(CFITSIO)d(recognizes)k
+(when)d(the)h(\014le)f(to)i(b)s(e)e(op)s(ened)g(\(in)h(the)g(call)h(to)
+g(\014ts)p 3499 4086 V 32 w(op)s(en)p 3721 4086 V 32
+w(\014le\))0 4199 y(has)29 b(already)g(b)s(een)f(op)s(ened)g(and)h
+(instead)g(of)g(actually)h(op)s(ening)e(the)i(\014le)e(again,)j(just)d
+(logically)k(links)c(the)h(new)0 4312 y(\014le)e(to)h(the)f(old)h
+(\014le.)39 b(\(This)27 b(of)g(course)h(do)s(es)e(not)i(prev)m(en)m(t)f
+(the)h(same)f(\014le)g(from)g(b)s(eing)g(sim)m(ultaneously)h(op)s(ened)
+0 4425 y(b)m(y)g(more)h(than)f(one)g(program\).)40 b(Then)28
+b(b)s(efore)g(CFITSIO)e(reads)i(or)h(writes)f(to)h(either)g
+(\(logical\))i(\014le,)e(it)g(mak)m(es)0 4538 y(sure)i(that)h(an)m(y)g
+(mo)s(di\014cations)g(made)g(to)g(the)g(other)g(\014le)f(ha)m(v)m(e)i
+(b)s(een)e(completely)i(\015ushed)d(from)h(the)h(in)m(ternal)0
+4650 y(bu\013ers)f(to)h(the)h(\014le.)45 b(Th)m(us,)31
+b(in)h(principle,)g(one)g(could)g(op)s(en)g(a)g(\014le)g(t)m(wice,)i
+(in)e(one)g(case)h(p)s(oin)m(ting)f(to)h(the)f(\014rst)0
+4763 y(extension)27 b(and)e(in)h(the)g(other)h(p)s(oin)m(ting)f(to)h
+(the)f(2nd)f(extension)i(and)f(then)f(write)i(data)f(to)h(b)s(oth)f
+(extensions,)h(in)0 4876 y(an)m(y)33 b(order,)f(without)h(danger)f(of)g
+(corrupting)g(the)h(\014le.)46 b(There)32 b(ma)m(y)h(b)s(e)f(some)h
+(e\016ciency)g(p)s(enalties)g(in)f(doing)0 4989 y(this)26
+b(ho)m(w)m(ev)m(er,)j(since)e(CFITSIO)e(has)i(to)g(\015ush)e(all)i(the)
+g(in)m(ternal)g(bu\013ers)f(related)h(to)h(one)e(\014le)h(b)s(efore)f
+(switc)m(hing)0 5102 y(to)33 b(the)g(other,)h(so)f(it)h(w)m(ould)e
+(still)i(b)s(e)e(pruden)m(t)f(to)j(minimize)f(the)g(n)m(um)m(b)s(er)e
+(of)i(times)h(one)f(switc)m(hes)g(bac)m(k)h(and)0 5215
+y(forth)c(b)s(et)m(w)m(een)h(doing)f(I/O)h(to)g(di\013eren)m(t)g(HDUs)g
+(in)f(the)g(same)h(\014le.)0 5375 y(Some)f(restriction)h(apply:)40
+b(a)30 b(FITS)f(\014le)h(cannot)g(b)s(e)f(op)s(ened)h(the)g(\014rst)f
+(time)h(with)g(READONL)-8 b(Y)30 b(access,)i(and)0 5488
+y(then)i(op)s(ened)g(a)h(second)g(time)g(with)g(READ)m(WRITE)g(access,)
+i(b)s(ecause)e(this)f(ma)m(y)i(b)s(e)e(ph)m(yically)h(imp)s(ossible)0
+5601 y(\(e.g.,)g(if)e(the)g(\014le)f(resides)h(on)f(read-only)h(media)g
+(suc)m(h)g(as)g(a)g(CDR)m(OM\).)g(Also,)h(in)f(m)m(ulti-threaded)g(en)m
+(virono-)0 5714 y(men)m(ts,)e(one)g(should)e(nev)m(er)i(op)s(en)e(the)i
+(same)g(\014le)f(with)g(write)h(access)g(in)g(di\013eren)m(t)f
+(threads.)p eop end
+%%Page: 27 35
+TeXDict begin 27 34 bop 0 299 a Fh(4.12.)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 Fj(27)0 555 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 816 y Fj(It)27 b(is)h(not)f(required)f
+(to)i(kno)m(w)f(the)h(total)h(size)f(of)f(a)h(FITS)e(data)i(arra)m(y)g
+(or)f(table)h(b)s(efore)f(b)s(eginning)f(to)i(write)g(the)0
+928 y(data)k(to)f(the)g(FITS)f(\014le.)43 b(In)30 b(the)h(case)h(of)f
+(the)g(primary)f(arra)m(y)h(or)g(an)f(image)j(extension,)e(one)h
+(should)d(initially)0 1041 y(create)i(the)e(arra)m(y)h(with)e(the)i
+(size)g(of)f(the)g(highest)g(dimension)g(\(largest)i(NAXISn)d(k)m(eyw)m
+(ord\))i(set)g(to)g(a)f(dumm)m(y)0 1154 y(v)-5 b(alue,)26
+b(suc)m(h)e(as)g(1.)39 b(Then)23 b(after)i(all)g(the)g(data)f(ha)m(v)m
+(e)i(b)s(een)d(written)h(and)g(the)g(true)g(dimensions)g(are)g(kno)m
+(wn,)h(then)0 1267 y(the)33 b(NAXISn)f(v)-5 b(alue)33
+b(should)f(b)s(e)g(up)s(dated)g(using)g(the)h(\014ts)p
+2069 1267 28 4 v 33 w(up)s(date)p 2378 1267 V 32 w(k)m(ey)g(routine)g
+(b)s(efore)g(mo)m(ving)g(to)h(another)0 1380 y(extension)d(or)f
+(closing)i(the)e(FITS)g(\014le.)0 1540 y(When)f(writing)g(to)g(FITS)g
+(tables,)h(CFITSIO)d(automatically)32 b(k)m(eeps)e(trac)m(k)g(of)f(the)
+g(highest)h(ro)m(w)f(n)m(um)m(b)s(er)e(that)0 1653 y(is)32
+b(written)g(to,)h(and)e(will)h(increase)h(the)f(size)h(of)f(the)g
+(table)g(if)g(necessary)-8 b(.)46 b(CFITSIO)30 b(will)i(also)h
+(automatically)0 1766 y(insert)j(space)h(in)f(the)g(FITS)f(\014le)i(if)
+f(necessary)-8 b(,)39 b(to)e(ensure)e(that)i(the)f(data)h('heap',)h(if)
+e(it)h(exists,)h(and/or)f(an)m(y)0 1879 y(additional)29
+b(HDUs)g(that)g(follo)m(w)g(the)g(table)g(do)f(not)h(get)g(o)m(v)m
+(erwritten)h(as)e(new)g(ro)m(ws)g(are)h(written)f(to)h(the)g(table.)0
+2039 y(As)37 b(a)h(general)g(rule)f(it)h(is)f(b)s(est)g(to)h(sp)s
+(ecify)f(the)h(initial)g(n)m(um)m(b)s(er)e(of)i(ro)m(ws)f(=)g(0)g(when)
+g(the)g(table)h(is)g(created,)0 2152 y(then)g(let)h(CFITSIO)e(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)i(written.)65 b(The)38 b(application)0 2265
+y(program)e(should)f(not)i(man)m(ually)g(up)s(date)e(the)i(n)m(um)m(b)s
+(er)e(of)h(ro)m(ws)g(in)g(the)h(table)g(\(as)g(giv)m(en)g(b)m(y)f(the)h
+(NAXIS2)0 2378 y(k)m(eyw)m(ord\))j(since)f(CFITSIO)e(do)s(es)i(this)g
+(automatically)-8 b(.)69 b(If)38 b(a)i(table)f(is)g(initially)i
+(created)f(with)e(more)h(than)0 2491 y(zero)i(ro)m(ws,)j(then)c(this)h
+(will)f(usually)h(b)s(e)f(considered)g(as)h(the)g(minim)m(um)f(size)h
+(of)g(the)g(table,)j(ev)m(en)d(if)g(few)m(er)0 2604 y(ro)m(ws)30
+b(are)g(actually)h(written)f(to)h(the)f(table.)41 b(Th)m(us,)30
+b(if)f(a)i(table)f(is)g(initially)h(created)g(with)f(NAXIS2)g(=)g(20,)h
+(and)0 2717 y(CFITSIO)g(only)i(writes)f(10)i(ro)m(ws)e(of)h(data)g(b)s
+(efore)f(closing)i(the)f(table,)h(then)e(NAXIS2)h(will)g(remain)f
+(equal)h(to)0 2829 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)f(to)h(this)f(table,)i(then)e(NAXIS2)h
+(will)f(b)s(e)g(increased)g(from)g(20)0 2942 y(to)f(30.)44
+b(The)31 b(one)g(exception)i(to)f(this)f(automatic)i(up)s(dating)d(of)h
+(the)h(NAXIS2)f(k)m(eyw)m(ord)h(is)f(if)g(the)h(application)0
+3055 y(program)c(directly)g(mo)s(di\014es)f(the)i(v)-5
+b(alue)28 b(of)g(NAXIS2)g(\(up)f(or)h(do)m(wn\))g(itself)h(just)e(b)s
+(efore)h(closing)h(the)f(table.)41 b(In)0 3168 y(this)28
+b(case,)i(CFITSIO)d(do)s(es)h(not)h(up)s(date)e(NAXIS2)i(again,)h
+(since)f(it)g(assumes)f(that)h(the)f(application)i(program)0
+3281 y(m)m(ust)i(ha)m(v)m(e)h(had)f(a)g(go)s(o)s(d)g(reason)h(for)f(c)m
+(hanging)h(the)f(v)-5 b(alue)33 b(directly)-8 b(.)47
+b(This)31 b(is)h(not)h(recommended,)f(ho)m(w)m(ev)m(er,)0
+3394 y(and)j(is)h(only)g(pro)m(vided)g(for)f(bac)m(kw)m(ard)h
+(compatibilit)m(y)i(with)e(soft)m(w)m(are)h(that)g(initially)g(creates)
+g(a)f(table)h(with)0 3507 y(a)d(large)h(n)m(um)m(b)s(er)e(of)h(ro)m
+(ws,)h(than)f(decreases)g(the)h(NAXIS2)f(v)-5 b(alue)34
+b(to)h(the)f(actual)h(smaller)g(v)-5 b(alue)34 b(just)f(b)s(efore)0
+3620 y(closing)e(the)g(table.)0 4004 y Ff(4.13)136 b(CFITSIO)44
+b(Size)h(Limitations)0 4264 y Fj(CFITSIO)29 b(places)j(v)m(ery)f(few)g
+(restrictions)g(on)g(the)g(size)g(of)g(FITS)f(\014les)h(that)g(it)h
+(reads)e(or)h(writes.)42 b(There)30 b(are)i(a)0 4377
+y(few)e(limits,)h(ho)m(w)m(ev)m(er,)h(that)f(ma)m(y)g(a\013ect)h(some)f
+(extreme)g(cases:)0 4538 y(1.)43 b(The)31 b(maxim)m(um)g(n)m(um)m(b)s
+(er)f(of)h(FITS)f(\014les)h(that)h(ma)m(y)g(b)s(e)e(sim)m(ultaneously)i
+(op)s(ened)f(b)m(y)g(CFITSIO)e(is)i(set)h(b)m(y)0 4650
+y(NMAXFILES)i(as)g(de\014ned)f(in)h(\014tsio2.h.)52 b(It)34
+b(is)g(curren)m(tly)g(set)h(=)f(300)h(b)m(y)f(default.)52
+b(CFITSIO)32 b(will)i(allo)s(cate)0 4763 y(ab)s(out)f(80)g(*)h
+(NMAXFILES)f(b)m(ytes)g(of)g(memory)g(for)g(in)m(ternal)g(use.)48
+b(Note)34 b(that)g(the)f(underlying)f(C)g(compiler)0
+4876 y(or)39 b(op)s(erating)h(system,)j(ma)m(y)d(ha)m(v)m(e)g(a)g
+(smaller)g(limit)h(on)e(the)h(n)m(um)m(b)s(er)e(of)i(op)s(ened)e
+(\014les.)68 b(The)39 b(C)h(sym)m(b)s(olic)0 4989 y(constan)m(t)31
+b(F)m(OPEN)p 690 4989 V 34 w(MAX)f(is)g(in)m(tended)g(to)h(de\014ne)e
+(the)i(maxim)m(um)f(n)m(um)m(b)s(er)e(of)j(\014les)f(that)g(ma)m(y)h
+(op)s(en)e(at)i(once)0 5102 y(\(including)g(an)m(y)g(other)g(text)h(or)
+f(binary)f(\014les)h(that)h(ma)m(y)f(b)s(e)g(op)s(en,)f(not)h(just)g
+(FITS)f(\014les\).)43 b(On)30 b(some)h(systems)0 5215
+y(it)g(has)f(b)s(een)g(found)f(that)i(gcc)g(supp)s(orts)e(a)h(maxim)m
+(um)h(of)f(255)i(op)s(ened)e(\014les.)0 5375 y(2.)67
+b(It)40 b(used)e(to)i(b)s(e)e(common)i(for)f(computer)g(systems)g(to)h
+(only)f(supp)s(ort)f(disk)g(\014les)h(up)f(to)i(2**31)i(b)m(ytes)d(=)0
+5488 y(2.1)k(GB)g(in)f(size,)47 b(but)41 b(most)i(systems)f(no)m(w)g
+(supp)s(ort)f(larger)i(\014les.)76 b(CFITSIO)41 b(can)i(optionally)g
+(read)g(and)0 5601 y(write)37 b(these)h(so-called)h('large)f(\014les')g
+(that)f(are)h(greater)g(than)f(2.1)h(GB)g(on)f(platforms)g(where)g
+(they)g(are)h(sup-)0 5714 y(p)s(orted,)43 b(but)d(this)g(usually)h
+(requires)f(that)i(sp)s(ecial)f(compiler)g(option)g(\015ags)g(b)s(e)f
+(sp)s(eci\014ed)g(to)i(turn)d(on)i(this)p eop end
+%%Page: 28 36
+TeXDict begin 28 35 bop 0 299 a Fj(28)1763 b Fh(CHAPTER)29
+b(4.)112 b(PR)m(OGRAMMING)32 b(GUIDELINES)0 555 y Fj(option.)69
+b(On)39 b(lin)m(ux)h(and)f(solaris)i(systems)f(the)g(compiler)g
+(\015ags)g(are)g('-D)p 2617 555 28 4 v 34 w(LAR)m(GEFILE)p
+3184 555 V 33 w(SOUR)m(CE')f(and)g(`-)0 668 y(D)p 74
+668 V 33 w(FILE)p 318 668 V 33 w(OFFSET)p 719 668 V 32
+w(BITS=64'.)i(These)29 b(\015ags)h(ma)m(y)g(also)h(w)m(ork)f(on)g
+(other)g(platforms)f(but)g(this)h(has)g(not)g(b)s(een)0
+781 y(tested.)43 b(Starting)31 b(with)f(v)m(ersion)h(3.0)h(of)f
+(CFITSIO,)f(the)h(default)f(Mak)m(e\014le)j(that)e(is)g(distributed)f
+(with)g(CFIT-)0 894 y(SIO)h(will)h(include)g(these)g(2)g(compiler)h
+(\015ags)f(when)e(building)h(on)h(Solaris)g(and)g(Lin)m(ux)f(PC)g
+(systems.)45 b(Users)32 b(on)0 1007 y(other)g(platforms)g(will)g(need)f
+(to)i(add)e(these)h(compiler)h(\015ags)f(man)m(ually)g(if)g(they)g(w)m
+(an)m(t)g(to)h(supp)s(ort)d(large)j(\014les.)0 1120 y(In)j(most)i
+(cases)g(it)g(app)s(ears)e(that)i(it)g(is)f(not)h(necessary)f(to)h
+(include)f(these)h(compiler)g(\015ags)f(when)f(compiling)0
+1233 y(application)c(co)s(de)e(that)h(call)h(the)e(CFITSIO)f(library)h
+(routines.)0 1393 y(When)i(CFITSIO)e(is)i(built)g(with)g(large)h
+(\014le)f(supp)s(ort)e(\(e.g.,)35 b(on)d(Solaris)g(and)f(Lin)m(ux)h(PC)
+f(system)h(b)m(y)g(default\))0 1506 y(then)e(it)h(can)g(read)f(and)g
+(write)g(FITS)g(data)h(\014les)f(on)h(disk)e(that)i(ha)m(v)m(e)h(an)m
+(y)f(of)f(these)h(conditions:)136 1766 y Fc(\017)46 b
+Fj(FITS)30 b(\014les)g(larger)h(than)f(2.1)i(GB)f(in)f(size)136
+1953 y Fc(\017)46 b Fj(FITS)30 b(images)h(con)m(taining)h(greater)g
+(than)e(2.1)h(G)g(pixels)136 2141 y Fc(\017)46 b Fj(FITS)34
+b(images)i(that)g(ha)m(v)m(e)g(one)f(dimension)f(with)g(more)h(than)g
+(2.1)h(G)f(pixels)g(\(as)g(giv)m(en)h(b)m(y)f(one)g(of)g(the)227
+2254 y(NAXISn)30 b(k)m(eyw)m(ord\))136 2441 y Fc(\017)46
+b Fj(FITS)26 b(tables)h(con)m(taining)g(more)g(than)f(2.1E09)i(ro)m(ws)
+e(\(giv)m(en)i(b)m(y)e(the)g(NAXIS2)h(k)m(eyw)m(ord\),)h(or)e(with)g
+(ro)m(ws)227 2554 y(that)31 b(are)g(more)g(than)f(2.1)h(GB)g(wide)f
+(\(giv)m(en)i(b)m(y)e(the)h(NAXIS1)f(k)m(eyw)m(ord\))136
+2742 y Fc(\017)46 b Fj(FITS)36 b(binary)f(tables)i(with)f(a)h(v)-5
+b(ariable-length)38 b(arra)m(y)f(heap)f(that)h(is)f(larger)h(than)f
+(2.1)h(GB)g(\(giv)m(en)h(b)m(y)227 2855 y(the)31 b(PCOUNT)e(k)m(eyw)m
+(ord\))0 3115 y(The)c(curren)m(t)g(maxim)m(um)g(FITS)f(\014le)h(size)h
+(supp)s(orted)e(b)m(y)h(CFITSIO)e(is)j(ab)s(out)f(6)g(terab)m(ytes)i
+(\(con)m(taining)g(2**31)0 3227 y(FITS)d(blo)s(c)m(ks,)i(eac)m(h)g
+(2880)h(b)m(ytes)e(in)f(size\).)40 b(Curren)m(tly)-8
+b(,)26 b(supp)s(ort)d(for)i(large)g(\014les)g(in)g(CFITSIO)e(has)h(b)s
+(een)g(tested)0 3340 y(on)30 b(the)h(Lin)m(ux,)f(Solaris,)h(and)f(IBM)g
+(AIX)h(op)s(erating)g(systems.)0 3501 y(Note)26 b(that)f(when)e
+(writing)h(application)i(programs)e(that)h(are)f(in)m(tended)g(to)h
+(supp)s(ort)e(large)i(\014les)g(it)f(is)h(imp)s(ortan)m(t)0
+3613 y(to)31 b(use)g(64-bit)g(in)m(teger)h(v)-5 b(ariables)31
+b(to)h(store)f(quan)m(tities)h(suc)m(h)e(as)h(the)f(dimensions)g(of)h
+(images,)h(or)f(the)f(n)m(um)m(b)s(er)0 3726 y(of)38
+b(ro)m(ws)f(in)h(a)g(table.)63 b(These)38 b(programs)f(m)m(ust)g(also)i
+(call)g(the)f(sp)s(ecial)g(v)m(ersions)g(of)g(some)g(of)g(the)f
+(CFITSIO)0 3839 y(routines)28 b(that)h(ha)m(v)m(e)h(b)s(een)d(adapted)i
+(to)g(supp)s(ort)e(64-bit)i(in)m(tegers.)42 b(The)27
+b(names)i(of)f(these)h(routines)f(end)g(in)g('ll')0 3952
+y(\('el')k('el'\))g(to)f(distinguish)e(them)i(from)f(the)g(32-bit)i(in)
+m(teger)g(v)m(ersion)e(\(e.g.,)j(\014ts)p 2766 3952 V
+32 w(get)p 2918 3952 V 34 w(n)m(um)p 3127 3952 V 32 w(ro)m(wsll\).)p
+eop end
+%%Page: 29 37
+TeXDict begin 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)30 b(c)m(hapter)i(describ)s(es)e(the)i(basic)f(routines)
+g(in)g(the)g(CFITSIO)e(user)i(in)m(terface)h(that)g(pro)m(vide)f(all)h
+(the)g(func-)0 2293 y(tions)j(normally)g(needed)g(to)g(read)g(and)f
+(write)h(most)h(FITS)e(\014les.)54 b(It)35 b(is)g(recommended)f(that)i
+(these)f(routines)0 2406 y(b)s(e)d(used)g(for)g(most)h(applications)h
+(and)e(that)h(the)f(more)h(adv)-5 b(anced)33 b(routines)f(describ)s(ed)
+g(in)g(the)h(next)f(c)m(hapter)0 2518 y(only)e(b)s(e)g(used)g(in)g(sp)s
+(ecial)h(circumstances)g(when)e(necessary)-8 b(.)0 2679
+y(The)30 b(follo)m(wing)i(con)m(v)m(en)m(tions)g(are)f(used)e(in)i
+(this)f(c)m(hapter)h(in)f(the)g(description)h(of)f(eac)m(h)i(function:)
+0 2839 y(1.)39 b(Most)25 b(functions)e(ha)m(v)m(e)i(2)f(names:)37
+b(a)24 b(long)h(descriptiv)m(e)f(name)g(and)f(a)i(short)e(concise)i
+(name.)38 b(Both)25 b(names)f(are)0 2952 y(listed)g(on)f(the)g(\014rst)
+f(line)i(of)f(the)h(follo)m(wing)g(descriptions,)h(separated)e(b)m(y)h
+(a)f(slash)g(\(/\))h(c)m(haracter.)40 b(Programmers)0
+3065 y(ma)m(y)27 b(use)g(either)g(name)g(in)f(their)h(programs)g(but)f
+(the)h(long)g(names)g(are)g(recommended)f(to)i(help)e(do)s(cumen)m(t)h
+(the)0 3177 y(co)s(de)k(and)e(mak)m(e)j(it)f(easier)g(to)g(read.)0
+3338 y(2.)42 b(A)30 b(righ)m(t)h(arro)m(w)g(sym)m(b)s(ol)f(\()p
+Fb(>)p Fj(\))h(is)g(used)f(in)g(the)h(function)f(descriptions)g(to)i
+(separate)f(the)g(input)f(parameters)0 3451 y(from)j(the)g(output)f
+(parameters)i(in)f(the)g(de\014nition)g(of)g(eac)m(h)h(routine.)49
+b(This)32 b(sym)m(b)s(ol)h(is)g(not)g(actually)i(part)e(of)0
+3563 y(the)e(C)f(calling)h(sequence.)0 3724 y(3.)41 b(The)30
+b(function)g(parameters)h(are)g(de\014ned)e(in)h(more)g(detail)i(in)e
+(the)g(alphab)s(etical)i(listing)f(in)f(App)s(endix)f(B.)0
+3884 y(4.)39 b(The)23 b(\014rst)g(argumen)m(t)g(in)h(almost)g(all)h
+(the)e(functions)g(is)h(a)g(p)s(oin)m(ter)f(to)h(a)g(structure)f(of)h
+(t)m(yp)s(e)g(`\014ts\014le'.)38 b(Memory)0 3997 y(for)26
+b(this)g(structure)f(is)h(allo)s(cated)i(b)m(y)e(CFITSIO)e(when)h(the)h
+(FITS)g(\014le)g(is)g(\014rst)f(op)s(ened)g(or)h(created)h(and)e(is)h
+(freed)0 4110 y(when)j(the)i(FITS)f(\014le)g(is)g(closed.)0
+4270 y(5.)53 b(The)34 b(last)h(argumen)m(t)f(in)g(almost)i(all)f(the)f
+(functions)g(is)g(the)h(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,)h
+(otherwise)g(the)f(function)g(will)h(immediately)g(exit)g(without)g
+(doing)f(an)m(ything.)59 b(A)36 b(non-zero)0 4496 y(output)27
+b(v)-5 b(alue)27 b(indicates)i(that)e(an)g(error)g(o)s(ccurred)g(in)g
+(the)g(function.)39 b(In)27 b(most)g(cases)h(the)g(status)f(v)-5
+b(alue)28 b(is)f(also)0 4608 y(returned)i(as)i(the)f(v)-5
+b(alue)31 b(of)g(the)f(function)g(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)f(text)h(string)e(\(30)i(c)m(har)f
+(max.\))41 b(corresp)s(onding)28 b(to)h(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\))h(80-c)m(haracter)i(error)c
+(message)i(from)e(the)h(in)m(ternal)h(CFITSIO)d(stac)m(k)j(of)f(error)
+227 5714 y(messages)45 b(and)e(shift)h(an)m(y)g(remaining)g(messages)h
+(on)f(the)g(stac)m(k)h(up)e(one)h(lev)m(el.)83 b(Call)44
+b(this)g(routine)1905 5942 y(29)p eop end
+%%Page: 30 38
+TeXDict begin 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)c(to)h(get)g(eac)m(h)g
+(message)f(in)g(sequence.)39 b(The)26 b(function)f(returns)g(a)h(v)-5
+b(alue)26 b(=)f(0)h(and)g(a)g(n)m(ull)f(error)227 668
+y(message)32 b(when)d(the)i(error)f(stac)m(k)i(is)e(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)30 b(out)h(the)g(error)f
+(message)i(corresp)s(onding)e(to)h(the)g(input)f(status)h(v)-5
+b(alue)31 b(and)f(all)i(the)f(error)f(messages)227 1291
+y(on)d(the)h(CFITSIO)e(stac)m(k)j(to)f(the)f(sp)s(eci\014ed)g(\014le)g
+(stream)h(\(normally)g(to)g(stdout)f(or)g(stderr\).)40
+b(If)26 b(the)i(input)227 1404 y(status)j(v)-5 b(alue)31
+b(=)f(0)h(then)f(this)g(routine)g(do)s(es)g(nothing.)95
+1659 y Fe(void)47 b(fits_report_error)c(/)48 b(ffrprt)e(\(FILE)g
+(*stream,)g(status\))0 1914 y Fi(4)81 b Fj(The)44 b(\014ts)p
+461 1914 28 4 v 32 w(write)p 695 1914 V 33 w(errmark)g(routine)h(puts)f
+(an)h(in)m(visible)g(mark)m(er)g(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
+573 2027 V 34 w(errmark)31 b(routine)i(can)g(then)f(b)s(e)f(used)h(to)h
+(delete)h(an)m(y)f(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)g(of)g(the)g
+(mark)m(er.)63 b(This)37 b(preserv)m(es)g(an)m(y)h(older)g(error)f
+(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 1073 2253 V 34 w(errmsg)g(routine)h
+(simply)f(clears)i(all)g(the)f(messages)g(\(and)g(marks\))f(from)h(the)
+227 2365 y(stac)m(k.)g(These)31 b(routines)f(are)h(called)g(without)g
+(an)m(y)f(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)h(data)g(\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)h(parameter)g
+(determines)g(the)f(read/write)h(access)h(allo)m(w)m(ed)h(in)d(the)g
+(\014le)h(and)f(can)h(ha)m(v)m(e)227 5488 y(v)-5 b(alues)32
+b(of)g(READONL)-8 b(Y)32 b(\(0\))g(or)g(READ)m(WRITE)g(\(1\).)44
+b(The)31 b(\014lename)h(parameter)g(giv)m(es)h(the)e(name)h(of)227
+5601 y(the)f(\014le)g(to)g(b)s(e)f(op)s(ened,)h(follo)m(w)m(ed)h(b)m(y)
+f(an)f(optional)i(argumen)m(t)f(giving)h(the)f(name)f(or)h(index)f(n)m
+(um)m(b)s(er)g(of)227 5714 y(the)d(extension)g(within)g(the)f(FITS)g
+(\014le)h(that)g(should)f(b)s(e)g(mo)m(v)m(ed)i(to)f(and)f(op)s(ened)g
+(\(e.g.,)k Fe(myfile.fits+3)p eop end
+%%Page: 31 39
+TeXDict begin 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)g(within)g(the)h(\014le,)h(and)d Fe(myfile.fits[events])227
+668 y Fj(mo)m(v)m(es)d(to)f(the)g(extension)g(with)f(the)g(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)g(routine)g(is)
+g(similar)g(to)h(the)f(\014ts)p 2241 816 V 33 w(op)s(en)p
+2464 816 V 32 w(\014le)g(routine)g(except)h(that)f(it)h(do)s(es)f(not)
+227 929 y(supp)s(ort)22 b(the)h(extended)h(\014lename)f(syn)m(tax)h(in)
+f(the)h(input)e(\014le)i(name.)38 b(This)23 b(routine)g(simply)g(tries)
+h(to)g(op)s(en)227 1042 y(the)36 b(sp)s(eci\014ed)e(input)h(\014le)g
+(on)g(magnetic)i(disk.)55 b(This)34 b(routine)h(is)h(mainly)f(for)g
+(use)g(in)g(cases)h(where)f(the)227 1155 y(\014lename)f(\(or)h
+(directory)f(path\))g(con)m(tains)h(square)f(or)g(curly)f(brac)m(k)m
+(et)j(c)m(haracters)f(that)f(w)m(ould)g(confuse)227 1268
+y(the)d(extended)f(\014lename)h(parser.)227 1416 y(The)i(\014ts)p
+544 1416 V 32 w(op)s(en)p 766 1416 V 32 w(data)h(routine)e(is)h
+(similar)g(to)h(the)f(\014ts)p 2113 1416 V 32 w(op)s(en)p
+2335 1416 V 33 w(\014le)f(routine)h(except)h(that)f(it)h(will)f(mo)m(v)
+m(e)h(to)227 1529 y(the)23 b(\014rst)f(HDU)h(con)m(taining)h
+(signi\014can)m(t)f(data,)i(if)e(a)g(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)37
+b(as)g(part)h(of)f(the)h(\014lename.)61 b(In)37 b(this)g(case,)j(it)e
+(will)g(lo)s(ok)g(for)f(the)g(\014rst)g(IMA)m(GE)h(HDU)g(with)227
+1755 y(NAXIS)29 b(greater)h(than)e(0,)i(or)f(the)f(\014rst)g(table)i
+(that)f(do)s(es)g(not)g(con)m(tain)h(the)f(strings)f(`GTI')h(\(Go)s(o)s
+(d)g(Time)227 1868 y(In)m(terv)-5 b(al)31 b(extension\))h(or)e(`OBST)-8
+b(ABLE')31 b(in)f(the)h(EXTNAME)f(k)m(eyw)m(ord)h(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)h(and)e(\014ts)p 1305 2016 V 33
+w(op)s(en)p 1528 2016 V 32 w(image)i(routines)f(are)g(similar)h(to)f
+(\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)h(table)h(HDU)f(or)g(image)h(HDU)f(in)f(the)h(\014le,)h(resp)s
+(ectiv)m(ely)-8 b(,)29 b(if)c(a)h(HDU)h(name)227 2242
+y(or)k(n)m(um)m(b)s(er)e(is)h(not)h(sp)s(eci\014ed)e(as)i(part)f(of)h
+(the)f(\014lename.)227 2390 y(IRAF)c(images)g(\(.imh)g(format)g
+(\014les\))f(and)g(ra)m(w)h(binary)e(data)j(arra)m(ys)e(ma)m(y)h(also)h
+(b)s(e)e(op)s(ened)f(with)h(READ-)227 2503 y(ONL)-8 b(Y)37
+b(access.)60 b(CFITSIO)35 b(will)i(automatically)i(test)f(if)e(the)h
+(input)e(\014le)i(is)f(an)h(IRAF)f(image,)k(and)c(if,)227
+2616 y(so)c(will)g(con)m(v)m(ert)h(it)f(on)f(the)h(\015y)f(in)m(to)i(a)
+f(virtual)f(FITS)g(image)i(b)s(efore)e(it)h(is)g(op)s(ened)e(b)m(y)i
+(the)g(application)227 2729 y(program.)64 b(If)37 b(the)h(input)g
+(\014le)g(is)g(a)g(ra)m(w)g(binary)g(data)g(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)d(of)g(the)g(arra)m(y)h(m)m(ust)f(b)s(e)f(sp)s(eci\014ed)g
+(in)h(square)g(brac)m(k)m(ets)h(follo)m(wing)h(the)e(name)g(of)h(the)f
+(\014le)227 2955 y(\(e.g.)56 b('ra)m(w\014le.dat[i512,512]')40
+b(op)s(ens)34 b(a)i(512)g(x)f(512)h(short)e(in)m(teger)j(image\).)56
+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)g(on)f(ho)m(w)g(to)h(sp)s(ecify)f(the)g
+(ra)m(w)h(\014le)f(name.)64 b(The)38 b(ra)m(w)g(\014le)227
+3181 y(is)k(con)m(v)m(erted)g(on)f(the)h(\015y)f(in)m(to)h(a)f(virtual)
+h(FITS)e(image)j(in)e(memory)g(that)h(is)f(then)g(op)s(ened)g(b)m(y)g
+(the)227 3294 y(application)32 b(program)e(with)g(READONL)-8
+b(Y)31 b(access.)227 3442 y(Programs)g(can)g(read)f(the)h(input)e
+(\014le)i(from)f(the)h('stdin')f(\014le)h(stream)g(if)f(a)h(dash)f(c)m
+(haracter)i(\('-'\))g(is)f(giv)m(en)227 3555 y(as)e(the)f(\014lename.)
+40 b(Files)30 b(can)e(also)h(b)s(e)f(op)s(ened)f(o)m(v)m(er)j(the)e
+(net)m(w)m(ork)h(using)f(FTP)g(or)g(HTTP)g(proto)s(cols)h(b)m(y)227
+3668 y(supplying)g(the)i(appropriate)f(URL)h(as)f(the)h(\014lename.)227
+3816 y(The)43 b(input)f(\014le)h(can)h(b)s(e)f(mo)s(di\014ed)f(in)g(v)
+-5 b(arious)44 b(w)m(a)m(ys)g(to)g(create)g(a)g(virtual)f(\014le)h
+(\(usually)f(stored)g(in)227 3929 y(memory\))31 b(that)g(is)g(then)f
+(op)s(ened)f(b)m(y)i(the)f(application)i(program)e(b)m(y)h(supplying)e
+(a)i(\014ltering)g(or)f(binning)227 4042 y(sp)s(eci\014er)e(in)g
+(square)g(brac)m(k)m(ets)h(follo)m(wing)h(the)e(\014lename.)40
+b(Some)29 b(of)f(the)g(more)h(common)f(\014ltering)h(meth-)227
+4155 y(o)s(ds)j(are)h(illustrated)h(in)e(the)h(follo)m(wing)i
+(paragraphs,)e(but)f(users)g(should)f(refer)i(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)h
+(description)e(of)h(the)f(full)h(\014le)f(\014ltering)h(syn)m(tax.)227
+4416 y(When)c(op)s(ening)f(an)h(image,)h(a)g(rectangular)f(subset)f(of)
+h(the)g(ph)m(ysical)g(image)h(ma)m(y)g(b)s(e)e(op)s(ened)f(b)m(y)i
+(listing)227 4529 y(the)k(\014rst)e(and)h(last)h(pixel)g(in)f(eac)m(h)i
+(dimension)e(\(and)g(optional)h(pixel)g(skipping)f(factor\):)227
+4765 y Fe(myimage.fits[101:200,301:)o(400])227 5001 y
+Fj(will)g(create)h(and)e(op)s(en)f(a)i(100x100)i(pixel)e(virtual)g
+(image)g(of)g(that)g(section)g(of)g(the)f(ph)m(ysical)h(image,)i(and)
+227 5114 y Fe(myimage.fits[*,-*])c Fj(op)s(ens)k(a)h(virtual)g(image)h
+(that)f(is)g(the)g(same)g(size)h(as)e(the)h(ph)m(ysical)h(image)g(but)
+227 5227 y(has)c(b)s(een)g(\015ipp)s(ed)f(in)h(the)g(v)m(ertical)j
+(direction.)227 5375 y(When)28 b(op)s(ening)g(a)g(table,)i(the)e
+(\014ltering)g(syn)m(tax)h(can)f(b)s(e)f(used)h(to)g(add)g(or)g(delete)
+h(columns)f(or)g(k)m(eyw)m(ords)227 5488 y(in)g(the)g(virtual)h(table:)
+40 b Fe(myfile.fits[events][col)i(!time;)k(PI)h(=)h(PHA*1.2])26
+b Fj(op)s(ens)h(a)h(virtual)h(ta-)227 5601 y(ble)j(in)f(whic)m(h)g(the)
+h(TIME)f(column)g(has)g(b)s(een)g(deleted)h(and)f(a)g(new)g(PI)g
+(column)h(has)f(b)s(een)g(added)f(with)227 5714 y(a)41
+b(v)-5 b(alue)40 b(1.2)i(times)e(that)h(of)f(the)h(PHA)f(column.)70
+b(Similarly)-8 b(,)43 b(one)e(can)f(\014lter)h(a)f(table)h(to)g(k)m
+(eep)g(only)p eop end
+%%Page: 32 40
+TeXDict begin 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)f(a)g
+(selection)i(criterion:)48 b Fe(myfile.fits[events][pha)42
+b(>)47 b(50])33 b Fj(creates)j(and)227 668 y(op)s(ens)31
+b(a)g(virtual)h(table)g(con)m(taining)h(only)e(those)h(ro)m(ws)f(with)g
+(a)g(PHA)h(v)-5 b(alue)31 b(greater)i(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)h(and)e
+(mathematical)k(op)s(erators)d(can)g(b)s(e)g(used)f(in)h(the)g
+(selection)i(expression.)40 b(One)227 894 y(can)25 b(also)g(\014lter)g
+(table)g(ro)m(ws)f(using)g('Go)s(o)s(d)h(Time)f(In)m(terv)-5
+b(al')26 b(extensions,)g(and)e(spatial)h(region)g(\014lters)g(as)f(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(,)34
+b(table)e(columns)f(ma)m(y)h(b)s(e)f(binned)f(or)h(histogrammed)h(to)g
+(generate)h(a)e(virtual)h(image.)45 b(F)-8 b(or)32 b(ex-)227
+1280 y(ample,)d Fe(myfile.fits[events][bin)41 b(\(X,Y\)=4])26
+b Fj(will)h(result)h(in)f(a)h(2-dimensional)g(image)h(calculated)227
+1393 y(b)m(y)35 b(binning)e(the)i(X)f(and)g(Y)h(columns)f(in)g(the)h
+(ev)m(en)m(t)h(table)f(with)f(a)h(bin)f(size)h(of)g(4)f(in)h(eac)m(h)g
+(dimension.)227 1506 y(The)30 b(TLMINn)g(and)f(TLMAXn)h(k)m(eyw)m(ords)
+h(will)g(b)s(e)e(used)h(b)m(y)g(default)h(to)g(determine)f(the)h(range)
+f(of)h(the)227 1619 y(image.)227 1779 y(A)j(single)g(program)f(can)g
+(op)s(en)g(the)h(same)f(FITS)g(\014le)g(more)h(than)f(once)h(and)f
+(then)g(treat)h(the)g(resulting)227 1892 y(\014ts\014le)c(p)s(oin)m
+(ters)g(as)g(though)g(they)g(w)m(ere)h(completely)h(indep)s(enden)m(t)d
+(FITS)g(\014les.)40 b(Using)31 b(this)f(facilit)m(y)-8
+b(,)33 b(a)227 2005 y(program)f(can)f(op)s(en)g(a)h(FITS)f(\014le)g(t)m
+(wice,)j(mo)m(v)m(e)f(to)f(2)g(di\013eren)m(t)g(extensions)g(within)f
+(the)g(\014le,)h(and)f(then)227 2118 y(read)g(and)e(write)i(data)g(in)f
+(those)h(extensions)g(in)f(an)m(y)h(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)g(b)s(e)f(returned)f(if)h(the)h(sp)s
+(eci\014ed)f(\014le)h(already)g(exists,)i(unless)d(the)h(\014lename)f
+(is)h(pre\014xed)227 3522 y(with)30 b(an)g(exclamation)i(p)s(oin)m(t)e
+(\(!\).)42 b(In)29 b(that)i(case)g(CFITSIO)d(will)j(o)m(v)m(erwrite)g
+(\(delete\))h(an)m(y)f(existing)g(\014le)227 3635 y(with)36
+b(the)g(same)h(name.)57 b(Note)38 b(that)e(the)h(exclamation)h(p)s(oin)
+m(t)e(is)g(a)h(sp)s(ecial)f(UNIX)g(c)m(haracter)i(so)e(if)g(it)227
+3748 y(is)d(used)e(on)h(the)h(command)f(line)h(it)g(m)m(ust)f(b)s(e)g
+(preceded)g(b)m(y)g(a)g(bac)m(kslash)h(to)h(force)e(the)h(UNIX)g(shell)
+f(to)227 3860 y(accept)g(the)f(c)m(haracter)h(as)e(part)g(of)h(the)g
+(\014lename.)227 4021 y(The)26 b(output)h(\014le)g(will)g(b)s(e)f
+(written)h(to)g(the)g('stdout')g(\014le)g(stream)g(if)g(a)g(dash)f(c)m
+(haracter)i(\('-'\))g(or)f(the)g(string)227 4134 y('stdout')34
+b(is)f(giv)m(en)h(as)g(the)f(\014lename.)49 b(Similarly)-8
+b(,)35 b('-.gz')g(or)e('stdout.gz')i(will)f(cause)f(the)h(\014le)f(to)h
+(b)s(e)e(gzip)227 4247 y(compressed)e(b)s(efore)g(it)h(is)g(written)f
+(out)h(to)g(the)f(stdout)h(stream.)227 4407 y(Optionally)-8
+b(,)41 b(the)c(name)h(of)f(a)h(template)h(\014le)e(that)h(is)f(used)g
+(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)f(in)h(paren)m(theses)h(follo)m
+(wing)g(the)g(output)e(\014le)i(name.)64 b(The)38 b(template)h(\014le)g
+(ma)m(y)g(b)s(e)227 4633 y(another)32 b(FITS)e(\014le,)i(in)f(whic)m(h)
+g(case)i(the)e(new)g(\014le,)h(at)g(the)g(time)g(it)f(is)h(op)s(ened,)f
+(will)g(b)s(e)g(an)g(exact)i(cop)m(y)227 4746 y(of)38
+b(the)g(template)i(\014le)e(except)g(that)h(the)f(data)g(structures)g
+(\(images)h(and)e(tables\))i(will)f(b)s(e)g(\014lled)f(with)227
+4858 y(zeros.)k(Alternativ)m(ely)-8 b(,)32 b(the)d(template)i(\014le)e
+(ma)m(y)g(b)s(e)f(an)h(ASCI)s(I)e(format)i(text)h(\014le)f(con)m
+(taining)i(directiv)m(es)227 4971 y(that)e(de\014ne)e(the)h(k)m(eyw)m
+(ords)g(to)g(b)s(e)g(created)h(in)e(eac)m(h)i(HDU)g(of)f(the)g(\014le.)
+40 b(See)28 b(the)g('Extended)f(File)i(Name)227 5084
+y(Syn)m(tax')i(section)h(for)e(a)h(complete)g(description)g(of)f(the)h
+(template)h(\014le)e(syn)m(tax.)227 5245 y(The)f(\014ts)p
+540 5245 28 4 v 33 w(create)p 809 5245 V 34 w(disk\014le)g(routine)h
+(is)g(similar)g(to)g(the)g(\014ts)p 2238 5245 V 32 w(create)p
+2506 5245 V 34 w(\014le)g(routine)g(except)g(that)g(it)g(do)s(es)g(not)
+227 5357 y(supp)s(ort)36 b(the)i(extended)g(\014lename)g(syn)m(tax)g
+(in)g(the)g(input)f(\014le)h(name.)63 b(This)37 b(routine)h(simply)f
+(tries)h(to)227 5470 y(create)e(the)e(sp)s(eci\014ed)f(\014le)h(on)f
+(magnetic)j(disk.)50 b(This)33 b(routine)h(is)g(mainly)g(for)g(use)f
+(in)h(cases)g(where)g(the)227 5583 y(\014lename)g(\(or)h(directory)f
+(path\))g(con)m(tains)h(square)f(or)g(curly)f(brac)m(k)m(et)j(c)m
+(haracters)f(that)f(w)m(ould)g(confuse)227 5696 y(the)d(extended)f
+(\014lename)h(parser.)p eop end
+%%Page: 33 41
+TeXDict begin 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)28 b(a)f(previously)g
+(op)s(ened)g(FITS)g(\014le.)40 b(The)27 b(\014rst)f(routine)i(simply)f
+(closes)h(the)g(\014le,)g(whereas)f(the)h(second)227
+668 y(one)41 b(also)g(DELETES)e(THE)h(FILE,)g(whic)m(h)g(can)h(b)s(e)e
+(useful)h(in)g(cases)h(where)e(a)i(FITS)e(\014le)i(has)f(b)s(een)227
+781 y(partially)32 b(created,)f(but)f(then)g(an)g(error)g(o)s(ccurs)g
+(whic)m(h)h(prev)m(en)m(ts)f(it)h(from)f(b)s(eing)g(completed.)95
+1017 y Fe(int)47 b(fits_close_file)d(/)j(ffclos)g(\(fitsfile)e(*fptr,)h
+(>)h(int)g(*status\))95 1243 y(int)g(fits_delete_file)d(/)j(ffdelt)f
+(\(fitsfile)g(*fptr,)g(>)h(int)g(*status\))0 1479 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)h(t)m(yp)s(e)f
+(\(e.g.)40 b('\014le://',)227 1592 y('ftp://'\))32 b(of)f(the)f(op)s
+(ened)g(FITS)g(\014le.)95 1828 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 2054 y(int)g(fits_file_mode)d(/)k(ffflmd)e(\(fitsfile)f
+(*fptr,)h(>)i(int)f(*iomode,)e(int)i(*status\))95 2280
+y(int)g(fits_url_type)e(/)i(ffurlt)f(\(fitsfile)f(*fptr,)h(>)i(char)f
+(*urltype,)e(int)i(*status\))0 2610 y Ff(5.3)135 b(HDU)46
+b(Access)e(Routines)0 2860 y Fj(The)30 b(follo)m(wing)i(functions)e(p)s
+(erform)f(op)s(erations)h(on)h(Header-Data)h(Units)f(\(HDUs\))h(as)e(a)
+h(whole.)0 3096 y Fi(1)81 b Fj(Mo)m(v)m(e)44 b(to)g(a)f(di\013eren)m(t)
+g(HDU)g(in)g(the)g(\014le.)77 b(The)43 b(\014rst)f(routine)g(mo)m(v)m
+(es)i(to)g(a)f(sp)s(eci\014ed)f(absolute)h(HDU)227 3209
+y(n)m(um)m(b)s(er)f(\(starting)h(with)g(1)f(for)h(the)g(primary)e(arra)
+m(y\))j(in)e(the)h(FITS)f(\014le,)k(and)c(the)g(second)h(routine)227
+3322 y(mo)m(v)m(es)35 b(a)e(relativ)m(e)i(n)m(um)m(b)s(er)d(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)g(p)s(oin)m(ter)227 3435 y(ma)m(y)e(b)s(e)f(giv)m(en)h(for)f
+(the)g(hdut)m(yp)s(e)f(parameter)i(if)f(it's)h(v)-5 b(alue)31
+b(is)f(not)h(needed.)40 b(The)30 b(third)f(routine)i(mo)m(v)m(es)227
+3548 y(to)39 b(the)g(\(\014rst\))f(HDU)i(whic)m(h)e(has)g(the)h(sp)s
+(eci\014ed)e(extension)i(t)m(yp)s(e)g(and)f(EXTNAME)g(and)g(EXTVER)227
+3661 y(k)m(eyw)m(ord)26 b(v)-5 b(alues)26 b(\(or)g(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 3774 y(a)d(v)-5 b(alue)22 b(of)g(IMA)m(GE)p
+935 3774 28 4 v 34 w(HDU,)h(ASCI)s(I)p 1476 3774 V 31
+w(TBL,)f(BINAR)-8 b(Y)p 2101 3774 V 34 w(TBL,)22 b(or)g(ANY)p
+2676 3774 V 34 w(HDU)g(where)g(ANY)p 3396 3774 V 33 w(HDU)h(means)227
+3887 y(that)33 b(only)g(the)f(extname)i(and)d(extv)m(er)j(v)-5
+b(alues)33 b(will)f(b)s(e)g(used)g(to)h(lo)s(cate)h(the)f(correct)g
+(extension.)48 b(If)32 b(the)227 4000 y(input)i(v)-5
+b(alue)36 b(of)f(extv)m(er)h(is)f(0)h(then)e(the)i(EXTVER)e(k)m(eyw)m
+(ord)i(is)f(ignored)g(and)g(the)g(\014rst)f(HDU)i(with)f(a)227
+4112 y(matc)m(hing)28 b(EXTNAME)g(\(or)f(HDUNAME\))i(k)m(eyw)m(ord)e
+(will)g(b)s(e)g(found.)38 b(If)27 b(no)f(matc)m(hing)i(HDU)g(is)f
+(found)227 4225 y(in)f(the)g(\014le)g(then)g(the)g(curren)m(t)g(HDU)g
+(will)h(remain)f(unc)m(hanged)f(and)h(a)g(status)g(=)g(BAD)p
+3246 4225 V 33 w(HDU)p 3484 4225 V 34 w(NUM)h(will)227
+4338 y(b)s(e)j(returned.)95 4574 y Fe(int)47 b(fits_movabs_hdu)d(/)j
+(ffmahd)286 4687 y(\(fitsfile)f(*fptr,)g(int)h(hdunum,)e(>)j(int)f
+(*hdutype,)e(int)i(*status\))95 4913 y(int)g(fits_movrel_hdu)d(/)j
+(ffmrhd)286 5026 y(\(fitsfile)f(*fptr,)g(int)h(nmove,)f(>)h(int)g
+(*hdutype,)e(int)i(*status\))95 5252 y(int)g(fits_movnam_hdu)d(/)j
+(ffmnhd)286 5365 y(\(fitsfile)f(*fptr,)g(int)h(hdutype,)e(char)i
+(*extname,)e(int)i(extver,)f(>)h(int)g(*status\))0 5601
+y Fi(2)81 b Fj(Return)38 b(the)i(total)h(n)m(um)m(b)s(er)d(of)i(HDUs)g
+(in)f(the)h(FITS)f(\014le.)68 b(This)39 b(returns)f(the)h(n)m(um)m(b)s
+(er)g(of)g(completely)227 5714 y(de\014ned)30 b(HDUs)h(in)f(the)h
+(\014le.)42 b(If)30 b(a)h(new)f(HDU)h(has)g(just)f(b)s(een)g(added)f
+(to)j(the)f(FITS)f(\014le,)h(then)f(that)h(last)p eop
+end
+%%Page: 34 42
+TeXDict begin 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)227 555 y Fj(HDU)g(will)f(only)g(b)s(e)g(coun)m(ted)g(if)
+g(it)h(has)e(b)s(een)h(closed,)h(or)f(if)g(data)h(has)e(b)s(een)h
+(written)g(to)g(the)g(HDU.)h(The)227 668 y(curren)m(t)g(HDU)i(remains)e
+(unc)m(hanged)g(b)m(y)g(this)g(routine.)95 900 y Fe(int)47
+b(fits_get_num_hdus)c(/)48 b(ffthdu)286 1013 y(\(fitsfile)e(*fptr,)g(>)
+h(int)g(*hdunum,)f(int)h(*status\))0 1246 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)d(the)i(FITS)e(\014le)h(\(where)g(the)g(primary)g(arra)m
+(y)g(=)227 1359 y(1\).)42 b(This)29 b(function)h(returns)g(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 1591 y Fe(int)47 b(fits_get_hdu_num)d(/)j(ffghdn)286
+1704 y(\(fitsfile)f(*fptr,)g(>)h(int)g(*hdunum\))0 1936
+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)f(the)g(FITS)g(\014le.)67 b(The)39 b(p)s(ossible)g(v)-5
+b(alues)39 b(for)g(hdut)m(yp)s(e)f(are:)227 2049 y(IMA)m(GE)p
+546 2049 28 4 v 34 w(HDU,)31 b(ASCI)s(I)p 1095 2049 V
+32 w(TBL,)f(or)g(BINAR)-8 b(Y)p 1840 2049 V 34 w(TBL.)95
+2281 y Fe(int)47 b(fits_get_hdu_type)c(/)48 b(ffghdt)286
+2394 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*hdutype,)e(int)i(*status\))0
+2626 y Fi(5)81 b Fj(Cop)m(y)24 b(all)h(or)f(part)g(of)g(the)g(HDUs)h
+(in)f(the)g(FITS)g(\014le)g(asso)s(ciated)h(with)f(infptr)f(and)h(app)s
+(end)e(them)i(to)h(the)g(end)227 2739 y(of)f(the)f(FITS)f(\014le)i
+(asso)s(ciated)g(with)f(outfptr.)38 b(If)23 b('previous')g(is)g(true)g
+(\(not)h(0\),)i(then)d(an)m(y)g(HDUs)h(preceding)227
+2852 y(the)35 b(curren)m(t)f(HDU)g(in)g(the)h(input)e(\014le)h(will)h
+(b)s(e)e(copied)i(to)g(the)f(output)g(\014le.)52 b(Similarly)-8
+b(,)36 b('curren)m(t')f(and)227 2965 y('follo)m(wing')c(determine)e
+(whether)f(the)h(curren)m(t)g(HDU,)g(and/or)g(an)m(y)g(follo)m(wing)h
+(HDUs)g(in)e(the)h(input)f(\014le)227 3078 y(will)i(b)s(e)f(copied)i
+(to)f(the)g(output)f(\014le.)41 b(Th)m(us,)29 b(if)g(all)i(3)f
+(parameters)g(are)g(true,)g(then)g(the)f(en)m(tire)i(input)e(\014le)227
+3191 y(will)36 b(b)s(e)e(copied.)56 b(On)35 b(exit,)i(the)f(curren)m(t)
+f(HDU)h(in)e(the)i(input)e(\014le)i(will)f(b)s(e)g(unc)m(hanged,)h(and)
+f(the)g(last)227 3304 y(HDU)c(in)f(the)h(output)f(\014le)g(will)h(b)s
+(e)f(the)g(curren)m(t)h(HDU.)95 3536 y Fe(int)47 b(fits_copy_file)d(/)k
+(ffcpfl)286 3649 y(\(fitsfile)e(*infptr,)f(fitsfile)h(*outfptr,)f(int)i
+(previous,)e(int)i(current,)477 3762 y(int)g(following,)e(>)j(int)f
+(*status\))0 3994 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)h(asso)s(ciated)g(with)g(infptr)e(and)h
+(app)s(end)e(it)j(to)g(the)g(end)f(of)227 4107 y(the)39
+b(FITS)e(\014le)h(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 4220 y(k)m(eyw)m(ords)31 b(in)f(the)h(output)f(header.)
+95 4452 y Fe(int)47 b(fits_copy_hdu)e(/)i(ffcopy)286
+4565 y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(int)i(morekeys,)e
+(>)j(int)f(*status\))0 4798 y Fi(7)81 b Fj(W)-8 b(rite)31
+b(the)g(curren)m(t)f(HDU)h(in)f(the)h(input)e(FITS)h(\014le)g(to)h(the)
+g(output)f(FILE)g(stream)h(\(e.g.,)h(to)f(stdout\).)95
+5030 y Fe(int)47 b(fits_write_hdu)d(/)k(ffwrhdu)286 5143
+y(\(fitsfile)e(*infptr,)f(FILE)i(*stream,)e(>)j(int)f(*status\))0
+5375 y Fi(8)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)h(with)f(infptr)e(to)j(the)
+f(CHDU)227 5488 y(asso)s(ciated)28 b(with)e(outfptr.)39
+b(If)26 b(the)h(curren)m(t)f(output)g(HDU)h(is)g(not)f(completely)i
+(empt)m(y)-8 b(,)29 b(then)d(the)h(CHDU)227 5601 y(will)35
+b(b)s(e)f(closed)h(and)f(a)h(new)f(HDU)h(will)g(b)s(e)f(app)s(ended)e
+(to)j(the)g(output)f(\014le.)53 b(An)34 b(empt)m(y)h(output)f(data)227
+5714 y(unit)c(will)h(b)s(e)f(created)h(with)f(all)h(v)-5
+b(alues)31 b(initially)h(=)e(0\).)p eop end
+%%Page: 35 43
+TeXDict begin 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)95
+555 y Fe(int)47 b(fits_copy_header)d(/)j(ffcphd)286 668
+y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(>)i(int)g(*status\))0
+942 y Fi(9)81 b Fj(Delete)35 b(the)e(CHDU)h(in)f(the)g(FITS)f(\014le.)
+50 b(An)m(y)33 b(follo)m(wing)i(HDUs)e(will)h(b)s(e)e(shifted)h(forw)m
+(ard)g(in)g(the)g(\014le,)h(to)227 1054 y(\014ll)k(in)f(the)g(gap)h
+(created)g(b)m(y)g(the)f(deleted)h(HDU.)h(In)d(the)i(case)g(of)g
+(deleting)g(the)g(primary)e(arra)m(y)i(\(the)227 1167
+y(\014rst)30 b(HDU)h(in)f(the)h(\014le\))g(then)f(the)h(curren)m(t)f
+(primary)f(arra)m(y)i(will)g(b)s(e)f(replace)h(b)m(y)g(a)g(n)m(ull)f
+(primary)f(arra)m(y)227 1280 y(con)m(taining)k(the)f(minim)m(um)e(set)i
+(of)g(required)e(k)m(eyw)m(ords)i(and)e(no)i(data.)44
+b(If)31 b(there)g(are)h(more)f(extensions)227 1393 y(in)f(the)g(\014le)
+g(follo)m(wing)i(the)e(one)g(that)h(is)f(deleted,)h(then)f(the)g(the)g
+(CHDU)h(will)f(b)s(e)g(rede\014ned)e(to)j(p)s(oin)m(t)f(to)227
+1506 y(the)d(follo)m(wing)h(extension.)41 b(If)26 b(there)h(are)g(no)g
+(follo)m(wing)h(extensions)f(then)g(the)g(CHDU)g(will)g(b)s(e)f
+(rede\014ned)227 1619 y(to)36 b(p)s(oin)m(t)f(to)g(the)g(previous)f
+(HDU.)i(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 1732 y(CHDU.)c(A)g(n)m(ull)f(p)s(oin)m
+(ter)g(ma)m(y)h(b)s(e)f(giv)m(en)i(for)e(hdut)m(yp)s(e)f(if)h(the)h
+(returned)e(v)-5 b(alue)31 b(is)f(not)h(needed.)95 2005
+y Fe(int)47 b(fits_delete_hdu)d(/)j(ffdhdu)286 2118 y(\(fitsfile)f
+(*fptr,)g(>)h(int)g(*hdutype,)e(int)i(*status\))0 2468
+y Ff(5.4)135 b(Header)46 b(Keyw)l(ord)g(Read/W)-11 b(rite)46
+b(Routines)0 2722 y Fj(These)35 b(routines)g(read)f(or)h(write)h(k)m
+(eyw)m(ords)f(in)g(the)g(Curren)m(t)f(Header)h(Unit)g(\(CHU\).)h(Wild)g
+(card)e(c)m(haracters)0 2834 y(\(*,)28 b(?,)g(or)e(#\))h(ma)m(y)g(b)s
+(e)f(used)g(when)f(sp)s(ecifying)i(the)g(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)27
+b(matc)m(h)h(an)m(y)0 2947 y(single)35 b(c)m(haracter)g(at)g(that)f(p)s
+(osition)g(in)g(the)g(k)m(eyw)m(ord)h(name)f(and)f(a)h('*')h(will)g
+(matc)m(h)f(an)m(y)h(length)f(\(including)0 3060 y(zero\))c(string)f
+(of)g(c)m(haracters.)42 b(The)28 b('#')h(c)m(haracter)i(will)e(matc)m
+(h)h(an)m(y)f(consecutiv)m(e)i(string)e(of)g(decimal)h(digits)f(\(0)0
+3173 y(-)35 b(9\).)55 b(When)35 b(a)g(wild)g(card)g(is)g(used)f(the)h
+(routine)g(will)g(only)g(searc)m(h)h(for)f(a)g(matc)m(h)h(from)e(the)h
+(curren)m(t)g(header)0 3286 y(p)s(osition)27 b(to)h(the)f(end)f(of)h
+(the)g(header)g(and)f(will)h(not)g(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 3399
+y(the)k(original)i(header)e(p)s(osition)g(as)h(is)f(done)g(when)f(no)h
+(wildcards)g(are)h(included)e(in)h(the)g(k)m(eyw)m(ord)h(name.)43
+b(The)0 3512 y(\014ts)p 127 3512 28 4 v 32 w(read)p 331
+3512 V 33 w(record)29 b(routine)h(ma)m(y)g(b)s(e)f(used)f(to)i(set)g
+(the)g(starting)g(p)s(osition)f(when)g(doing)g(wild)g(card)h(searc)m
+(hes.)41 b(A)0 3625 y(status)29 b(v)-5 b(alue)30 b(of)f(KEY)p
+809 3625 V 32 w(NO)p 980 3625 V 33 w(EXIST)f(is)h(returned)e(if)i(the)g
+(sp)s(eci\014ed)f(k)m(eyw)m(ord)i(to)f(b)s(e)g(read)f(is)h(not)h(found)
+d(in)i(the)0 3738 y(header.)0 4045 y Fd(5.4.1)112 b(Keyw)m(ord)38
+b(Reading)g(Routines)0 4264 y Fi(1)81 b Fj(Return)33
+b(the)h(n)m(um)m(b)s(er)e(of)i(existing)h(k)m(eyw)m(ords)g(\(not)f
+(coun)m(ting)h(the)f(END)g(k)m(eyw)m(ord\))h(and)e(the)h(amoun)m(t)h
+(of)227 4377 y(space)e(curren)m(tly)f(a)m(v)-5 b(ailable)34
+b(for)e(more)g(k)m(eyw)m(ords.)46 b(It)32 b(returns)e(morek)m(eys)j(=)f
+(-1)g(if)g(the)g(header)g(has)g(not)227 4489 y(y)m(et)27
+b(b)s(een)d(closed.)40 b(Note)26 b(that)g(CFITSIO)d(will)j(dynamically)
+g(add)e(space)i(if)f(required)f(when)g(writing)h(new)227
+4602 y(k)m(eyw)m(ords)32 b(to)g(a)f(header)g(so)h(in)f(practice)h
+(there)g(is)f(no)g(limit)h(to)g(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 4715 y(added)e(to)h(a)f(header.)41
+b(A)30 b(n)m(ull)g(p)s(oin)m(ter)h(ma)m(y)f(b)s(e)g(en)m(tered)h(for)f
+(the)g(morek)m(eys)h(parameter)g(if)f(it's)h(v)-5 b(alue)31
+b(is)227 4828 y(not)g(needed.)95 5102 y Fe(int)47 b(fits_get_hdrspace)c
+(/)48 b(ffghsp)286 5215 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*keysexist,)e
+(int)i(*morekeys,)e(int)i(*status\))0 5488 y Fi(2)81
+b Fj(Return)28 b(the)h(sp)s(eci\014ed)f(k)m(eyw)m(ord.)41
+b(In)29 b(the)g(\014rst)f(routine,)i(the)f(datat)m(yp)s(e)h(parameter)g
+(sp)s(eci\014es)e(the)h(desired)227 5601 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)28 b(and)f(can)h(ha)m(v)m
+(e)h(one)f(of)g(the)g(follo)m(wing)h(sym)m(b)s(olic)g(constan)m(t)227
+5714 y(v)-5 b(alues:)47 b(TSTRING,)33 b(TLOGICAL)f(\(==)h(in)m(t\),)j
+(TBYTE,)d(TSHOR)-8 b(T,)33 b(TUSHOR)-8 b(T,)32 b(TINT,)h(TUINT,)p
+eop end
+%%Page: 36 44
+TeXDict begin 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(TLONG,)24 b(TULONG,)g(TLONGLONG,)g(TFLO)m(A)
+-8 b(T,)25 b(TDOUBLE,)f(TCOMPLEX,)f(and)h(TDBLCOM-)227
+668 y(PLEX.)j(Within)f(the)h(con)m(text)h(of)f(this)g(routine,)g
+(TSTRING)f(corresp)s(onds)f(to)i(a)g('c)m(har*')h(data)f(t)m(yp)s(e,)h
+(i.e.,)227 781 y(a)k(p)s(oin)m(ter)g(to)g(a)g(c)m(haracter)i(arra)m(y)
+-8 b(.)45 b(Data)33 b(t)m(yp)s(e)f(con)m(v)m(ersion)h(will)f(b)s(e)f(p)
+s(erformed)f(for)i(n)m(umeric)f(v)-5 b(alues)32 b(if)227
+894 y(the)27 b(k)m(eyw)m(ord)g(v)-5 b(alue)27 b(do)s(es)f(not)h(ha)m(v)
+m(e)h(the)f(same)g(data)g(t)m(yp)s(e.)40 b(If)26 b(the)h(v)-5
+b(alue)27 b(of)g(the)f(k)m(eyw)m(ord)i(is)e(unde\014ned)227
+1007 y(\(i.e.,)31 b(the)e(v)-5 b(alue)30 b(\014eld)e(is)h(blank\))g
+(then)f(an)h(error)g(status)g(=)f(V)-10 b(ALUE)p 2627
+1007 28 4 v 33 w(UNDEFINED)30 b(will)g(b)s(e)e(returned.)227
+1156 y(The)c(second)f(routine)h(returns)f(the)h(k)m(eyw)m(ord)g(v)-5
+b(alue)24 b(as)g(a)g(c)m(haracter)i(string)d(\(a)i(literal)g(cop)m(y)g
+(of)f(what)f(is)h(in)227 1269 y(the)j(v)-5 b(alue)26
+b(\014eld\))g(regardless)h(of)f(the)g(in)m(trinsic)h(data)g(t)m(yp)s(e)
+f(of)g(the)g(k)m(eyw)m(ord.)40 b(The)26 b(third)f(routine)h(returns)227
+1382 y(the)45 b(en)m(tire)h(80-c)m(haracter)i(header)c(record)h(of)g
+(the)g(k)m(eyw)m(ord,)k(with)c(an)m(y)g(trailing)h(blank)e(c)m
+(haracters)227 1495 y(stripp)s(ed)37 b(o\013.)64 b(The)38
+b(fourth)f(routine)h(returns)f(the)h(\(next\))h(header)f(record)g(that)
+h(con)m(tains)g(the)f(literal)227 1608 y(string)31 b(of)f(c)m
+(haracters)i(sp)s(eci\014ed)e(b)m(y)g(the)g('string')h(argumen)m(t.)227
+1757 y(If)f(a)h(NULL)f(commen)m(t)i(p)s(oin)m(ter)e(is)g(supplied)g
+(then)g(the)g(commen)m(t)i(string)e(will)h(not)f(b)s(e)g(returned.)95
+2013 y Fe(int)47 b(fits_read_key)e(/)i(ffgky)286 2126
+y(\(fitsfile)f(*fptr,)g(int)h(datatype,)e(char)i(*keyname,)e(>)i(DTYPE)
+g(*value,)334 2238 y(char)g(*comment,)e(int)i(*status\))95
+2464 y(int)g(fits_read_keyword)c(/)48 b(ffgkey)286 2577
+y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h(char)g(*value,)f(char)g
+(*comment,)334 2690 y(int)h(*status\))95 2916 y(int)g(fits_read_card)d
+(/)k(ffgcrd)286 3029 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h
+(char)g(*card,)f(int)h(*status\))95 3255 y(int)g(fits_read_str)e(/)i
+(ffgstr)286 3368 y(\(fitsfile)f(*fptr,)g(char)g(*string,)g(>)h(char)g
+(*card,)f(int)h(*status\))0 3623 y Fi(3)81 b Fj(Return)38
+b(the)h(n)m(th)f(header)h(record)g(in)f(the)i(CHU.)f(The)f(\014rst)g(k)
+m(eyw)m(ord)i(in)e(the)h(header)g(is)g(at)g(k)m(eyn)m(um)g(=)227
+3736 y(1;)53 b(if)45 b(k)m(eyn)m(um)g(=)f(0)h(then)g(these)g(routines)g
+(simply)f(reset)h(the)h(in)m(ternal)f(CFITSIO)e(p)s(oin)m(ter)i(to)h
+(the)227 3849 y(b)s(eginning)35 b(of)h(the)g(header)f(so)h(that)g
+(subsequen)m(t)f(k)m(eyw)m(ord)h(op)s(erations)g(will)g(start)g(at)g
+(the)g(top)g(of)g(the)227 3962 y(header)26 b(\(e.g.,)j(prior)c(to)h
+(searc)m(hing)h(for)f(k)m(eyw)m(ords)g(using)f(wild)g(cards)h(in)f(the)
+h(k)m(eyw)m(ord)h(name\).)39 b(The)26 b(\014rst)227 4074
+y(routine)32 b(returns)e(the)i(en)m(tire)h(80-c)m(haracter)h(header)e
+(record)g(\(with)f(trailing)i(blanks)e(truncated\),)i(while)227
+4187 y(the)41 b(second)f(routine)g(parses)g(the)g(record)h(and)e
+(returns)g(the)i(name,)i(v)-5 b(alue,)43 b(and)d(commen)m(t)h(\014elds)
+f(as)227 4300 y(separate)32 b(\(blank)f(truncated\))g(c)m(haracter)i
+(strings.)42 b(If)30 b(a)h(NULL)g(commen)m(t)h(p)s(oin)m(ter)f(is)g
+(giv)m(en)h(on)f(input,)227 4413 y(then)f(the)h(commen)m(t)g(string)g
+(will)f(not)h(b)s(e)f(returned.)95 4668 y Fe(int)47 b(fits_read_record)
+d(/)j(ffgrec)286 4781 y(\(fitsfile)f(*fptr,)g(int)h(keynum,)e(>)j(char)
+f(*card,)f(int)h(*status\))95 5007 y(int)g(fits_read_keyn)d(/)k(ffgkyn)
+286 5120 y(\(fitsfile)e(*fptr,)g(int)h(keynum,)e(>)j(char)f(*keyname,)e
+(char)h(*value,)334 5233 y(char)h(*comment,)e(int)i(*status\))0
+5488 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)h(in)f('inclist')i(but)e
+(do)s(es)g(not)227 5601 y(matc)m(h)31 b(an)m(y)g(of)g(the)f(strings)g
+(in)g('exclist'.)43 b(The)30 b(strings)g(in)g(inclist)h(and)f(exclist)i
+(ma)m(y)e(con)m(tain)i(wild)e(card)227 5714 y(c)m(haracters)k(\(*,)f
+(?,)f(and)f(#\))h(as)g(describ)s(ed)f(at)i(the)f(b)s(eginning)f(of)h
+(this)g(section.)46 b(This)31 b(routine)h(searc)m(hes)p
+eop end
+%%Page: 37 45
+TeXDict begin 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(from)35 b(the)g(curren)m(t)g(header)g(p)s(osition)g(to)h(the)f
+(end)f(of)h(the)h(header,)g(only)-8 b(,)37 b(and)d(do)s(es)h(not)g(con)
+m(tin)m(ue)i(the)227 668 y(searc)m(h)32 b(from)e(the)h(top)g(of)g(the)g
+(header)g(bac)m(k)g(to)h(the)f(original)h(p)s(osition.)42
+b(The)31 b(curren)m(t)f(header)h(p)s(osition)227 781
+y(ma)m(y)e(b)s(e)e(reset)h(with)g(the)g(\013grec)g(routine.)40
+b(Note)29 b(that)g(nexc)f(ma)m(y)g(b)s(e)f(set)h(=)g(0)g(if)g(there)g
+(are)g(no)g(k)m(eyw)m(ords)227 894 y(to)h(b)s(e)f(excluded.)39
+b(This)28 b(routine)g(returns)f(status)h(=)g(KEY)p 2268
+894 28 4 v 32 w(NO)p 2439 894 V 33 w(EXIST)f(if)h(a)h(matc)m(hing)g(k)m
+(eyw)m(ord)g(is)f(not)227 1007 y(found.)95 1226 y Fe(int)47
+b(fits_find_nextkey)c(/)48 b(ffgnxk)286 1339 y(\(fitsfile)e(*fptr,)g
+(char)g(**inclist,)f(int)i(ninc,)g(char)f(**exclist,)334
+1452 y(int)h(nexc,)f(>)i(char)e(*card,)h(int)94 b(*status\))0
+1671 y Fi(5)81 b Fj(Return)25 b(the)h(ph)m(ysical)g(units)g(string)g
+(from)f(an)h(existing)h(k)m(eyw)m(ord.)39 b(This)26 b(routine)g(uses)f
+(a)h(lo)s(cal)i(con)m(v)m(en)m(tion,)227 1784 y(sho)m(wn)d(in)g(the)g
+(follo)m(wing)i(example,)g(in)e(whic)m(h)g(the)h(k)m(eyw)m(ord)f(units)
+g(are)h(enclosed)g(in)f(square)g(brac)m(k)m(ets)h(in)227
+1896 y(the)k(b)s(eginning)f(of)h(the)g(k)m(eyw)m(ord)g(commen)m(t)g
+(\014eld.)40 b(A)30 b(n)m(ull)g(string)f(is)h(returned)e(if)i(no)f
+(units)g(are)h(de\014ned)227 2009 y(for)g(the)h(k)m(eyw)m(ord.)239
+2228 y Fe(VELOCITY=)809 b(12.3)46 b(/)i([km/s])e(orbital)g(speed)95
+2454 y(int)h(fits_read_key_unit)c(/)48 b(ffgunt)286 2567
+y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h(char)g(*unit,)f(int)h
+(*status\))0 2786 y Fi(6)81 b Fj(Concatenate)39 b(the)f(header)f(k)m
+(eyw)m(ords)h(in)g(the)f(CHDU)h(in)m(to)h(a)f(single)g(long)g(string)g
+(of)g(c)m(haracters.)64 b(This)227 2899 y(pro)m(vides)28
+b(a)h(con)m(v)m(enien)m(t)h(w)m(a)m(y)f(of)g(passing)f(all)h(or)f(part)
+g(of)g(the)h(header)f(information)g(in)g(a)h(FITS)e(HDU)i(to)227
+3012 y(other)i(subroutines.)39 b(Eac)m(h)31 b(80-c)m(haracter)h
+(\014xed-length)f(k)m(eyw)m(ord)f(record)g(is)g(app)s(ended)e(to)j(the)
+f(output)227 3125 y(c)m(haracter)j(string,)f(in)f(order,)g(with)g(no)g
+(in)m(terv)m(ening)i(separator)f(or)f(terminating)h(c)m(haracters.)45
+b(The)31 b(last)227 3238 y(header)e(record)g(is)g(terminated)h(with)f
+(a)g(NULL)g(c)m(haracter.)42 b(These)29 b(routine)g(allo)s(cates)j
+(memory)d(for)g(the)227 3351 y(returned)k(c)m(haracter)j(arra)m(y)-8
+b(,)37 b(so)d(the)h(calling)h(program)e(m)m(ust)g(free)g(the)h(memory)f
+(when)f(\014nished.)51 b(The)227 3464 y(cleanest)32 b(w)m(a)m(y)g(to)f
+(do)f(this)g(is)h(to)g(call)g(the)g(\014ts)p 1823 3464
+V 32 w(free)p 1999 3464 V 33 w(memory)g(routine.)227
+3607 y(There)38 b(are)h(2)g(related)g(routines:)57 b(\014ts)p
+1581 3607 V 32 w(hdr2str)37 b(simply)h(concatenates)j(all)f(the)e
+(existing)i(k)m(eyw)m(ords)e(in)227 3720 y(the)44 b(header;)51
+b(\014ts)p 863 3720 V 33 w(con)m(v)m(ert)p 1185 3720
+V 34 w(hdr2str)43 b(is)h(similar,)k(except)d(that)f(if)g(the)g(CHDU)h
+(is)f(a)g(tile)h(compressed)227 3833 y(image)c(\(stored)f(in)f(a)h
+(binary)e(table\))j(then)e(it)h(will)f(\014rst)g(con)m(v)m(ert)i(that)f
+(header)f(bac)m(k)h(to)g(that)g(of)g(the)227 3946 y(corresp)s(onding)30
+b(normal)g(FITS)g(image)h(b)s(efore)f(concatenating)j(the)e(k)m(eyw)m
+(ords.)227 4089 y(Selected)f(k)m(eyw)m(ords)e(ma)m(y)h(b)s(e)e
+(excluded)h(from)g(the)g(returned)f(c)m(haracter)j(string.)40
+b(If)27 b(the)i(second)f(param-)227 4202 y(eter)h(\(no)s(commen)m(ts\))
+g(is)f(TR)m(UE)g(\(nonzero\))h(then)e(an)m(y)i(COMMENT,)f(HISTOR)-8
+b(Y,)27 b(or)h(blank)g(k)m(eyw)m(ords)227 4315 y(in)i(the)h(header)f
+(will)h(not)f(b)s(e)g(copied)h(to)g(the)g(output)f(string.)227
+4458 y(The)25 b('exclist')j(parameter)e(ma)m(y)g(b)s(e)f(used)g(to)h
+(supply)e(a)i(list)h(of)e(k)m(eyw)m(ords)h(that)h(are)f(to)g(b)s(e)f
+(excluded)g(from)227 4571 y(the)k(output)g(c)m(haracter)h(string.)41
+b(Wild)29 b(card)g(c)m(haracters)h(\(*,)g(?,)f(and)g(#\))g(ma)m(y)g(b)s
+(e)f(used)g(in)h(the)g(excluded)227 4684 y(k)m(eyw)m(ord)h(names.)41
+b(If)29 b(no)g(additional)i(k)m(eyw)m(ords)f(are)g(to)g(b)s(e)f
+(excluded,)h(then)f(set)h(nexc)g(=)f(0)h(and)f(sp)s(ecify)227
+4797 y(NULL)i(for)f(the)g(the)h(**exclist)i(parameter.)95
+5016 y Fe(int)47 b(fits_hdr2str)e(/)i(ffhdr2str)286 5129
+y(\(fitsfile)f(*fptr,)g(int)h(nocomments,)d(char)j(**exclist,)e(int)i
+(nexc,)286 5242 y(>)h(char)e(**header,)g(int)h(*nkeys,)e(int)i
+(*status\))95 5468 y(int)g(fits_convert_hdr2str)c(/)k(ffcnvthdr2str)286
+5581 y(\(fitsfile)f(*fptr,)g(int)h(nocomments,)d(char)j(**exclist,)e
+(int)i(nexc,)286 5694 y(>)h(char)e(**header,)g(int)h(*nkeys,)e(int)i
+(*status\))p eop end
+%%Page: 38 46
+TeXDict begin 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 Fd(5.4.2)112 b(Keyw)m(ord)38 b(W)-9
+b(riting)37 b(Routines)0 775 y Fi(1)81 b Fj(W)-8 b(rite)32
+b(a)g(k)m(eyw)m(ord)g(of)f(the)h(appropriate)f(data)h(t)m(yp)s(e)g(in)m
+(to)g(the)g(CHU.)f(The)g(\014rst)g(routine)g(simply)g(app)s(ends)227
+888 y(a)j(new)f(k)m(eyw)m(ord)h(whereas)f(the)g(second)h(routine)f
+(will)h(up)s(date)e(the)i(v)-5 b(alue)33 b(and)g(commen)m(t)h(\014elds)
+f(of)h(the)227 1001 y(k)m(eyw)m(ord)g(if)g(it)g(already)g(exists,)h
+(otherwise)f(it)g(app)s(ends)e(a)i(new)f(k)m(eyw)m(ord.)51
+b(Note)35 b(that)f(the)g(address)e(to)227 1114 y(the)37
+b(v)-5 b(alue,)38 b(and)d(not)i(the)f(v)-5 b(alue)36
+b(itself,)j(m)m(ust)d(b)s(e)f(en)m(tered.)59 b(The)35
+b(datat)m(yp)s(e)i(parameter)g(sp)s(eci\014es)f(the)227
+1227 y(data)25 b(t)m(yp)s(e)f(of)g(the)g(k)m(eyw)m(ord)g(v)-5
+b(alue)25 b(with)e(one)h(of)g(the)g(follo)m(wing)i(v)-5
+b(alues:)37 b(TSTRING,)23 b(TLOGICAL)g(\(==)227 1340
+y(in)m(t\),)38 b(TBYTE,)d(TSHOR)-8 b(T,)34 b(TUSHOR)-8
+b(T,)35 b(TINT,)f(TUINT,)h(TLONG,)g(TLONGLONG,)g(TULONG,)227
+1452 y(TFLO)m(A)-8 b(T,)24 b(TDOUBLE.)f(Within)h(the)f(con)m(text)i(of)
+f(this)f(routine,)i(TSTRING)d(corresp)s(onds)g(to)i(a)g('c)m(har*')227
+1565 y(data)j(t)m(yp)s(e,)h(i.e.,)g(a)f(p)s(oin)m(ter)f(to)i(a)e(c)m
+(haracter)i(arra)m(y)-8 b(.)41 b(A)26 b(n)m(ull)g(p)s(oin)m(ter)h(ma)m
+(y)g(b)s(e)e(en)m(tered)i(for)f(the)h(commen)m(t)227
+1678 y(parameter)k(in)f(whic)m(h)g(case)i(the)e(k)m(eyw)m(ord)h(commen)
+m(t)h(\014eld)d(will)i(b)s(e)f(unmo)s(di\014ed)e(or)j(left)g(blank.)95
+1953 y Fe(int)47 b(fits_write_key)d(/)k(ffpky)286 2066
+y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(char)i(*keyname,)e(DTYPE)h
+(*value,)477 2179 y(char)h(*comment,)e(>)j(int)f(*status\))95
+2404 y(int)g(fits_update_key)d(/)j(ffuky)286 2517 y(\(fitsfile)f
+(*fptr,)g(int)h(datatype,)e(char)i(*keyname,)e(DTYPE)h(*value,)477
+2630 y(char)h(*comment,)e(>)j(int)f(*status\))0 2905
+y Fi(2)81 b Fj(W)-8 b(rite)44 b(a)g(k)m(eyw)m(ord)f(with)g(a)h(n)m(ull)
+f(or)g(unde\014ned)e(v)-5 b(alue)43 b(\(i.e.,)48 b(the)c(v)-5
+b(alue)43 b(\014eld)g(in)g(the)g(k)m(eyw)m(ord)h(is)f(left)227
+3018 y(blank\).)70 b(The)40 b(\014rst)f(routine)h(simply)g(app)s(ends)e
+(a)j(new)e(k)m(eyw)m(ord)i(whereas)f(the)g(second)g(routine)h(will)227
+3130 y(up)s(date)27 b(the)h(v)-5 b(alue)29 b(and)e(commen)m(t)i
+(\014elds)e(of)h(the)g(k)m(eyw)m(ord)g(if)g(it)g(already)h(exists,)g
+(otherwise)f(it)h(app)s(ends)227 3243 y(a)g(new)g(k)m(eyw)m(ord.)40
+b(A)29 b(n)m(ull)g(p)s(oin)m(ter)g(ma)m(y)g(b)s(e)g(en)m(tered)g(for)g
+(the)g(commen)m(t)g(parameter)h(in)e(whic)m(h)h(case)h(the)227
+3356 y(k)m(eyw)m(ord)h(commen)m(t)h(\014eld)d(will)i(b)s(e)f(unmo)s
+(di\014ed)e(or)j(left)g(blank.)95 3631 y Fe(int)47 b
+(fits_write_key_null)c(/)k(ffpkyu)286 3744 y(\(fitsfile)f(*fptr,)g
+(char)g(*keyname,)g(char)g(*comment,)g(>)h(int)g(*status\))95
+3970 y(int)g(fits_update_key_null)c(/)k(ffukyu)286 4082
+y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*comment,)g(>)h(int)g
+(*status\))0 4357 y Fi(3)81 b Fj(W)-8 b(rite)40 b(\(app)s(end\))e(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 4470 y(string)31
+b(will)f(b)s(e)g(con)m(tin)m(ued)h(o)m(v)m(er)h(m)m(ultiple)f(k)m(eyw)m
+(ords)g(if)f(it)h(is)f(longer)h(than)f(70)i(c)m(haracters.)95
+4744 y Fe(int)47 b(fits_write_comment)c(/)48 b(ffpcom)286
+4857 y(\(fitsfile)e(*fptr,)g(char)g(*comment,)g(>)h(int)g(*status\))95
+5083 y(int)g(fits_write_history)c(/)48 b(ffphis)286 5196
+y(\(fitsfile)e(*fptr,)g(char)g(*history,)g(>)h(int)g(*status\))0
+5470 y Fi(4)81 b Fj(W)-8 b(rite)29 b(the)g(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)29 b(will)f(con)m(tain)i(the)f(curren)m(t)f(system)g(date)227
+5583 y(as)k(a)g(c)m(haracter)h(string)e(in)g('yyyy-mm-ddThh:mm:ss')e
+(format.)44 b(If)31 b(a)h(D)m(A)-8 b(TE)32 b(k)m(eyw)m(ord)g(already)g
+(exists)227 5696 y(in)c(the)f(header,)i(then)e(this)g(routine)h(will)g
+(simply)f(up)s(date)g(the)h(k)m(eyw)m(ord)g(v)-5 b(alue)28
+b(with)f(the)h(curren)m(t)g(date.)p eop end
+%%Page: 39 47
+TeXDict begin 39 46 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(39)95
+555 y Fe(int)47 b(fits_write_date)d(/)j(ffpdat)286 668
+y(\(fitsfile)f(*fptr,)g(>)h(int)g(*status\))0 930 y Fi(5)81
+b Fj(W)-8 b(rite)34 b(a)g(user)f(sp)s(eci\014ed)g(k)m(eyw)m(ord)h
+(record)f(in)m(to)h(the)g(CHU.)g(This)e(is)i(a)g(lo)m(w{lev)m(el)i
+(routine)e(whic)m(h)f(can)h(b)s(e)227 1043 y(used)f(to)h(write)f(an)m
+(y)h(arbitrary)f(record)g(in)m(to)i(the)e(header.)50
+b(The)32 b(record)i(m)m(ust)f(conform)g(to)h(the)g(all)g(the)227
+1156 y(FITS)c(format)h(requiremen)m(ts.)95 1418 y Fe(int)47
+b(fits_write_record)c(/)48 b(ffprec)286 1531 y(\(fitsfile)e(*fptr,)g
+(char)g(*card,)g(>)i(int)f(*status\))0 1793 y Fi(6)81
+b Fj(Up)s(date)34 b(an)g(80-c)m(haracter)j(record)e(in)f(the)g(CHU.)h
+(If)f(a)h(k)m(eyw)m(ord)f(with)h(the)f(input)g(name)g(already)h
+(exists,)227 1906 y(then)e(it)h(is)f(o)m(v)m(erwritten)h(b)m(y)f(the)g
+(v)-5 b(alue)34 b(of)f(card.)49 b(This)32 b(could)h(mo)s(dify)f(the)i
+(k)m(eyw)m(ord)f(name)g(as)h(w)m(ell)g(as)227 2019 y(the)c(v)-5
+b(alue)30 b(and)e(commen)m(t)j(\014elds.)40 b(If)29 b(the)g(k)m(eyw)m
+(ord)h(do)s(esn't)f(already)h(exist)g(then)g(a)f(new)g(k)m(eyw)m(ord)h
+(card)227 2132 y(is)h(app)s(ended)d(to)j(the)g(header.)95
+2394 y Fe(int)47 b(fits_update_card)d(/)j(ffucrd)286
+2507 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*card,)g(>)i
+(int)f(*status\))0 2769 y Fi(7)81 b Fj(Mo)s(dify)30 b(\(o)m(v)m
+(erwrite\))i(the)f(commen)m(t)g(\014eld)f(of)h(an)f(existing)h(k)m(eyw)
+m(ord.)95 3031 y Fe(int)47 b(fits_modify_comment)c(/)k(ffmcom)286
+3144 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*comment,)g(>)h
+(int)g(*status\))0 3406 y Fi(8)81 b Fj(W)-8 b(rite)33
+b(the)f(ph)m(ysical)h(units)f(string)g(in)m(to)h(an)f(existing)h(k)m
+(eyw)m(ord.)46 b(This)32 b(routine)g(uses)g(a)g(lo)s(cal)i(con)m(v)m
+(en)m(tion,)227 3519 y(sho)m(wn)e(in)g(the)h(follo)m(wing)h(example,)g
+(in)e(whic)m(h)g(the)h(k)m(eyw)m(ord)g(units)f(are)h(enclosed)g(in)f
+(square)g(brac)m(k)m(ets)227 3632 y(in)e(the)h(b)s(eginning)f(of)g(the)
+h(k)m(eyw)m(ord)g(commen)m(t)g(\014eld.)239 3894 y Fe(VELOCITY=)809
+b(12.3)46 b(/)i([km/s])e(orbital)g(speed)95 4120 y(int)h
+(fits_write_key_unit)c(/)k(ffpunt)286 4233 y(\(fitsfile)f(*fptr,)g
+(char)g(*keyname,)g(char)g(*unit,)g(>)i(int)f(*status\))0
+4495 y Fi(9)81 b Fj(Rename)30 b(an)h(existing)g(k)m(eyw)m(ord,)g
+(preserving)f(the)g(curren)m(t)h(v)-5 b(alue)30 b(and)g(commen)m(t)i
+(\014elds.)95 4757 y Fe(int)47 b(fits_modify_name)d(/)j(ffmnam)286
+4870 y(\(fitsfile)f(*fptr,)g(char)g(*oldname,)g(char)g(*newname,)g(>)h
+(int)g(*status\))0 5132 y Fi(10)f Fj(Delete)37 b(a)e(k)m(eyw)m(ord)g
+(record.)54 b(The)34 b(space)i(o)s(ccupied)e(b)m(y)h(the)g(k)m(eyw)m
+(ord)g(is)g(reclaimed)h(b)m(y)e(mo)m(ving)i(all)g(the)227
+5245 y(follo)m(wing)e(header)f(records)f(up)g(one)h(ro)m(w)f(in)h(the)f
+(header.)48 b(The)32 b(\014rst)g(routine)g(deletes)i(a)f(k)m(eyw)m(ord)
+g(at)h(a)227 5357 y(sp)s(eci\014ed)23 b(p)s(osition)h(in)g(the)g
+(header)f(\(the)i(\014rst)e(k)m(eyw)m(ord)h(is)g(at)g(p)s(osition)g
+(1\),)i(whereas)e(the)g(second)g(routine)227 5470 y(deletes)30
+b(a)f(sp)s(eci\014cally)g(named)f(k)m(eyw)m(ord.)41 b(Wild)29
+b(card)f(c)m(haracters)i(ma)m(y)f(b)s(e)f(used)g(when)f(sp)s(ecifying)i
+(the)227 5583 y(name)23 b(of)g(the)f(k)m(eyw)m(ord)h(to)h(b)s(e)e
+(deleted.)38 b(The)22 b(third)g(routine)h(deletes)g(the)g(\(next\))h(k)
+m(eyw)m(ord)f(that)g(con)m(tains)227 5696 y(the)31 b(literal)h(c)m
+(haracter)g(string)e(sp)s(eci\014ed)g(b)m(y)g(the)h('string')f(argumen)
+m(t.)p eop end
+%%Page: 40 48
+TeXDict begin 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)95 555 y Fe(int)47 b(fits_delete_record)c(/)48
+b(ffdrec)286 668 y(\(fitsfile)e(*fptr,)g(int)142 b(keynum,)94
+b(>)47 b(int)g(*status\))95 894 y(int)g(fits_delete_key)d(/)j(ffdkey)
+286 1007 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(>)h(int)g
+(*status\))95 1233 y(int)g(fits_delete_str)d(/)j(ffdstr)286
+1346 y(\(fitsfile)f(*fptr,)g(char)g(*string,)g(>)h(int)g(*status\))0
+1678 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 1929 y Fj(These)22 b(routines)g(read)h(or)f(write)h
+(data)g(v)-5 b(alues)23 b(in)f(the)g(primary)g(data)h(arra)m(y)g
+(\(i.e.,)j(the)c(\014rst)g(HDU)h(in)f(a)h(FITS)e(\014le\))0
+2042 y(or)32 b(an)g(IMA)m(GE)h(extension.)47 b(There)31
+b(are)i(also)g(routines)f(to)h(get)g(information)f(ab)s(out)g(the)g
+(data)h(t)m(yp)s(e)g(and)e(size)0 2154 y(of)c(the)g(image.)41
+b(Users)27 b(should)f(also)i(read)f(the)g(follo)m(wing)h(c)m(hapter)g
+(on)f(the)g(CFITSIO)e(iterator)k(function)d(whic)m(h)0
+2267 y(pro)m(vides)33 b(a)h(more)f(`ob)5 b(ject)35 b(orien)m(ted')f
+(metho)s(d)f(of)g(reading)g(and)g(writing)g(images.)51
+b(The)32 b(iterator)j(function)e(is)0 2380 y(a)e(little)i(more)e
+(complicated)h(to)g(use,)f(but)f(the)h(adv)-5 b(an)m(tages)32
+b(are)f(that)h(it)f(usually)g(tak)m(es)h(less)f(co)s(de)g(to)g(p)s
+(erform)0 2493 y(the)37 b(same)f(op)s(eration,)j(and)c(the)i(resulting)
+f(program)g(often)h(runs)e(faster)i(b)s(ecause)f(the)g(FITS)g(\014les)g
+(are)h(read)0 2606 y(and)30 b(written)g(using)g(the)h(most)f(e\016cien)
+m(t)i(blo)s(c)m(k)f(size.)0 2766 y(C)25 b(programmers)h(should)f(note)h
+(that)g(the)h(ordering)e(of)h(arra)m(ys)g(in)g(FITS)f(\014les,)i(and)e
+(hence)h(in)g(all)g(the)g(CFITSIO)0 2879 y(calls,)40
+b(is)d(more)g(similar)h(to)f(the)h(dimensionalit)m(y)g(of)f(arra)m(ys)g
+(in)g(F)-8 b(ortran)38 b(rather)f(than)f(C.)h(F)-8 b(or)38
+b(instance)g(if)f(a)0 2992 y(FITS)28 b(image)i(has)e(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)i
+(enough)e(to)i(hold)e(the)0 3105 y(image)k(should)d(b)s(e)h(declared)h
+(as)f(arra)m(y[50][100])k(and)c(not)h(as)f(arra)m(y[100][50].)0
+3265 y(The)h(`datat)m(yp)s(e')h(parameter)g(sp)s(eci\014es)e(the)i
+(data)g(t)m(yp)s(e)f(of)g(the)g(`n)m(ulv)-5 b(al')32
+b(and)f(`arra)m(y')h(p)s(oin)m(ters)f(and)f(can)i(ha)m(v)m(e)0
+3378 y(one)h(of)g(the)g(follo)m(wing)h(v)-5 b(alues:)46
+b(TBYTE,)33 b(TSBYTE,)f(TSHOR)-8 b(T,)32 b(TUSHOR)-8
+b(T,)32 b(TINT,)h(TUINT,)f(TLONG,)0 3491 y(TLONGLONG,)26
+b(TULONG,)g(TFLO)m(A)-8 b(T,)27 b(TDOUBLE.)f(Automatic)i(data)f(t)m(yp)
+s(e)g(con)m(v)m(ersion)g(is)f(p)s(erformed)f(if)0 3604
+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)e(from)
+h(that)g(sp)s(eci\014ed)f(b)m(y)0 3717 y('datat)m(yp)s(e'.)54
+b(The)34 b(data)h(v)-5 b(alues)35 b(are)f(also)i(automatically)h
+(scaled)e(b)m(y)f(the)h(BSCALE)f(and)f(BZER)m(O)h(k)m(eyw)m(ord)0
+3830 y(v)-5 b(alues)31 b(as)f(they)h(are)g(b)s(eing)f(read)g(or)g
+(written)h(in)f(the)g(FITS)g(arra)m(y)-8 b(.)0 4084 y
+Fi(1)81 b Fj(Get)33 b(the)f(data)h(t)m(yp)s(e)f(or)g(equiv)-5
+b(alen)m(t)34 b(data)f(t)m(yp)s(e)f(of)g(the)h(image.)47
+b(The)32 b(\014rst)f(routine)h(returns)f(the)h(ph)m(ysical)227
+4197 y(data)46 b(t)m(yp)s(e)f(of)h(the)f(FITS)f(image,)51
+b(as)45 b(giv)m(en)h(b)m(y)f(the)g(BITPIX)g(k)m(eyw)m(ord,)50
+b(with)44 b(allo)m(w)m(ed)j(v)-5 b(alues)46 b(of)227
+4310 y(BYTE)p 492 4310 28 4 v 33 w(IMG)23 b(\(8\),)i(SHOR)-8
+b(T)p 1215 4310 V 32 w(IMG)23 b(\(16\),)i(LONG)p 1934
+4310 V 33 w(IMG)e(\(32\),)i(LONGLONG)p 2921 4310 V 33
+w(IMG)e(\(64\),)i(FLO)m(A)-8 b(T)p 3684 4310 V 33 w(IMG)227
+4423 y(\(-32\),)31 b(and)c(DOUBLE)p 1043 4423 V 33 w(IMG)h(\(-64\).)42
+b(The)27 b(second)h(routine)f(is)h(similar,)h(except)g(that)f(if)g(the)
+g(image)h(pixel)227 4536 y(v)-5 b(alues)33 b(are)g(scaled,)g(with)f
+(non-default)h(v)-5 b(alues)32 b(for)g(the)h(BZER)m(O)f(and)g(BSCALE)f
+(k)m(eyw)m(ords,)j(then)e(the)227 4649 y(routine)j(will)g(return)e(the)
+i('equiv)-5 b(alen)m(t')36 b(data)f(t)m(yp)s(e)g(that)g(is)f(needed)h
+(to)g(store)g(the)g(scaled)g(v)-5 b(alues.)53 b(F)-8
+b(or)227 4762 y(example,)29 b(if)e(BITPIX)g(=)g(16)h(and)f(BSCALE)f(=)h
+(0.1)h(then)f(the)h(equiv)-5 b(alen)m(t)28 b(data)g(t)m(yp)s(e)g(is)f
+(FLO)m(A)-8 b(T)p 3659 4762 V 33 w(IMG.)227 4875 y(Similarly)25
+b(if)f(BITPIX)g(=)g(16,)i(BSCALE)e(=)g(1,)i(and)d(BZER)m(O)h(=)g
+(32768,)k(then)c(the)g(the)h(pixel)f(v)-5 b(alues)25
+b(span)227 4987 y(the)31 b(range)g(of)f(an)g(unsigned)g(short)g(in)m
+(teger)h(and)f(the)h(returned)e(data)i(t)m(yp)s(e)g(will)f(b)s(e)g
+(USHOR)-8 b(T)p 3572 4987 V 32 w(IMG.)95 5242 y Fe(int)47
+b(fits_get_img_type)c(/)48 b(ffgidt)286 5355 y(\(fitsfile)e(*fptr,)g(>)
+h(int)g(*bitpix,)f(int)h(*status\))95 5581 y(int)g
+(fits_get_img_equivtype)42 b(/)48 b(ffgiet)286 5694 y(\(fitsfile)e
+(*fptr,)g(>)h(int)g(*bitpix,)f(int)h(*status\))p eop
+end
+%%Page: 41 49
+TeXDict begin 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)0 555 y Fi(2)81 b Fj(Get)34 b(the)g(n)m(um)m(b)s
+(er)e(of)i(dimensions,)g(and/or)g(the)g(size)g(of)g(eac)m(h)h
+(dimension)e(in)g(the)h(image)h(.)50 b(The)33 b(n)m(um)m(b)s(er)227
+668 y(of)h(axes)f(in)g(the)g(image)i(is)e(giv)m(en)h(b)m(y)f(naxis,)h
+(and)f(the)g(size)h(of)f(eac)m(h)i(dimension)d(is)h(giv)m(en)h(b)m(y)f
+(the)h(naxes)227 781 y(arra)m(y)d(\(a)g(maxim)m(um)g(of)f(maxdim)g
+(dimensions)g(will)g(b)s(e)g(returned\).)95 1036 y Fe(int)47
+b(fits_get_img_dim)d(/)j(ffgidm)286 1149 y(\(fitsfile)f(*fptr,)g(>)h
+(int)g(*naxis,)f(int)h(*status\))95 1375 y(int)g(fits_get_img_size)c(/)
+48 b(ffgisz)286 1488 y(\(fitsfile)e(*fptr,)g(int)h(maxdim,)e(>)j(long)f
+(*naxes,)e(int)i(*status\))95 1714 y(int)g(fits_get_img_sizell)c(/)k
+(ffgiszll)286 1827 y(\(fitsfile)f(*fptr,)g(int)h(maxdim,)e(>)j
+(LONGLONG)d(*naxes,)h(int)h(*status\))95 2052 y(int)g
+(fits_get_img_param)c(/)48 b(ffgipr)286 2165 y(\(fitsfile)e(*fptr,)g
+(int)h(maxdim,)e(>)j(int)f(*bitpix,)e(int)i(*naxis,)f(long)h(*naxes,)
+334 2278 y(int)g(*status\))95 2504 y(int)g(fits_get_img_paramll)c(/)k
+(ffgiprll)286 2617 y(\(fitsfile)f(*fptr,)g(int)h(maxdim,)e(>)j(int)f
+(*bitpix,)e(int)i(*naxis,)f(LONGLONG)g(*naxes,)334 2730
+y(int)h(*status\))0 2985 y Fi(3)81 b Fj(Create)23 b(a)f(new)g(primary)f
+(arra)m(y)i(or)f(IMA)m(GE)i(extension)e(with)g(a)h(sp)s(eci\014ed)f
+(data)h(t)m(yp)s(e)f(and)g(size.)38 b(If)22 b(the)h(FITS)227
+3098 y(\014le)30 b(is)g(curren)m(tly)f(empt)m(y)h(then)g(a)g(primary)f
+(arra)m(y)h(is)g(created,)h(otherwise)f(a)g(new)f(IMA)m(GE)i(extension)
+f(is)227 3211 y(app)s(ended)f(to)i(the)g(\014le.)95 3466
+y Fe(int)47 b(fits_create_img)d(/)j(ffcrim)286 3579 y(\()h(fitsfile)d
+(*fptr,)h(int)h(bitpix,)f(int)h(naxis,)f(long)h(*naxes,)f(>)h(int)g
+(*status\))95 3805 y(int)g(fits_create_imgll)c(/)48 b(ffcrimll)286
+3918 y(\()g(fitsfile)d(*fptr,)h(int)h(bitpix,)f(int)h(naxis,)f
+(LONGLONG)g(*naxes,)g(>)h(int)g(*status\))0 4173 y Fi(4)81
+b Fj(Cop)m(y)39 b(an)f(n-dimensional)h(image)h(in)f(a)g(particular)h
+(ro)m(w)f(and)f(column)h(of)g(a)g(binary)f(table)i(\(in)f(a)g(v)m
+(ector)227 4286 y(column\))31 b(to)g(or)f(from)g(a)h(primary)e(arra)m
+(y)i(or)g(image)g(extension.)227 4435 y(The)c('cell2image')k(routine)d
+(will)g(app)s(end)e(a)i(new)f(image)i(extension)f(\(or)g(primary)f
+(arra)m(y\))h(to)h(the)e(output)227 4548 y(\014le.)43
+b(An)m(y)31 b(W)m(CS)g(k)m(eyw)m(ords)g(asso)s(ciated)h(with)f(the)g
+(input)f(column)h(image)h(will)f(b)s(e)f(translated)i(in)m(to)g(the)227
+4661 y(appropriate)j(form)g(for)g(an)f(image)j(extension.)55
+b(An)m(y)35 b(other)g(k)m(eyw)m(ords)g(in)g(the)g(table)h(header)f
+(that)h(are)227 4774 y(not)28 b(sp)s(eci\014cally)h(related)f(to)h
+(de\014ning)e(the)g(binary)g(table)i(structure)e(or)h(to)g(other)g
+(columns)g(in)f(the)h(table)227 4887 y(will)j(also)g(b)s(e)f(copied)h
+(to)g(the)g(header)f(of)g(the)h(output)f(image.)227 5036
+y(The)i('image2cell')k(routine)c(will)h(cop)m(y)g(the)g(input)e(image)j
+(in)m(to)f(the)g(sp)s(eci\014ed)f(ro)m(w)g(and)g(column)g(of)h(the)227
+5149 y(curren)m(t)e(binary)g(table)h(in)f(the)h(output)f(\014le.)44
+b(The)31 b(binary)f(table)j(HDU)f(m)m(ust)f(exist)h(b)s(efore)f
+(calling)i(this)227 5262 y(routine,)h(but)f(it)h(ma)m(y)f(b)s(e)g(empt)
+m(y)-8 b(,)35 b(with)e(no)g(ro)m(ws)g(or)g(columns)g(of)g(data.)50
+b(The)33 b(sp)s(eci\014ed)f(column)h(\(and)227 5375 y(ro)m(w\))e(will)h
+(b)s(e)e(created)h(if)g(it)g(do)s(es)g(not)g(already)g(exist.)43
+b(The)30 b('cop)m(yk)m(ey\015ag')j(parameter)e(con)m(trols)h(whic)m(h)
+227 5488 y(k)m(eyw)m(ords)26 b(are)g(copied)g(from)f(the)g(input)g
+(image)h(to)g(the)g(header)f(of)h(the)f(output)g(table:)39
+b(0)26 b(=)f(no)h(k)m(eyw)m(ords)227 5601 y(will)k(b)s(e)g(copied,)g(1)
+h(=)e(all)i(k)m(eyw)m(ords)f(will)g(b)s(e)f(copied)h(\(except)i(those)e
+(k)m(eyw)m(ords)g(that)h(w)m(ould)e(b)s(e)g(in)m(v)-5
+b(alid)227 5714 y(in)30 b(the)h(table)g(header\),)g(and)f(2)g(=)g(cop)m
+(y)i(only)e(the)h(W)m(CS)f(k)m(eyw)m(ords.)p eop end
+%%Page: 42 50
+TeXDict begin 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)95 555 y Fe(int)47 b(fits_copy_cell2image)286
+668 y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(char)i(*colname,)e
+(long)i(rownum,)334 781 y(>)h(int)e(*status\))95 1007
+y(int)h(fits_copy_image2cell)286 1120 y(\(fitsfile)f(*infptr,)f
+(fitsfile)h(*outfptr,)f(char)i(*colname,)e(long)i(rownum,)334
+1233 y(int)g(copykeyflag)e(>)i(int)g(*status\))0 1474
+y Fi(5)81 b Fj(W)-8 b(rite)40 b(a)f(rectangular)g(subimage)g(\(or)g
+(the)g(whole)g(image\))h(to)f(the)g(FITS)f(data)h(arra)m(y)-8
+b(.)67 b(The)38 b(fpixel)h(and)227 1587 y(lpixel)30 b(arra)m(ys)g(giv)m
+(e)h(the)f(co)s(ordinates)g(of)f(the)h(\014rst)f(\(lo)m(w)m(er)i(left)f
+(corner\))g(and)f(last)h(\(upp)s(er)e(righ)m(t)i(corner\))227
+1700 y(pixels)h(in)f(FITS)g(image)h(to)g(b)s(e)f(written)g(to.)95
+1941 y Fe(int)47 b(fits_write_subset)c(/)48 b(ffpss)286
+2054 y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(long)i(*fpixel,)e(long)i
+(*lpixel,)334 2167 y(DTYPE)f(*array,)g(>)i(int)f(*status\))0
+2408 y Fi(6)81 b Fj(W)-8 b(rite)39 b(pixels)g(in)m(to)g(the)g(FITS)f
+(data)h(arra)m(y)-8 b(.)66 b('fpixel')39 b(is)f(an)g(arra)m(y)h(of)g
+(length)g(NAXIS)f(whic)m(h)g(giv)m(es)i(the)227 2521
+y(co)s(ordinate)k(of)f(the)g(starting)g(pixel)g(to)h(b)s(e)e(written)h
+(to,)j(suc)m(h)d(that)g(fpixel[0])h(is)f(in)f(the)h(range)g(1)g(to)227
+2634 y(NAXIS1,)34 b(fpixel[1])f(is)g(in)f(the)g(range)h(1)g(to)g
+(NAXIS2,)g(etc.)48 b(The)32 b(\014rst)g(pair)g(of)h(routines)f(simply)g
+(writes)227 2747 y(the)40 b(arra)m(y)g(of)g(pixels)f(to)i(the)e(FITS)g
+(\014le)h(\(doing)g(data)g(t)m(yp)s(e)g(con)m(v)m(ersion)h(if)e
+(necessary\))h(whereas)g(the)227 2860 y(second)c(routines)g(will)g
+(substitute)f(the)h(appropriate)g(FITS)f(n)m(ull)g(v)-5
+b(alue)37 b(for)e(an)m(y)h(elemen)m(ts)h(whic)m(h)f(are)227
+2973 y(equal)41 b(to)g(the)f(input)g(v)-5 b(alue)40 b(of)h(n)m(ulv)-5
+b(al)40 b(\(note)h(that)g(this)f(parameter)h(giv)m(es)h(the)e(address)f
+(of)i(the)f(n)m(ull)227 3086 y(v)-5 b(alue,)36 b(not)f(the)f(n)m(ull)g
+(v)-5 b(alue)35 b(itself)7 b(\).)53 b(F)-8 b(or)35 b(in)m(teger)h(FITS)
+d(arra)m(ys,)j(the)f(FITS)e(n)m(ull)h(v)-5 b(alue)35
+b(is)f(de\014ned)f(b)m(y)227 3199 y(the)26 b(BLANK)f(k)m(eyw)m(ord)h
+(\(an)g(error)f(is)g(returned)f(if)i(the)f(BLANK)h(k)m(eyw)m(ord)g(do)s
+(esn't)f(exist\).)40 b(F)-8 b(or)26 b(\015oating)227
+3312 y(p)s(oin)m(t)g(FITS)f(arra)m(ys)h(the)g(sp)s(ecial)g(IEEE)f(NaN)i
+(\(Not-a-Num)m(b)s(er\))g(v)-5 b(alue)26 b(will)g(b)s(e)f(written)h(in)
+m(to)h(the)f(FITS)227 3425 y(\014le.)66 b(If)38 b(a)h(n)m(ull)f(p)s
+(oin)m(ter)h(is)f(en)m(tered)h(for)g(n)m(ulv)-5 b(al,)41
+b(then)d(the)h(n)m(ull)f(v)-5 b(alue)39 b(is)g(ignored)g(and)e(this)i
+(routine)227 3537 y(b)s(eha)m(v)m(es)31 b(the)g(same)g(as)f(\014ts)p
+1189 3537 28 4 v 33 w(write)p 1424 3537 V 33 w(pix.)95
+3779 y Fe(int)47 b(fits_write_pix)d(/)k(ffppx)286 3892
+y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(long)i(*fpixel,)e(LONGLONG)h
+(nelements,)334 4005 y(DTYPE)g(*array,)g(int)h(*status\);)95
+4231 y(int)g(fits_write_pixll)d(/)j(ffppxll)286 4343
+y(\(fitsfile)f(*fptr,)g(int)h(datatype,)e(LONGLONG)g(*fpixel,)h
+(LONGLONG)g(nelements,)334 4456 y(DTYPE)g(*array,)g(int)h(*status\);)95
+4682 y(int)g(fits_write_pixnull)c(/)48 b(ffppxn)286 4795
+y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(long)i(*fpixel,)e(LONGLONG)h
+(nelements,)334 4908 y(DTYPE)g(*array,)g(DTYPE)h(*nulval,)e(>)j(int)f
+(*status\);)95 5134 y(int)g(fits_write_pixnullll)c(/)k(ffppxnll)286
+5247 y(\(fitsfile)f(*fptr,)g(int)h(datatype,)e(LONGLONG)g(*fpixel,)h
+(LONGLONG)g(nelements,)334 5360 y(DTYPE)g(*array,)g(DTYPE)h(*nulval,)e
+(>)j(int)f(*status\);)0 5601 y Fi(7)81 b Fj(Set)24 b(FITS)g(data)i
+(arra)m(y)f(elemen)m(ts)h(equal)f(to)g(the)g(appropriate)f(n)m(ull)h
+(pixel)g(v)-5 b(alue.)39 b(F)-8 b(or)25 b(in)m(teger)h(FITS)e(arra)m
+(ys,)227 5714 y(the)34 b(FITS)e(n)m(ull)h(v)-5 b(alue)34
+b(is)f(de\014ned)f(b)m(y)h(the)h(BLANK)f(k)m(eyw)m(ord)h(\(an)f(error)g
+(is)g(returned)f(if)h(the)h(BLANK)p eop end
+%%Page: 43 51
+TeXDict begin 43 50 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(43)227 555 y(k)m(eyw)m(ord)23 b(do)s(esn't)g
+(exist\).)39 b(F)-8 b(or)23 b(\015oating)g(p)s(oin)m(t)g(FITS)f(arra)m
+(ys)g(the)h(sp)s(ecial)g(IEEE)f(NaN)h(\(Not-a-Num)m(b)s(er\))227
+668 y(v)-5 b(alue)34 b(will)f(b)s(e)g(written)g(in)m(to)h(the)g(FITS)e
+(\014le.)49 b(Note)34 b(that)g('\014rstelem')g(is)f(a)h(scalar)g
+(giving)g(the)f(o\013set)h(to)227 781 y(the)d(\014rst)e(pixel)i(to)g(b)
+s(e)f(written)g(in)h(the)f(equiv)-5 b(alen)m(t)32 b(1-dimensional)f
+(arra)m(y)g(of)g(image)g(pixels.)95 1034 y Fe(int)47
+b(fits_write_null_img)c(/)k(ffpprn)286 1147 y(\(fitsfile)f(*fptr,)g
+(LONGLONG)f(firstelem,)g(LONGLONG)h(nelements,)f(>)i(int)g(*status\))0
+1399 y Fi(8)81 b Fj(Read)33 b(a)h(rectangular)h(subimage)f(\(or)g(the)g
+(whole)g(image\))h(from)e(the)h(FITS)f(data)h(arra)m(y)-8
+b(.)52 b(The)33 b(fpixel)h(and)227 1512 y(lpixel)c(arra)m(ys)g(giv)m(e)
+h(the)f(co)s(ordinates)g(of)f(the)h(\014rst)f(\(lo)m(w)m(er)i(left)f
+(corner\))g(and)f(last)h(\(upp)s(er)e(righ)m(t)i(corner\))227
+1625 y(pixels)d(to)h(b)s(e)e(read)h(from)g(the)g(FITS)f(image.)41
+b(Unde\014ned)25 b(FITS)h(arra)m(y)i(elemen)m(ts)g(will)f(b)s(e)f
+(returned)g(with)227 1738 y(a)k(v)-5 b(alue)30 b(=)e(*n)m(ullv)-5
+b(al,)31 b(\(note)f(that)g(this)f(parameter)h(giv)m(es)g(the)g(address)
+e(of)h(the)h(n)m(ull)f(v)-5 b(alue,)30 b(not)g(the)f(n)m(ull)227
+1851 y(v)-5 b(alue)36 b(itself)7 b(\))37 b(unless)e(n)m(ulv)-5
+b(al)36 b(=)g(0)g(or)f(*n)m(ulv)-5 b(al)37 b(=)e(0,)j(in)d(whic)m(h)g
+(case)i(no)f(c)m(hec)m(ks)h(for)e(unde\014ned)f(pixels)227
+1964 y(will)d(b)s(e)f(p)s(erformed.)95 2216 y Fe(int)47
+b(fits_read_subset)d(/)j(ffgsv)286 2329 y(\(fitsfile)f(*fptr,)g(int)94
+b(datatype,)46 b(long)g(*fpixel,)g(long)g(*lpixel,)g(long)h(*inc,)334
+2442 y(DTYPE)f(*nulval,)g(>)h(DTYPE)g(*array,)f(int)h(*anynul,)e(int)i
+(*status\))0 2695 y Fi(9)81 b Fj(Read)32 b(pixels)h(from)f(the)g(FITS)g
+(data)h(arra)m(y)-8 b(.)48 b('fpixel')33 b(is)g(the)f(starting)h(pixel)
+g(lo)s(cation)h(and)e(is)h(an)f(arra)m(y)h(of)227 2808
+y(length)h(NAXIS)f(suc)m(h)g(that)h(fpixel[0])g(is)f(in)g(the)h(range)f
+(1)h(to)g(NAXIS1,)g(fpixel[1])g(is)g(in)f(the)g(range)h(1)f(to)227
+2921 y(NAXIS2,)c(etc.)41 b(The)28 b(nelemen)m(ts)h(parameter)f(sp)s
+(eci\014es)g(the)g(n)m(um)m(b)s(er)f(of)h(pixels)h(to)g(read.)39
+b(If)28 b(fpixel)g(is)g(set)227 3034 y(to)36 b(the)f(\014rst)f(pixel,)j
+(and)e(nelemen)m(ts)g(is)g(set)h(equal)g(to)f(the)g(NAXIS1)h(v)-5
+b(alue,)37 b(then)d(this)h(routine)g(w)m(ould)227 3147
+y(read)28 b(the)g(\014rst)f(ro)m(w)h(of)g(the)h(image.)41
+b(Alternativ)m(ely)-8 b(,)31 b(if)d(nelemen)m(ts)h(is)f(set)g(equal)h
+(to)f(NAXIS1)g(*)h(NAXIS2)227 3260 y(then)h(it)h(w)m(ould)f(read)h(an)f
+(en)m(tire)h(2D)g(image,)h(or)f(the)f(\014rst)g(plane)g(of)h(a)g(3-D)g
+(datacub)s(e.)227 3409 y(The)38 b(\014rst)g(2)h(routines)f(will)h
+(return)f(an)m(y)h(unde\014ned)d(pixels)j(in)f(the)h(FITS)e(arra)m(y)i
+(equal)g(to)h(the)e(v)-5 b(alue)227 3522 y(of)36 b(*n)m(ullv)-5
+b(al)36 b(\(note)g(that)g(this)f(parameter)h(giv)m(es)g(the)g(address)e
+(of)i(the)f(n)m(ull)g(v)-5 b(alue,)37 b(not)f(the)f(n)m(ull)g(v)-5
+b(alue)227 3634 y(itself)7 b(\))34 b(unless)d(n)m(ulv)-5
+b(al)32 b(=)g(0)g(or)h(*n)m(ulv)-5 b(al)32 b(=)g(0,)h(in)f(whic)m(h)g
+(case)h(no)f(c)m(hec)m(ks)h(for)f(unde\014ned)e(pixels)i(will)h(b)s(e)
+227 3747 y(p)s(erformed.)42 b(The)31 b(second)h(2)f(routines)h(are)f
+(similar)h(except)g(that)g(an)m(y)g(unde\014ned)d(pixels)i(will)h(ha)m
+(v)m(e)h(the)227 3860 y(corresp)s(onding)d(n)m(ullarra)m(y)g(elemen)m
+(t)i(set)f(equal)g(to)g(TR)m(UE)g(\(=)f(1\).)95 4113
+y Fe(int)47 b(fits_read_pix)e(/)i(ffgpxv)286 4226 y(\(fitsfile)f
+(*fptr,)g(int)94 b(datatype,)46 b(long)g(*fpixel,)g(LONGLONG)f
+(nelements,)334 4339 y(DTYPE)h(*nulval,)g(>)h(DTYPE)g(*array,)f(int)h
+(*anynul,)e(int)i(*status\))95 4565 y(int)g(fits_read_pixll)d(/)j
+(ffgpxvll)286 4677 y(\(fitsfile)f(*fptr,)g(int)94 b(datatype,)46
+b(LONGLONG)f(*fpixel,)h(LONGLONG)f(nelements,)334 4790
+y(DTYPE)h(*nulval,)g(>)h(DTYPE)g(*array,)f(int)h(*anynul,)e(int)i
+(*status\))95 5016 y(int)g(fits_read_pixnull)c(/)48 b(ffgpxf)286
+5129 y(\(fitsfile)e(*fptr,)g(int)94 b(datatype,)46 b(long)g(*fpixel,)g
+(LONGLONG)f(nelements,)334 5242 y(>)j(DTYPE)e(*array,)g(char)g
+(*nullarray,)f(int)i(*anynul,)f(int)g(*status\))95 5468
+y(int)h(fits_read_pixnullll)c(/)k(ffgpxfll)286 5581 y(\(fitsfile)f
+(*fptr,)g(int)94 b(datatype,)46 b(LONGLONG)f(*fpixel,)h(LONGLONG)f
+(nelements,)334 5694 y(>)j(DTYPE)e(*array,)g(char)g(*nullarray,)f(int)i
+(*anynul,)f(int)g(*status\))p eop end
+%%Page: 44 52
+TeXDict begin 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)0 555 y Fi(10)46 b Fj(Cop)m(y)36 b(a)g(rectangular)h
+(section)g(of)g(an)e(image)j(and)d(write)h(it)h(to)f(a)h(new)e(FITS)g
+(primary)g(image)j(or)e(image)227 668 y(extension.)49
+b(The)32 b(new)g(image)i(HDU)g(is)e(app)s(ended)f(to)j(the)f(end)f(of)h
+(the)g(output)f(\014le;)i(all)g(the)f(k)m(eyw)m(ords)227
+781 y(in)39 b(the)f(input)g(image)i(will)f(b)s(e)f(copied)h(to)g(the)g
+(output)f(image.)66 b(The)38 b(common)h(W)m(CS)g(k)m(eyw)m(ords)g(will)
+227 894 y(b)s(e)34 b(up)s(dated)f(if)i(necessary)g(to)g(corresp)s(ond)e
+(to)j(the)e(co)s(ordinates)h(of)g(the)g(section.)54 b(The)34
+b(format)h(of)g(the)227 1007 y(section)29 b(expression)e(is)g(same)g
+(as)h(sp)s(ecifying)f(an)g(image)h(section)h(using)d(the)i(extended)f
+(\014le)g(name)g(syn)m(tax)227 1120 y(\(see)32 b("Image)f(Section")h
+(in)e(Chapter)g(10\).)42 b(\(Examples:)f("1:100,1:200",)36
+b("1:100:2,)d(1:*:2",)g("*,)f(-*"\).)95 1405 y Fe(int)47
+b(fits_copy_image_section)42 b(/)47 b(ffcpimg)286 1518
+y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(char)i(*section,)e
+(int)i(*status\))0 1881 y Ff(5.6)135 b(Image)46 b(Compression)0
+2138 y Fj(CFITSIO)29 b(transparen)m(tly)h(supp)s(orts)f(the)h(2)h
+(metho)s(ds)f(of)g(image)i(compression)e(describ)s(ed)g(b)s(elo)m(w.)0
+2298 y(1\))45 b(The)f(en)m(tire)i(FITS)e(\014le)h(ma)m(y)g(b)s(e)f
+(externally)i(compressed)e(with)g(the)h(gzip)g(or)g(Unix)f(compress)h
+(utilit)m(y)0 2411 y(programs,)37 b(pro)s(ducing)d(a)j(*.gz)g(or)f(*.Z)
+g(\014le,)h(resp)s(ectiv)m(ely)-8 b(.)59 b(When)36 b(reading)g
+(compressed)f(\014les)h(of)g(this)g(t)m(yp)s(e,)0 2524
+y(CFITSIO)43 b(\014rst)h(uncompresses)f(the)i(en)m(tire)g(\014le)g(in)m
+(to)g(memory)g(b)s(efore)f(p)s(erforming)f(the)i(requested)f(read)0
+2636 y(op)s(erations.)c(Output)28 b(\014les)g(can)h(b)s(e)f(directly)i
+(written)e(in)g(the)h(gzip)g(compressed)g(format)g(if)f(the)h(user-sp)s
+(eci\014ed)0 2749 y(\014lename)35 b(ends)e(with)i(`.gz'.)54
+b(In)34 b(this)g(case,)j(CFITSIO)c(initially)j(writes)e(the)h
+(uncompressed)e(\014le)i(in)f(memory)0 2862 y(and)j(then)g(compresses)g
+(it)h(and)f(writes)g(it)h(to)g(disk)f(when)f(the)i(FITS)f(\014le)g(is)g
+(closed,)k(th)m(us)36 b(sa)m(ving)j(user)d(disk)0 2975
+y(space.)59 b(Read)36 b(and)g(write)h(access)g(to)g(these)g(compressed)
+f(FITS)g(\014les)g(is)g(generally)i(quite)e(fast)h(since)g(all)g(the)0
+3088 y(I/O)28 b(is)g(p)s(erformed)e(in)i(memory;)h(the)f(main)g
+(limitation)i(with)e(this)f(tec)m(hnique)i(is)f(that)h(there)f(m)m(ust)
+g(b)s(e)f(enough)0 3201 y(a)m(v)-5 b(ailable)33 b(memory)d(\(or)h(sw)m
+(ap)f(space\))h(to)g(hold)f(the)h(en)m(tire)g(uncompressed)e(FITS)h
+(\014le.)0 3361 y(2\))42 b(CFITSIO)d(also)j(supp)s(orts)d(the)j(FITS)e
+(tiled)h(image)i(compression)e(con)m(v)m(en)m(tion)i(in)e(whic)m(h)f
+(the)i(image)g(is)0 3474 y(sub)s(divided)30 b(in)m(to)j(a)f(grid)g(of)g
+(rectangular)i(tiles,)f(and)f(eac)m(h)h(tile)g(of)g(pixels)f(is)g
+(individually)g(compressed.)45 b(The)0 3587 y(details)33
+b(of)f(this)g(FITS)f(compression)h(con)m(v)m(en)m(tion)j(are)d(describ)
+s(ed)f(at)i(the)f(FITS)f(Supp)s(ort)f(O\016ce)i(w)m(eb)g(site)h(at)0
+3700 y(h)m(ttp://\014ts.gsfc.nasa.go)m(v/\014ts)p 1114
+3700 28 4 v 37 w(registry)-8 b(.h)m(tml)33 b(Basically)-8
+b(,)35 b(the)d(compressed)g(image)h(tiles)f(are)h(stored)e(in)h(ro)m
+(ws)0 3813 y(of)i(a)h(v)-5 b(ariable)35 b(length)f(arra)m(y)h(column)f
+(in)f(a)i(FITS)e(binary)g(table,)k(ho)m(w)m(ev)m(er)e(CFITSIO)e
+(recognizes)i(that)g(this)0 3926 y(binary)i(table)i(extension)f(con)m
+(tains)h(an)e(image)i(and)e(treats)i(it)f(as)g(if)g(it)g(w)m(ere)g(an)g
+(IMA)m(GE)g(extension.)64 b(This)0 4039 y(tile-compressed)37
+b(format)f(is)f(esp)s(ecially)i(w)m(ell)g(suited)e(for)h(compressing)f
+(v)m(ery)h(large)h(images)g(b)s(ecause)e(a\))i(the)0
+4152 y(FITS)28 b(header)h(k)m(eyw)m(ords)h(remain)f(uncompressed)e(for)
+i(rapid)g(read)g(access,)h(and)f(b)s(ecause)g(b\))g(it)g(is)h(p)s
+(ossible)e(to)0 4264 y(extract)f(and)e(uncompress)g(sections)i(of)f
+(the)g(image)h(without)e(ha)m(ving)i(to)f(uncompress)f(the)h(en)m(tire)
+g(image.)41 b(This)0 4377 y(format)34 b(is)g(also)h(m)m(uc)m(h)e(more)h
+(e\013ectiv)m(e)j(in)c(compressing)h(\015oating)h(p)s(oin)m(t)e(images)
+i(than)f(simply)f(compressing)0 4490 y(the)39 b(image)i(using)d(gzip)i
+(or)f(compress)g(b)s(ecause)g(it)h(appro)m(ximates)g(the)g(\015oating)g
+(p)s(oin)m(t)f(v)-5 b(alues)39 b(with)g(scaled)0 4603
+y(in)m(tegers)32 b(whic)m(h)e(can)g(then)g(b)s(e)g(compressed)g(more)h
+(e\016cien)m(tly)-8 b(.)0 4763 y(Curren)m(tly)41 b(CFITSIO)e(supp)s
+(orts)h(3)h(general)i(purp)s(ose)c(compression)i(algorithms)i(plus)d
+(one)i(other)f(sp)s(ecial-)0 4876 y(purp)s(ose)31 b(compression)i(tec)m
+(hnique)h(that)f(is)g(designed)g(for)g(data)g(masks)g(with)g(p)s
+(ositiv)m(e)h(in)m(teger)g(pixel)f(v)-5 b(alues.)0 4989
+y(The)40 b(3)g(general)h(purp)s(ose)e(algorithms)i(are)f(GZIP)-8
+b(,)41 b(Rice,)j(and)39 b(HCOMPRESS,)g(and)h(the)g(sp)s(ecial)h(purp)s
+(ose)0 5102 y(algorithm)32 b(is)g(the)f(IRAF)h(pixel)f(list)h
+(compression)f(tec)m(hnique)h(\(PLIO\).)g(In)e(principle,)i(an)m(y)f(n)
+m(um)m(b)s(er)f(of)i(other)0 5215 y(compression)e(algorithms)i(could)e
+(also)h(b)s(e)f(supp)s(orted)f(b)m(y)h(the)g(FITS)g(tiled)h(image)h
+(compression)e(con)m(v)m(en)m(tion.)0 5375 y(The)35 b(FITS)g(image)h
+(can)g(b)s(e)f(sub)s(divided)e(in)m(to)k(an)m(y)f(desired)f
+(rectangular)h(grid)f(of)h(compression)f(tiles.)57 b(With)0
+5488 y(the)32 b(GZIP)-8 b(,)33 b(Rice,)h(and)e(PLIO)f(algorithms,)j
+(the)e(default)h(is)f(to)h(tak)m(e)h(eac)m(h)g(ro)m(w)e(of)h(the)f
+(image)i(as)e(a)h(tile.)47 b(The)0 5601 y(HCOMPRESS)25
+b(algorithm)i(is)g(inheren)m(tly)f(2-dimensional)h(in)f(nature,)i(so)e
+(the)h(default)f(in)g(this)g(case)i(is)e(to)h(tak)m(e)0
+5714 y(16)h(ro)m(ws)g(of)f(the)h(image)h(p)s(er)d(tile.)41
+b(In)27 b(most)h(cases)g(it)g(mak)m(es)h(little)g(di\013erence)f(what)f
+(tiling)i(pattern)f(is)f(used,)h(so)p eop end
+%%Page: 45 53
+TeXDict begin 45 52 bop 0 299 a Fh(5.6.)72 b(IMA)m(GE)31
+b(COMPRESSION)2567 b Fj(45)0 555 y(the)33 b(default)g(tiles)g(are)g
+(usually)g(adequate.)48 b(In)32 b(the)h(case)g(of)g(v)m(ery)g(small)g
+(images,)i(it)e(could)g(b)s(e)f(more)g(e\016cien)m(t)0
+668 y(to)h(compress)f(the)h(whole)f(image)i(as)e(a)h(single)g(tile.)48
+b(Note)34 b(that)f(the)f(image)i(dimensions)d(are)i(not)g(required)e
+(to)0 781 y(b)s(e)d(an)g(in)m(teger)i(m)m(ultiple)f(of)f(the)h(tile)g
+(dimensions;)g(if)f(not,)i(then)e(the)g(tiles)i(at)f(the)f(edges)h(of)g
+(the)f(image)i(will)f(b)s(e)0 894 y(smaller)i(than)f(the)h(other)f
+(tiles.)0 1054 y(The)41 b(4)g(supp)s(orted)f(image)i(compression)f
+(algorithms)h(are)g(all)g('loss-less')h(when)d(applied)h(to)h(in)m
+(teger)h(FITS)0 1167 y(images;)25 b(the)c(pixel)g(v)-5
+b(alues)20 b(are)h(preserv)m(ed)f(exactly)j(with)d(no)g(loss)h(of)f
+(information)h(during)e(the)i(compression)g(and)0 1280
+y(uncompression)34 b(pro)s(cess.)54 b(In)34 b(addition,)j(the)e
+(HCOMPRESS)f(algorithm)i(supp)s(orts)d(a)i('lossy')h(compression)0
+1393 y(mo)s(de)41 b(that)h(will)g(pro)s(duce)f(larger)h(amoun)m(t)g(of)
+g(image)h(compression.)74 b(This)41 b(is)g(ac)m(hiev)m(ed)j(b)m(y)d(sp)
+s(ecifying)h(a)0 1506 y(non-zero)32 b(v)-5 b(alue)32
+b(for)f(the)g(HCOMPRESS)f(\\scale")k(parameter.)44 b(Since)31
+b(the)g(amoun)m(t)h(of)g(compression)f(that)h(is)0 1619
+y(ac)m(hiev)m(ed)g(dep)s(ends)d(directly)i(on)f(the)h(RMS)f(noise)h(in)
+f(the)h(image,)h(it)f(is)g(usually)f(more)g(con)m(v)m(en)m(tion)j(to)e
+(sp)s(ecify)0 1732 y(the)f(HCOMPRESS)e(scale)i(factor)h(relativ)m(e)g
+(to)f(the)g(RMS)f(noise.)41 b(Setting)30 b(s)f(=)g(2.5)i(means)e(use)g
+(a)h(scale)h(factor)0 1844 y(that)h(is)f(2.5)i(times)e(the)h
+(calculated)h(RMS)e(noise)h(in)f(the)g(image)i(tile.)44
+b(In)31 b(some)g(cases)h(it)g(ma)m(y)g(b)s(e)f(desirable)g(to)0
+1957 y(sp)s(ecify)h(the)g(exact)i(scaling)f(to)g(b)s(e)e(used,)h
+(instead)h(of)f(sp)s(ecifying)g(it)g(relativ)m(e)j(to)d(the)h
+(calculated)h(noise)e(v)-5 b(alue.)0 2070 y(This)37 b(ma)m(y)h(b)s(e)f
+(done)g(b)m(y)h(sp)s(ecifying)f(the)h(negativ)m(e)i(of)d(desired)g
+(scale)i(v)-5 b(alue)38 b(\(t)m(ypically)i(in)d(the)h(range)g(-2)g(to)0
+2183 y(-100\).)0 2343 y(V)-8 b(ery)43 b(high)g(compression)f(factors)i
+(\(of)f(100)h(or)f(more\))g(can)g(b)s(e)f(ac)m(hiev)m(ed)j(b)m(y)d
+(using)h(large)g(HCOMPRESS)0 2456 y(scale)31 b(v)-5 b(alues,)31
+b(ho)m(w)m(ev)m(er,)h(this)e(can)g(pro)s(duce)f(undesirable)g(\\blo)s
+(c)m(ky")j(artifacts)f(in)f(the)g(compressed)g(image.)42
+b(A)0 2569 y(v)-5 b(ariation)27 b(of)g(the)f(HCOMPRESS)f(algorithm)i
+(\(called)h(HSCOMPRESS\))c(can)i(b)s(e)g(used)f(in)h(this)g(case)h(to)g
+(apply)0 2682 y(a)f(small)h(amoun)m(t)f(of)h(smo)s(othing)f(of)g(the)g
+(image)h(when)e(it)i(is)f(uncompressed)f(to)h(help)g(co)m(v)m(er)i(up)d
+(these)h(artifacts.)0 2795 y(This)36 b(smo)s(othing)h(is)g(purely)f
+(cosmetic)j(and)d(do)s(es)h(not)g(cause)g(an)m(y)h(signi\014can)m(t)g
+(c)m(hange)g(to)f(the)g(image)i(pixel)0 2908 y(v)-5 b(alues.)0
+3068 y(Floating)34 b(p)s(oin)m(t)f(FITS)e(images)j(\(whic)m(h)e(ha)m(v)
+m(e)i(BITPIX)e(=)g(-32)h(or)g(-64\))g(usually)f(con)m(tain)i(to)s(o)f
+(m)m(uc)m(h)g(\\noise")0 3181 y(in)k(the)g(least)i(signi\014can)m(t)f
+(bits)f(of)h(the)f(man)m(tissa)h(of)g(the)f(pixel)h(v)-5
+b(alues)37 b(to)h(b)s(e)f(e\013ectiv)m(ely)j(compressed)d(with)0
+3294 y(an)m(y)d(lossless)g(algorithm.)52 b(Consequen)m(tly)-8
+b(,)35 b(\015oating)g(p)s(oin)m(t)e(images)i(are)f(\014rst)f(quan)m
+(tized)h(in)m(to)h(scaled)g(in)m(teger)0 3407 y(pixel)26
+b(v)-5 b(alues)25 b(\(and)g(th)m(us)g(thro)m(wing)h(a)m(w)m(a)m(y)h(m)m
+(uc)m(h)e(of)h(the)f(noise\))h(b)s(efore)f(b)s(eing)g(compressed)g
+(with)g(the)h(sp)s(eci\014ed)0 3520 y(algorithm)d(\(either)g(GZIP)-8
+b(,)23 b(Rice,)i(or)d(HCOMPRESS\).)f(This)h(tec)m(hnique)h(pro)s(duces)
+e(m)m(uc)m(h)h(higher)g(compression)0 3633 y(factors)33
+b(than)e(simply)g(using)g(the)h(GZIP)g(utilit)m(y)h(to)f(externally)h
+(compress)f(the)f(whole)h(FITS)f(\014le,)i(but)e(it)h(also)0
+3745 y(means)d(that)h(the)g(original)g(\015oating)g(v)-5
+b(alue)30 b(pixel)f(v)-5 b(alues)30 b(are)g(not)f(exactly)i(preserv)m
+(ed.)40 b(When)29 b(done)g(prop)s(erly)-8 b(,)0 3858
+y(this)33 b(in)m(teger)h(scaling)f(tec)m(hnique)h(will)f(only)f
+(discard)h(the)f(insigni\014can)m(t)i(noise)f(while)g(still)g
+(preserving)f(all)i(the)0 3971 y(real)43 b(information)f(in)g(the)h
+(image.)77 b(The)42 b(amoun)m(t)g(of)h(precision)f(that)h(is)f
+(retained)h(in)e(the)i(pixel)f(v)-5 b(alues)43 b(is)0
+4084 y(con)m(trolled)37 b(b)m(y)d(the)i("quan)m(tization)h(lev)m(el")g
+(parameter,)g(q.)54 b(Larger)35 b(v)-5 b(alues)36 b(of)f(q)f(will)i
+(result)f(in)f(compressed)0 4197 y(images)h(whose)e(pixels)h(more)f
+(closely)i(matc)m(h)g(the)e(\015oating)i(p)s(oin)m(t)e(pixel)h(v)-5
+b(alues,)35 b(but)e(at)h(the)g(same)g(time)g(the)0 4310
+y(amoun)m(t)j(of)f(compression)g(that)h(is)f(ac)m(hiev)m(ed)i(will)f(b)
+s(e)e(reduced.)58 b(Users)36 b(should)f(exp)s(erimen)m(t)i(with)e
+(di\013eren)m(t)0 4423 y(v)-5 b(alues)25 b(for)g(this)g(parameter)g(to)
+h(determine)f(the)g(optimal)h(v)-5 b(alue)25 b(that)h(preserv)m(es)f
+(all)h(the)f(useful)f(information)h(in)0 4536 y(the)k(image,)h(without)
+f(needlessly)g(preserving)f(all)h(the)g(\\noise")h(whic)m(h)e(will)h(h)
+m(urt)f(the)h(compression)f(e\016ciency)-8 b(.)0 4696
+y(The)38 b(default)g(v)-5 b(alue)38 b(for)g(the)g(quan)m(tization)i
+(scale)g(factor)f(is)f(16.,)j(whic)m(h)d(means)g(that)g(scaled)h(in)m
+(teger)h(pixel)0 4809 y(v)-5 b(alues)38 b(will)g(b)s(e)g(quan)m(tized)g
+(suc)m(h)g(that)g(the)g(di\013erence)h(b)s(et)m(w)m(een)f(adjacen)m(t)h
+(in)m(teger)h(v)-5 b(alues)38 b(will)g(b)s(e)f(1/16th)0
+4922 y(of)e(the)h(noise)f(lev)m(el)i(in)e(the)g(image)h(bac)m(kground.)
+55 b(CFITSIO)34 b(uses)g(an)h(optimized)h(algorithm)g(to)g(accurately)0
+5035 y(estimate)41 b(the)e(noise)h(in)f(the)g(image.)68
+b(As)39 b(an)g(example,)k(if)c(the)g(RMS)g(noise)g(in)g(the)h(bac)m
+(kground)e(pixels)i(of)0 5148 y(an)35 b(image)h(=)f(32.0,)j(then)d(the)
+h(spacing)f(b)s(et)m(w)m(een)h(adjacen)m(t)g(scaled)g(in)m(teger)h
+(pixel)e(v)-5 b(alues)36 b(will)f(equal)h(2.0)g(b)m(y)0
+5261 y(default.)63 b(Note)38 b(that)h(the)e(RMS)h(noise)g(is)f(indep)s
+(enden)m(tly)g(calculated)j(for)d(eac)m(h)i(tile)f(of)g(the)g(image,)j
+(so)d(the)0 5373 y(resulting)24 b(in)m(teger)i(scaling)f(factor)g(ma)m
+(y)g(\015uctuate)g(sligh)m(tly)g(for)f(eac)m(h)i(tile.)40
+b(In)23 b(some)i(cases)g(it)f(ma)m(y)h(b)s(e)f(desirable)0
+5486 y(to)29 b(sp)s(ecify)f(the)h(exact)h(quan)m(tization)h(lev)m(el)f
+(to)f(b)s(e)f(used,)g(instead)h(of)g(sp)s(ecifying)f(it)h(relativ)m(e)i
+(to)e(the)g(calculated)0 5599 y(noise)42 b(v)-5 b(alue.)73
+b(This)40 b(ma)m(y)i(b)s(e)f(done)f(b)m(y)h(sp)s(ecifying)g(the)h
+(negativ)m(e)h(of)e(desired)g(quan)m(tization)i(lev)m(el)g(for)e(the)0
+5712 y(v)-5 b(alue)29 b(of)h(q.)40 b(In)28 b(the)h(previous)g(example,)
+h(one)f(could)g(sp)s(ecify)g(q)f(=)h(-2.0)h(so)g(that)f(the)g(quan)m
+(tized)h(in)m(teger)g(lev)m(els)p eop end
+%%Page: 46 54
+TeXDict begin 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)0 555 y Fj(di\013er)f(b)m(y)g(2.0.)42 b(Larger)29
+b(negativ)m(e)j(v)-5 b(alues)29 b(for)h(q)f(means)g(that)h(the)f(lev)m
+(els)i(are)f(more)f(coarsely)i(spaced,)f(and)f(will)0
+668 y(pro)s(duce)g(higher)h(compression)h(factors.)0
+828 y(There)37 b(are)g(2)h(metho)s(ds)e(for)h(sp)s(ecifying)g(all)h
+(the)g(parameters)f(needed)g(to)h(write)f(a)h(FITS)e(image)j(in)d(the)i
+(tile)0 941 y(compressed)c(format.)53 b(The)34 b(parameters)h(ma)m(y)g
+(either)g(b)s(e)e(sp)s(eci\014ed)h(at)h(run)e(time)i(as)g(part)f(of)h
+(the)f(\014le)h(name)0 1054 y(of)41 b(the)g(output)f(compressed)g(FITS)
+g(\014le,)k(or)c(the)h(writing)g(program)f(ma)m(y)i(call)g(a)f(set)g
+(of)g(help)s(er)e(CFITSIO)0 1167 y(subroutines)29 b(that)i(are)g(pro)m
+(vided)f(for)g(sp)s(ecifying)g(the)h(parameter)g(v)-5
+b(alues,)31 b(as)f(describ)s(ed)f(b)s(elo)m(w:)0 1327
+y(1\))23 b(A)m(t)g(run)e(time,)k(when)c(sp)s(ecifying)h(the)h(name)f
+(of)g(the)h(output)f(FITS)f(\014le)i(to)g(b)s(e)e(created,)k(the)e
+(user)e(can)i(indicate)0 1440 y(that)32 b(images)g(should)e(b)s(e)h
+(written)g(in)g(tile-compressed)i(format)e(b)m(y)h(enclosing)g(the)f
+(compression)h(parameters)0 1553 y(in)e(square)g(brac)m(k)m(ets)i
+(follo)m(wing)g(the)e(ro)s(ot)h(disk)f(\014le)g(name)h(in)f(the)h
+(follo)m(wing)g(format:)191 1809 y Fe([compress)45 b(NAME)i(T1,T2;)f(q)
+h(QLEVEL,)f(s)i(HSCALE])0 2064 y Fj(where)191 2320 y
+Fe(NAME)142 b(=)47 b(algorithm)f(name:)94 b(GZIP,)46
+b(Rice,)h(HCOMPRESS,)e(HSCOMPRSS)g(or)i(PLIO)620 2433
+y(may)g(be)h(abbreviated)c(to)j(the)g(first)g(letter)f(\(or)h(HS)g(for)
+g(HSCOMPRESS\))191 2546 y(T1,T2)94 b(=)47 b(tile)g(dimension)e(\(e.g.)i
+(100,100)f(for)g(square)h(tiles)f(100)h(pixels)f(wide\))191
+2659 y(QLEVEL)g(=)h(quantization)e(level)h(for)h(floating)f(point)g
+(FITS)h(images)191 2772 y(HSCALE)f(=)h(HCOMPRESS)f(scale)g(factor;)g
+(default)g(=)h(0)h(which)e(is)h(lossless.)0 3027 y Fj(Here)31
+b(are)g(a)f(few)h(examples)f(of)h(this)f(extended)h(syn)m(tax:)191
+3283 y Fe(myfile.fit[compress])185 b(-)48 b(use)f(the)g(default)e
+(compression)g(algorithm)g(\(Rice\))1432 3396 y(and)i(the)g(default)e
+(tile)i(size)g(\(row)f(by)i(row\))191 3622 y(myfile.fit[compress)42
+b(GZIP])47 b(-)g(use)g(the)g(specified)e(compression)g(algorithm;)191
+3735 y(myfile.fit[compress)d(Rice])238 b(only)46 b(the)h(first)g
+(letter)f(of)h(the)g(algorithm)191 3848 y(myfile.fit[compress)42
+b(PLIO])238 b(name)46 b(is)i(required.)191 3960 y(myfile.fit[compress)
+42 b(HCOMP])191 4186 y(myfile.fit[compress)g(R)48 b(100,100])141
+b(-)47 b(use)g(Rice)g(and)g(100)g(x)g(100)g(pixel)f(tiles)191
+4412 y(myfile.fit[compress)c(R;)48 b(q)f(10.0])f(-)i(quantization)c
+(level)j(=)g(\(RMS-noise\))e(/)i(10.)191 4525 y(myfile.fit[compress)42
+b(HS;)47 b(s)h(2.0])94 b(-)h(HSCOMPRESS)45 b(\(with)i(smoothing\))2005
+4638 y(and)f(scale)h(=)g(2.0)g(*)h(RMS-noise)0 4894 y
+Fj(2\))29 b(Before)g(calling)g(the)f(CFITSIO)e(routine)i(to)h(write)f
+(the)g(image)h(header)f(k)m(eyw)m(ords)g(\(e.g.,)j(\014ts)p
+3335 4894 28 4 v 32 w(create)p 3603 4894 V 34 w(image\))0
+5007 y(the)37 b(programmer)g(can)g(call)i(the)e(routines)g(describ)s
+(ed)f(b)s(elo)m(w)h(to)h(sp)s(ecify)f(the)g(compression)g(algorithm)i
+(and)0 5119 y(the)g(tiling)h(pattern)f(that)g(is)g(to)g(b)s(e)f(used.)
+65 b(There)38 b(are)i(routines)e(for)h(sp)s(ecifying)f(the)h(v)-5
+b(arious)39 b(compression)0 5232 y(parameters)31 b(and)e(similar)i
+(routines)f(to)i(return)d(the)h(curren)m(t)h(v)-5 b(alues)30
+b(of)h(the)f(parameters:)95 5488 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 5601 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 5714 y(int)g
+(fits_set_quantize_level\(fi)o(tsf)o(ile)41 b(*fptr,)46
+b(float)h(qlevel,)f(int)h(*status\))p eop end
+%%Page: 47 55
+TeXDict begin 47 54 bop 0 299 a Fh(5.6.)72 b(IMA)m(GE)31
+b(COMPRESSION)2567 b Fj(47)95 555 y Fe(int)47 b
+(fits_set_hcomp_scale\(fitsf)o(ile)41 b(*fptr,)46 b(float)h(scale,)f
+(int)h(*status\))95 668 y(int)g(fits_set_hcomp_smooth\(fits)o(fil)o(e)
+42 b(*fptr,)k(int)h(smooth,)f(int)h(*status\))668 781
+y(Set)g(smooth)f(=)i(1)f(to)g(apply)g(smoothing)e(when)i(uncompressing)
+d(the)j(image)95 1007 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
+1120 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
+1233 y(int)g(fits_get_quantize_level\(fi)o(tsf)o(ile)41
+b(*fptr,)46 b(float)h(*level,)f(int)h(*status\))95 1346
+y(int)g(fits_get_hcomp_scale\(fitsf)o(ile)41 b(*fptr,)46
+b(float)h(*scale,)e(int)i(*status\))95 1458 y(int)g
+(fits_get_hcomp_smooth\(fits)o(fil)o(e)42 b(*fptr,)k(int)h(*smooth,)e
+(int)i(*status\))0 1719 y Fj(4)24 b(sym)m(b)s(olic)f(constan)m(ts)i
+(are)e(de\014ned)f(for)h(use)g(as)g(the)h(v)-5 b(alue)23
+b(of)h(the)f(`compt)m(yp)s(e')h(parameter:)38 b(GZIP)p
+3447 1719 28 4 v 32 w(1,)25 b(RICE)p 3802 1719 V 32 w(1,)0
+1832 y(HCOMPRESS)p 586 1832 V 31 w(1)35 b(or)f(PLIO)p
+1035 1832 V 32 w(1.)52 b(En)m(tering)34 b(NULL)g(for)g(compt)m(yp)s(e)h
+(will)f(turn)f(o\013)i(the)f(tile-compression)i(and)0
+1945 y(cause)31 b(normal)f(FITS)g(images)h(to)g(b)s(e)f(written.)0
+2105 y(No)23 b(sp)s(ecial)f(action)i(is)e(required)f(b)m(y)h(soft)m(w)m
+(are)i(when)d(read)h(tile-compressed)h(images)g(b)s(ecause)f(all)h(the)
+f(CFITSIO)0 2218 y(routines)35 b(that)g(read)g(normal)g(uncompressed)f
+(FITS)g(images)i(also)g(transparen)m(tly)g(read)e(images)j(in)d(the)h
+(tile-)0 2331 y(compressed)28 b(format;)h(CFITSIO)e(essen)m(tially)j
+(treats)f(the)f(binary)g(table)h(that)f(con)m(tains)i(the)e(compressed)
+g(tiles)0 2444 y(as)j(if)f(it)h(w)m(ere)g(an)f(IMA)m(GE)h(extension.)0
+2604 y(The)f(follo)m(wing)i(2)e(routines)h(are)f(a)m(v)-5
+b(ailable)33 b(for)d(compressing)h(or)f(or)g(decompressing)h(an)f
+(image:)95 2865 y Fe(int)47 b(fits_img_compress\(fitsfile)41
+b(*infptr,)46 b(fitsfile)f(*outfptr,)g(int)i(*status\);)95
+2978 y(int)g(fits_img_decompress)c(\(fitsfile)i(*infptr,)h(fitsfile)f
+(*outfptr,)h(int)g(*status\);)0 3238 y Fj(Before)30 b(calling)h(the)f
+(compression)f(routine,)h(the)g(compression)f(parameters)h(m)m(ust)f
+(\014rst)g(b)s(e)g(de\014ned)f(in)h(one)h(of)0 3351 y(the)e(2)h(w)m(a)m
+(y)g(describ)s(ed)e(in)h(the)g(previous)g(paragraphs.)39
+b(There)28 b(is)g(also)h(a)f(routine)h(to)f(determine)h(if)f(the)g
+(curren)m(t)0 3464 y(HDU)j(con)m(tains)h(a)e(tile)i(compressed)e(image)
+i(\(it)f(returns)e(1)i(or)f(0\):)95 3725 y Fe(int)47
+b(fits_is_compressed_image\(f)o(its)o(file)41 b(*fptr,)46
+b(int)h(*status\);)0 3985 y Fj(A)30 b(small)g(example)g(program)f
+(called)i('imcop)m(y')f(is)g(included)f(with)g(CFITSIO)f(that)i(can)f
+(b)s(e)g(used)g(to)h(compress)0 4098 y(\(or)44 b(uncompress\))g(an)m(y)
+g(FITS)g(image.)83 b(This)43 b(program)h(can)h(b)s(e)e(used)h(to)g(exp)
+s(erimen)m(t)h(with)f(the)g(v)-5 b(arious)0 4211 y(compression)30
+b(options)h(on)f(existing)i(FITS)d(images)j(as)e(sho)m(wn)g(in)g(these)
+h(examples:)0 4472 y Fe(1\))95 b(imcopy)46 b(infile.fit)f
+('outfile.fit[compress]')334 4698 y(This)i(will)f(use)h(the)g(default)f
+(compression)f(algorithm)g(\(Rice\))h(and)h(the)334 4811
+y(default)f(tile)h(size)f(\(row)h(by)g(row\))0 5036 y(2\))95
+b(imcopy)46 b(infile.fit)f('outfile.fit[compress)d(GZIP]')334
+5262 y(This)47 b(will)f(use)h(the)g(GZIP)g(compression)e(algorithm)g
+(and)i(the)g(default)334 5375 y(tile)g(size)f(\(row)h(by)g(row\).)94
+b(The)47 b(allowed)f(compression)f(algorithms)g(are)334
+5488 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 5601 y(name)g(needs)f(to)h(be)g(specified.)p
+eop end
+%%Page: 48 56
+TeXDict begin 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)0 555 y Fe(3\))95 b(imcopy)46 b(infile.fit)f
+('outfile.fit[compress)d(G)47 b(100,100]')334 781 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
+894 y(tiles.)0 1120 y(4\))95 b(imcopy)46 b(infile.fit)f
+('outfile.fit[compress)d(R)47 b(100,100;)f(q)h(10.0]')334
+1346 y(This)g(will)f(use)h(the)g(Rice)g(compression)e(algorithm,)g(100)
+h(X)i(100)f(pixel)334 1458 y(tiles,)f(and)h(quantization)e(level)h(=)h
+(RMSnoise)f(/)h(10.0)g(\(assuming)e(the)334 1571 y(input)h(image)h(has)
+g(a)g(floating)f(point)g(data)h(type\).)0 1797 y(5\))95
+b(imcopy)46 b(infile.fit)f(outfile.fit)334 2023 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 2136 y(uncompressed)f(to)i(the)g(output)f(file.)94
+b(Otherwise,)45 b(it)i(simply)f(copies)334 2249 y(the)h(input)f(image)h
+(to)g(the)g(output)f(image.)0 2475 y(6\))95 b(imcopy)46
+b('infile.fit[1001:1500,20)o(01:2)o(500])o(')89 b(outfile.fit)334
+2700 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 2813 y(input)f(image)h(\(which)f(may)h(be)g
+(in)g(tile-compressed)d(format\).)93 b(The)334 2926 y(output)46
+b(is)h(a)h(normal)e(uncompressed)e(FITS)j(image.)0 3152
+y(7\))95 b(imcopy)46 b('infile.fit[1001:1500,20)o(01:2)o(500])o(')89
+b(outfile.fit.gz)334 3378 y(Same)47 b(as)g(above,)f(except)g(the)h
+(output)f(file)h(is)g(externally)e(compressed)334 3491
+y(using)h(the)h(gzip)g(algorithm.)0 3964 y Ff(5.7)135
+b(ASCI)t(I)45 b(and)f(Binary)h(T)-11 b(able)45 b(Routines)0
+4220 y Fj(These)36 b(routines)g(p)s(erform)f(read)i(and)e(write)i(op)s
+(erations)g(on)f(columns)g(of)h(data)g(in)f(FITS)g(ASCI)s(I)e(or)j
+(Binary)0 4333 y(tables.)47 b(Note)33 b(that)g(in)e(the)i(follo)m(wing)
+g(discussions,)f(the)g(\014rst)g(ro)m(w)g(and)f(column)h(in)g(a)g
+(table)h(is)g(at)f(p)s(osition)h(1)0 4446 y(not)e(0.)0
+4606 y(Users)k(should)g(also)i(read)e(the)h(follo)m(wing)h(c)m(hapter)g
+(on)e(the)h(CFITSIO)e(iterator)j(function)f(whic)m(h)f(pro)m(vides)h(a)
+0 4719 y(more)i(`ob)5 b(ject)39 b(orien)m(ted')g(metho)s(d)f(of)g
+(reading)g(and)g(writing)g(table)h(columns.)63 b(The)37
+b(iterator)j(function)d(is)i(a)0 4832 y(little)e(more)f(complicated)h
+(to)f(use,)h(but)e(the)g(adv)-5 b(an)m(tages)38 b(are)d(that)i(it)f
+(usually)f(tak)m(es)i(less)e(co)s(de)h(to)g(p)s(erform)0
+4945 y(the)h(same)f(op)s(eration,)j(and)c(the)i(resulting)f(program)g
+(often)h(runs)e(faster)i(b)s(ecause)f(the)g(FITS)g(\014les)g(are)h
+(read)0 5058 y(and)30 b(written)g(using)g(the)h(most)f(e\016cien)m(t)i
+(blo)s(c)m(k)f(size.)0 5375 y Fd(5.7.1)112 b(Create)38
+b(New)f(T)-9 b(able)0 5601 y Fi(1)81 b Fj(Create)40 b(a)f(new)g(ASCI)s
+(I)e(or)i(bin)m(table)h(table)g(extension.)68 b(If)39
+b(the)g(FITS)g(\014le)g(is)g(curren)m(tly)g(empt)m(y)h(then)f(a)227
+5714 y(dumm)m(y)25 b(primary)f(arra)m(y)i(will)g(b)s(e)f(created)i(b)s
+(efore)e(app)s(ending)f(the)i(table)g(extension)h(to)f(it.)40
+b(The)25 b(tblt)m(yp)s(e)p eop end
+%%Page: 49 57
+TeXDict begin 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)227 555 y(parameter)39 b(de\014nes)e(the)h(t)m(yp)s(e)h(of)f
+(table)h(and)e(can)i(ha)m(v)m(e)g(v)-5 b(alues)39 b(of)f(ASCI)s(I)p
+2924 555 28 4 v 31 w(TBL)g(or)g(BINAR)-8 b(Y)p 3659 555
+V 34 w(TBL.)227 668 y(The)29 b(naxis2)g(parameter)h(giv)m(es)g(the)g
+(initial)g(n)m(um)m(b)s(er)e(of)h(ro)m(ws)g(to)h(b)s(e)f(created)h(in)f
+(the)g(table,)h(and)f(should)227 781 y(normally)h(b)s(e)f(set)h(=)g(0.)
+40 b(CFITSIO)29 b(will)h(automatically)i(increase)f(the)e(size)i(of)f
+(the)g(table)g(as)g(additional)227 894 y(ro)m(ws)d(are)g(written.)40
+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)g(to)i(reserv)m(e)f(space)h(for)e(that)i(man)m(y)227
+1007 y(ro)m(ws,)41 b(ev)m(en)e(if)g(a)g(few)m(er)g(n)m(um)m(b)s(er)e
+(of)i(ro)m(ws)f(will)h(b)s(e)f(written.)66 b(The)38 b(tunit)g(and)g
+(extname)i(parameters)227 1120 y(are)e(optional)g(and)f(a)h(n)m(ull)f
+(p)s(oin)m(ter)g(ma)m(y)h(b)s(e)f(giv)m(en)h(if)g(they)f(are)h(not)f
+(de\014ned.)61 b(The)37 b(FITS)f(Standard)227 1233 y(recommends)29
+b(that)h(only)g(letters,)h(digits,)g(and)e(the)g(underscore)g(c)m
+(haracter)i(b)s(e)e(used)g(in)g(column)g(names)227 1346
+y(\(the)c(tt)m(yp)s(e)g(parameter\))g(with)e(no)h(em)m(b)s(edded)f
+(spaces.)40 b(T)-8 b(railing)24 b(blank)g(c)m(haracters)i(are)e(not)h
+(signi\014can)m(t.)95 1678 y Fe(int)47 b(fits_create_tbl)d(/)j(ffcrtb)
+286 1791 y(\(fitsfile)f(*fptr,)g(int)h(tbltype,)e(LONGLONG)h(naxis2,)g
+(int)g(tfields,)g(char)h(*ttype[],)334 1904 y(char)g(*tform[],)e(char)i
+(*tunit[],)e(char)i(*extname,)e(int)i(*status\))0 2188
+y Fd(5.7.2)112 b(Column)39 b(Information)f(Routines)0
+2391 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)g(in)h(the)g(curren)m(t)f(FITS)g(table.)41
+b(The)29 b(n)m(um)m(b)s(er)f(of)i(ro)m(ws)g(is)f(giv)m(en)i(b)m(y)227
+2503 y(the)j(NAXIS2)f(k)m(eyw)m(ord)h(and)e(the)i(n)m(um)m(b)s(er)e(of)
+h(columns)g(is)g(giv)m(en)h(b)m(y)f(the)h(TFIELDS)e(k)m(eyw)m(ord)i(in)
+f(the)227 2616 y(header)d(of)h(the)g(table.)95 2836 y
+Fe(int)47 b(fits_get_num_rows)c(/)48 b(ffgnrw)286 2949
+y(\(fitsfile)e(*fptr,)g(>)h(long)g(*nrows,)f(int)h(*status\);)95
+3175 y(int)g(fits_get_num_rowsll)c(/)k(ffgnrwll)286 3288
+y(\(fitsfile)f(*fptr,)g(>)h(LONGLONG)f(*nrows,)g(int)g(*status\);)95
+3513 y(int)h(fits_get_num_cols)c(/)48 b(ffgncl)286 3626
+y(\(fitsfile)e(*fptr,)g(>)h(int)g(*ncols,)f(int)h(*status\);)0
+3846 y Fi(2)81 b Fj(Get)25 b(the)f(table)i(column)e(n)m(um)m(b)s(er)f
+(\(and)h(name\))h(of)f(the)h(column)f(whose)g(name)g(matc)m(hes)i(an)e
+(input)g(template)227 3959 y(name.)48 b(If)32 b(casesen)i(=)e(CASESEN)g
+(then)g(the)h(column)f(name)h(matc)m(h)h(will)f(b)s(e)f(case-sensitiv)m
+(e,)k(whereas)227 4072 y(if)27 b(casesen)h(=)e(CASEINSEN)g(then)h(the)g
+(case)h(will)f(b)s(e)f(ignored.)40 b(As)27 b(a)g(general)h(rule,)f(the)
+g(column)g(names)227 4185 y(should)j(b)s(e)f(treated)j(as)e(case)i
+(INsensitiv)m(e.)227 4328 y(The)26 b(input)g(column)g(name)g(template)i
+(ma)m(y)f(b)s(e)f(either)h(the)g(exact)h(name)e(of)h(the)f(column)g(to)
+i(b)s(e)d(searc)m(hed)227 4441 y(for,)k(or)f(it)h(ma)m(y)g(con)m(tain)h
+(wild)e(card)g(c)m(haracters)i(\(*,)g(?,)f(or)f(#\),)h(or)f(it)h(ma)m
+(y)g(con)m(tain)h(the)e(in)m(teger)i(n)m(um)m(b)s(er)227
+4554 y(of)j(the)f(desired)f(column)h(\(with)g(the)h(\014rst)e(column)h
+(=)g(1\).)46 b(The)32 b(`*')h(wild)f(card)g(c)m(haracter)h(matc)m(hes)h
+(an)m(y)227 4667 y(sequence)h(of)g(c)m(haracters)h(\(including)f(zero)g
+(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 4780 y(c)m(haracter.)42
+b(The)29 b(#)h(wildcard)f(will)h(matc)m(h)h(an)m(y)e(consecutiv)m(e)j
+(string)e(of)f(decimal)i(digits)f(\(0-9\).)43 b(If)29
+b(more)227 4893 y(than)43 b(one)f(column)h(name)f(in)g(the)h(table)h
+(matc)m(hes)f(the)g(template)h(string,)i(then)c(the)h(\014rst)e(matc)m
+(h)j(is)227 5006 y(returned)28 b(and)h(the)g(status)h(v)-5
+b(alue)30 b(will)f(b)s(e)g(set)h(to)g(COL)p 2171 5006
+V 32 w(NOT)p 2408 5006 V 32 w(UNIQUE)f(as)h(a)f(w)m(arning)g(that)h(a)g
+(unique)227 5119 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,)h(call)f(the)g(routine)f(again)227 5232 y(lea)m(ving)g(the)e
+(input)f(status)h(v)-5 b(alue)26 b(equal)f(to)h(COL)p
+1950 5232 V 32 w(NOT)p 2187 5232 V 32 w(UNIQUE)f(and)f(the)h(next)h
+(matc)m(hing)g(name)f(will)227 5344 y(then)30 b(b)s(e)g(returned.)40
+b(Rep)s(eat)30 b(this)h(pro)s(cess)f(un)m(til)g(a)h(status)g(=)f(COL)p
+2628 5344 V 32 w(NOT)p 2865 5344 V 32 w(F)m(OUND)i(is)e(returned.)227
+5488 y(The)36 b(FITS)g(Standard)g(recommends)g(that)i(only)e(letters,)k
+(digits,)f(and)d(the)h(underscore)f(c)m(haracter)j(b)s(e)227
+5601 y(used)31 b(in)g(column)g(names)g(\(with)h(no)f(em)m(b)s(edded)f
+(spaces\).)45 b(T)-8 b(railing)32 b(blank)f(c)m(haracters)i(are)e(not)h
+(signi\014-)227 5714 y(can)m(t.)p eop end
+%%Page: 50 58
+TeXDict begin 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)95 555 y Fe(int)47 b(fits_get_colnum)d(/)j(ffgcno)286
+668 y(\(fitsfile)f(*fptr,)g(int)h(casesen,)e(char)i(*templt,)e(>)j(int)
+f(*colnum,)334 781 y(int)g(*status\))95 1007 y(int)g(fits_get_colname)d
+(/)j(ffgcnn)286 1120 y(\(fitsfile)f(*fptr,)g(int)h(casesen,)e(char)i
+(*templt,)e(>)j(char)e(*colname,)334 1233 y(int)h(*colnum,)f(int)g
+(*status\))0 1508 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,)32 b(and)f(the)h(width)f(in)g(b)m
+(ytes)h(of)g(a)g(column)f(in)g(an)h(ASCI)s(I)e(or)227
+1621 y(binary)35 b(table.)56 b(Allo)m(w)m(ed)37 b(v)-5
+b(alues)36 b(for)f(the)h(data)g(t)m(yp)s(e)f(in)g(ASCI)s(I)f(tables)i
+(are:)51 b(TSTRING,)35 b(TSHOR)-8 b(T,)227 1734 y(TLONG,)36
+b(TFLO)m(A)-8 b(T,)36 b(and)f(TDOUBLE.)i(Binary)e(tables)i(also)g(supp)
+s(ort)d(these)i(t)m(yp)s(es:)52 b(TLOGICAL,)227 1847
+y(TBIT,)38 b(TBYTE,)h(TCOMPLEX)e(and)h(TDBLCOMPLEX.)h(The)f(negativ)m
+(e)i(of)f(the)g(data)g(t)m(yp)s(e)g(co)s(de)227 1960
+y(v)-5 b(alue)32 b(is)f(returned)f(if)h(it)g(is)h(a)f(v)-5
+b(ariable)32 b(length)f(arra)m(y)h(column.)43 b(Note)32
+b(that)g(in)e(the)i(case)g(of)f(a)g('J')h(32-bit)227
+2073 y(in)m(teger)g(binary)d(table)i(column,)f(this)g(routine)g(will)g
+(return)f(data)i(t)m(yp)s(e)f(=)g(TINT32BIT)g(\(whic)m(h)g(in)g(fact)
+227 2186 y(is)36 b(equiv)-5 b(alen)m(t)37 b(to)g(TLONG\).)f(With)g
+(most)g(curren)m(t)g(C)f(compilers,)j(a)f(v)-5 b(alue)36
+b(in)f(a)i('J')f(column)f(has)h(the)227 2299 y(same)29
+b(size)g(as)g(an)f('in)m(t')i(v)-5 b(ariable,)30 b(and)d(ma)m(y)j(not)e
+(b)s(e)g(equiv)-5 b(alen)m(t)30 b(to)f(a)g('long')g(v)-5
+b(ariable,)30 b(whic)m(h)e(is)h(64-bits)227 2412 y(long)i(on)g(an)f
+(increasing)h(n)m(um)m(b)s(er)e(of)h(compilers.)227 2570
+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)f(table)h(TF)m(ORMn)f(k)m(eyw)m
+(ord)227 2683 y(v)-5 b(alue.)60 b(\(ASCI)s(I)35 b(table)j(columns)e
+(alw)m(a)m(ys)i(ha)m(v)m(e)g(rep)s(eat)e(=)g(1\).)60
+b(The)36 b('width')g(parameter)h(returns)f(the)227 2796
+y(width)30 b(in)g(b)m(ytes)h(of)g(a)f(single)h(column)g(elemen)m(t)h
+(\(e.g.,)g(a)f('10D')h(binary)e(table)h(column)f(will)h(ha)m(v)m(e)h
+(width)227 2909 y(=)d(8,)i(an)e(ASCI)s(I)f(table)i('F12.2')i(column)e
+(will)g(ha)m(v)m(e)g(width)f(=)g(12,)i(and)e(a)h(binary)e(table'60A')k
+(c)m(haracter)227 3022 y(string)44 b(column)g(will)g(ha)m(v)m(e)h
+(width)e(=)h(60\);)52 b(Note)45 b(that)f(CFITSIO)f(supp)s(orts)f(the)i
+(lo)s(cal)h(con)m(v)m(en)m(tion)227 3135 y(for)d(sp)s(ecifying)f(arra)m
+(ys)i(of)f(\014xed)f(length)h(strings)f(within)h(a)g(binary)f(table)h
+(c)m(haracter)i(column)d(using)227 3247 y(the)g(syn)m(tax)g(TF)m(ORM)g
+(=)g('rAw')f(where)g('r')h(is)g(the)g(total)h(n)m(um)m(b)s(er)d(of)i(c)
+m(haracters)h(\(=)f(the)g(width)f(of)227 3360 y(the)f(column\))g(and)e
+('w')i(is)f(the)h(width)f(of)g(a)h(unit)f(string)g(within)g(the)h
+(column.)65 b(Th)m(us)37 b(if)h(the)h(column)227 3473
+y(has)34 b(TF)m(ORM)h(=)f('60A12')j(then)d(this)g(means)g(that)h(eac)m
+(h)g(ro)m(w)g(of)f(the)h(table)g(con)m(tains)g(5)g(12-c)m(haracter)227
+3586 y(substrings)23 b(within)h(the)g(60-c)m(haracter)j(\014eld,)f(and)
+d(th)m(us)h(in)g(this)g(case)h(this)g(routine)f(will)g(return)f(t)m(yp)
+s(eco)s(de)227 3699 y(=)f(TSTRING,)g(rep)s(eat)g(=)g(60,)j(and)d(width)
+f(=)h(12.)39 b(\(The)22 b(TDIMn)g(k)m(eyw)m(ord)h(ma)m(y)g(also)g(b)s
+(e)f(used)f(to)i(sp)s(ecify)227 3812 y(the)29 b(unit)e(string)h
+(length;)i(The)e(pair)g(of)g(k)m(eyw)m(ords)g(TF)m(ORMn)g(=)g('60A')i
+(and)e(TDIMn)f(=)h('\(12,5\)')j(w)m(ould)227 3925 y(ha)m(v)m(e)g(the)f
+(same)g(e\013ect)h(as)e(TF)m(ORMn)h(=)f('60A12'\).)43
+b(The)29 b(n)m(um)m(b)s(er)f(of)i(substrings)e(in)h(an)m(y)h(binary)f
+(table)227 4038 y(c)m(haracter)36 b(string)e(\014eld)f(can)h(b)s(e)g
+(calculated)i(b)m(y)d(\(rep)s(eat/width\).)53 b(A)34
+b(n)m(ull)f(p)s(oin)m(ter)h(ma)m(y)h(b)s(e)e(giv)m(en)i(for)227
+4151 y(an)m(y)c(of)g(the)f(output)g(parameters)h(that)g(are)g(not)f
+(needed.)227 4309 y(The)46 b(second)g(routine,)k(\014t)p
+1188 4309 28 4 v 33 w(get)p 1341 4309 V 34 w(eqcolt)m(yp)s(e)d(is)f
+(similar)h(except)g(that)f(in)g(the)g(case)i(of)e(scaled)h(in)m(teger)
+227 4422 y(columns)35 b(it)g(returns)f(the)h('equiv)-5
+b(alen)m(t')37 b(data)f(t)m(yp)s(e)f(that)h(is)f(needed)f(to)i(store)g
+(the)f(scaled)h(v)-5 b(alues,)37 b(and)227 4535 y(not)28
+b(necessarily)h(the)f(ph)m(ysical)g(data)g(t)m(yp)s(e)g(of)g(the)g
+(unscaled)f(v)-5 b(alues)29 b(as)e(stored)h(in)g(the)f(FITS)g(table.)41
+b(F)-8 b(or)227 4648 y(example)38 b(if)g(a)g('1I')g(column)f(in)g(a)h
+(binary)f(table)h(has)g(TSCALn)d(=)j(1)f(and)g(TZER)m(On)f(=)i(32768,)j
+(then)227 4761 y(this)29 b(column)f(e\013ectiv)m(ely)k(con)m(tains)d
+(unsigned)f(short)g(in)m(teger)i(v)-5 b(alues,)29 b(and)f(th)m(us)h
+(the)f(returned)g(v)-5 b(alue)29 b(of)227 4874 y(t)m(yp)s(eco)s(de)34
+b(will)f(b)s(e)g(TUSHOR)-8 b(T,)32 b(not)h(TSHOR)-8 b(T.)33
+b(Similarly)-8 b(,)34 b(if)f(a)h(column)f(has)f(TTYPEn)g(=)h('1I')h
+(and)227 4986 y(TSCALn)29 b(=)h(0.12,)i(then)e(the)h(returned)e(t)m(yp)
+s(eco)s(de)i(will)f(b)s(e)g(TFLO)m(A)-8 b(T.)95 5262
+y Fe(int)47 b(fits_get_coltype)d(/)j(ffgtcl)286 5375
+y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(>)j(int)f(*typecode,)e(long)h
+(*repeat,)334 5488 y(long)h(*width,)f(int)g(*status\))95
+5714 y(int)h(fits_get_coltypell)c(/)48 b(ffgtclll)p eop
+end
+%%Page: 51 59
+TeXDict begin 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(\(fitsfile)46 b(*fptr,)g(int)h(colnum,)e(>)j(int)f
+(*typecode,)e(LONGLONG)g(*repeat,)334 668 y(LONGLONG)h(*width,)f(int)i
+(*status\))95 894 y(int)g(fits_get_eqcoltype)c(/)48 b(ffeqty)286
+1007 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(>)j(int)f(*typecode,)e
+(long)h(*repeat,)334 1120 y(long)h(*width,)f(int)g(*status\))95
+1346 y(int)h(fits_get_eqcoltypell)c(/)k(ffeqtyll)286
+1458 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(>)j(int)f(*typecode,)e
+(LONGLONG)g(*repeat,)334 1571 y(LONGLONG)h(*width,)f(int)i(*status\))0
+1808 y Fi(4)81 b Fj(Return)29 b(the)h(displa)m(y)g(width)f(of)h(a)h
+(column.)40 b(This)29 b(is)h(the)g(length)h(of)f(the)g(string)g(that)h
+(will)f(b)s(e)f(returned)g(b)m(y)227 1921 y(the)34 b(\014ts)p
+514 1921 28 4 v 32 w(read)p 718 1921 V 33 w(col)g(routine)f(when)f
+(reading)h(the)h(column)e(as)i(a)f(formatted)h(string.)49
+b(The)32 b(displa)m(y)i(width)227 2034 y(is)29 b(determined)g(b)m(y)g
+(the)g(TDISPn)f(k)m(eyw)m(ord,)i(if)f(presen)m(t,)h(otherwise)f(b)m(y)g
+(the)g(data)h(t)m(yp)s(e)f(of)h(the)f(column.)95 2384
+y Fe(int)47 b(fits_get_col_display_width)41 b(/)47 b(ffgcdw)286
+2497 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(>)j(int)f(*dispwidth,)e
+(int)h(*status\))0 2734 y Fi(5)81 b Fj(Return)27 b(the)i(n)m(um)m(b)s
+(er)e(of)i(and)e(size)j(of)e(the)h(dimensions)f(of)g(a)h(table)g
+(column)g(in)f(a)g(binary)g(table.)41 b(Normally)227
+2847 y(this)28 b(information)h(is)f(giv)m(en)h(b)m(y)f(the)h(TDIMn)f(k)
+m(eyw)m(ord,)h(but)e(if)i(this)f(k)m(eyw)m(ord)g(is)g(not)h(presen)m(t)
+f(then)g(this)227 2960 y(routine)j(returns)e(naxis)h(=)g(1)h(and)f
+(naxes[0])h(equal)g(to)g(the)g(rep)s(eat)f(coun)m(t)h(in)f(the)h(TF)m
+(ORM)g(k)m(eyw)m(ord.)95 3197 y Fe(int)47 b(fits_read_tdim)d(/)k
+(ffgtdm)286 3309 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(int)i(maxdim,)
+f(>)i(int)f(*naxis,)334 3422 y(long)g(*naxes,)f(int)g(*status\))95
+3648 y(int)h(fits_read_tdimll)d(/)j(ffgtdmll)286 3761
+y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(int)i(maxdim,)f(>)i(int)f
+(*naxis,)334 3874 y(LONGLONG)f(*naxes,)f(int)i(*status\))0
+4111 y Fi(6)81 b Fj(Deco)s(de)33 b(the)g(input)f(TDIMn)h(k)m(eyw)m(ord)
+g(string)f(\(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 4224 y(of)c(the)g(dimensions)f(of)h
+(a)g(binary)f(table)h(column.)40 b(If)27 b(the)h(input)f(tdimstr)g(c)m
+(haracter)i(string)f(is)g(n)m(ull,)g(then)227 4337 y(this)d(routine)f
+(returns)f(naxis)h(=)h(1)f(and)g(naxes[0])i(equal)e(to)i(the)e(rep)s
+(eat)h(coun)m(t)g(in)f(the)g(TF)m(ORM)h(k)m(eyw)m(ord.)227
+4450 y(This)30 b(routine)g(is)h(called)g(b)m(y)f(\014ts)p
+1350 4450 V 33 w(read)p 1555 4450 V 33 w(tdim.)95 4687
+y Fe(int)47 b(fits_decode_tdim)d(/)j(ffdtdm)286 4799
+y(\(fitsfile)f(*fptr,)g(char)g(*tdimstr,)g(int)h(colnum,)e(int)i
+(maxdim,)f(>)i(int)e(*naxis,)334 4912 y(long)h(*naxes,)f(int)g
+(*status\))95 5138 y(int)h(fits_decode_tdimll)c(/)48
+b(ffdtdmll)286 5251 y(\(fitsfile)e(*fptr,)g(char)g(*tdimstr,)g(int)h
+(colnum,)e(int)i(maxdim,)f(>)i(int)e(*naxis,)334 5364
+y(LONGLONG)g(*naxes,)f(int)i(*status\))0 5601 y Fi(7)81
+b Fj(W)-8 b(rite)23 b(a)g(TDIMn)f(k)m(eyw)m(ord)h(whose)f(v)-5
+b(alue)23 b(has)g(the)f(form)g('\(l,m,n...\)')40 b(where)22
+b(l,)i(m,)g(n...)38 b(are)23 b(the)g(dimensions)227 5714
+y(of)31 b(a)g(m)m(ultidimensional)g(arra)m(y)g(column)f(in)g(a)h
+(binary)e(table.)p eop end
+%%Page: 52 60
+TeXDict begin 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)95 555 y Fe(int)47 b(fits_write_tdim)d(/)j(ffptdm)286
+668 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(int)i(naxis,)f(long)h
+(*naxes,)f(>)h(int)g(*status\))95 894 y(int)g(fits_write_tdimll)c(/)48
+b(ffptdmll)286 1007 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(int)i
+(naxis,)f(LONGLONG)g(*naxes,)g(>)h(int)g(*status\))0
+1298 y Fd(5.7.3)112 b(Routines)38 b(to)f(Edit)g(Ro)m(ws)g(or)g(Columns)
+0 1508 y Fi(1)81 b Fj(Insert)32 b(or)h(delete)i(ro)m(ws)e(in)g(an)g
+(ASCI)s(I)f(or)h(binary)f(table.)50 b(When)33 b(inserting)h(ro)m(ws)f
+(all)h(the)f(ro)m(ws)g(follo)m(wing)227 1621 y(ro)m(w)24
+b(FR)m(O)m(W)i(are)e(shifted)f(do)m(wn)h(b)m(y)g(NR)m(O)m(WS)g(ro)m
+(ws;)j(if)c(FR)m(O)m(W)j(=)d(0)i(then)e(the)h(blank)g(ro)m(ws)g(are)g
+(inserted)227 1734 y(at)31 b(the)e(b)s(eginning)g(of)h(the)f(table.)42
+b(Note)31 b(that)f(it)g(is)f(*not*)i(necessary)f(to)g(insert)f(ro)m(ws)
+h(in)f(a)h(table)g(b)s(efore)227 1846 y(writing)g(data)g(to)g(those)h
+(ro)m(ws)e(\(indeed,)h(it)g(w)m(ould)f(b)s(e)g(ine\016cien)m(t)i(to)f
+(do)g(so\).)41 b(Instead)29 b(one)h(ma)m(y)g(simply)227
+1959 y(write)h(data)g(to)g(an)m(y)g(ro)m(w)f(of)h(the)f(table,)i
+(whether)e(that)h(ro)m(w)f(of)h(data)g(already)g(exists)g(or)f(not.)227
+2110 y(The)40 b(\014rst)g(delete)i(routine)e(deletes)i(NR)m(O)m(WS)f
+(consecutiv)m(e)h(ro)m(ws)f(starting)g(with)f(ro)m(w)g(FIRSTR)m(O)m(W.)
+227 2223 y(The)d(second)g(delete)h(routine)f(tak)m(es)h(an)f(input)f
+(string)h(that)h(lists)f(the)g(ro)m(ws)g(or)g(ro)m(w)g(ranges)g
+(\(e.g.,)k('5-)227 2336 y(10,12,20-30'\),)32 b(whereas)26
+b(the)g(third)g(delete)h(routine)f(tak)m(es)h(an)f(input)f(in)m(teger)j
+(arra)m(y)e(that)h(sp)s(eci\014es)f(eac)m(h)227 2449
+y(individual)35 b(ro)m(w)h(to)g(b)s(e)f(deleted.)58 b(In)35
+b(b)s(oth)f(latter)j(cases,)i(the)c(input)g(list)h(of)g(ro)m(ws)g(to)g
+(delete)h(m)m(ust)f(b)s(e)227 2562 y(sorted)i(in)g(ascending)g(order.)
+62 b(These)38 b(routines)f(up)s(date)g(the)h(NAXIS2)g(k)m(eyw)m(ord)h
+(to)f(re\015ect)g(the)g(new)227 2674 y(n)m(um)m(b)s(er)29
+b(of)i(ro)m(ws)f(in)g(the)h(table.)95 2935 y Fe(int)47
+b(fits_insert_rows)d(/)j(ffirow)286 3048 y(\(fitsfile)f(*fptr,)g
+(LONGLONG)f(firstrow,)h(LONGLONG)f(nrows,)h(>)i(int)f(*status\))95
+3274 y(int)g(fits_delete_rows)d(/)j(ffdrow)286 3387 y(\(fitsfile)f
+(*fptr,)g(LONGLONG)f(firstrow,)h(LONGLONG)f(nrows,)h(>)i(int)f
+(*status\))95 3612 y(int)g(fits_delete_rowrange)c(/)k(ffdrrg)286
+3725 y(\(fitsfile)f(*fptr,)g(char)g(*rangelist,)f(>)j(int)e(*status\))
+95 3951 y(int)h(fits_delete_rowlist)c(/)k(ffdrws)286
+4064 y(\(fitsfile)f(*fptr,)g(long)g(*rowlist,)g(long)g(nrows,)g(>)i
+(int)f(*status\))95 4290 y(int)g(fits_delete_rowlistll)42
+b(/)48 b(ffdrwsll)286 4403 y(\(fitsfile)e(*fptr,)g(LONGLONG)f
+(*rowlist,)h(LONGLONG)f(nrows,)h(>)i(int)f(*status\))0
+4663 y Fi(2)81 b Fj(Insert)36 b(or)h(delete)i(column\(s\))e(in)g(an)g
+(ASCI)s(I)f(or)h(binary)f(table.)62 b(When)37 b(inserting,)i(COLNUM)e
+(sp)s(eci\014es)227 4776 y(the)28 b(column)g(n)m(um)m(b)s(er)f(that)h
+(the)g(\(\014rst\))g(new)f(column)h(should)f(o)s(ccup)m(y)h(in)g(the)g
+(table.)41 b(NCOLS)26 b(sp)s(eci\014es)227 4889 y(ho)m(w)35
+b(man)m(y)g(columns)f(are)h(to)g(b)s(e)f(inserted.)53
+b(An)m(y)35 b(existing)h(columns)e(from)g(this)h(p)s(osition)f(and)g
+(higher)227 5002 y(are)c(shifted)f(o)m(v)m(er)h(to)g(allo)m(w)g(ro)s
+(om)f(for)g(the)h(new)e(column\(s\).)41 b(The)29 b(index)f(n)m(um)m(b)s
+(er)g(on)h(all)h(the)f(follo)m(wing)227 5115 y(k)m(eyw)m(ords)34
+b(will)f(b)s(e)g(incremen)m(ted)h(or)f(decremen)m(ted)h(if)f(necessary)
+h(to)g(re\015ect)g(the)f(new)g(p)s(osition)g(of)h(the)227
+5228 y(column\(s\))26 b(in)f(the)h(table:)39 b(TBCOLn,)26
+b(TF)m(ORMn,)h(TTYPEn,)e(TUNITn,)h(TNULLn,)g(TSCALn,)f(TZE-)227
+5341 y(R)m(On,)43 b(TDISPn,)g(TDIMn,)g(TLMINn,)g(TLMAXn,)g(TDMINn,)g
+(TDMAXn,)h(TCTYPn,)e(TCRPXn,)227 5453 y(TCR)-10 b(VLn,)29
+b(TCDL)-8 b(Tn,)30 b(TCR)m(OTn,)f(and)h(TCUNIn.)95 5714
+y Fe(int)47 b(fits_insert_col)d(/)j(fficol)p eop end
+%%Page: 53 61
+TeXDict begin 53 60 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(53)286 555 y Fe(\(fitsfile)46 b(*fptr,)g(int)h(colnum,)e(char)i
+(*ttype,)f(char)h(*tform,)334 668 y(>)h(int)e(*status\))95
+894 y(int)h(fits_insert_cols)d(/)j(fficls)286 1007 y(\(fitsfile)f
+(*fptr,)g(int)h(colnum,)e(int)i(ncols,)f(char)h(**ttype,)334
+1120 y(char)g(**tform,)e(>)j(int)f(*status\))95 1346
+y(int)g(fits_delete_col)d(/)j(ffdcol\(fitsfile)d(*fptr,)i(int)h
+(colnum,)f(>)h(int)g(*status\))0 1604 y Fi(3)81 b Fj(Cop)m(y)32
+b(a)h(column)g(from)f(one)h(HDU)g(to)h(another)e(\(or)h(to)h(the)f
+(same)g(HDU\).)h(If)e(create)p 3129 1604 28 4 v 34 w(col)i(=)e(TR)m
+(UE,)h(then)227 1717 y(a)40 b(new)e(column)h(will)g(b)s(e)g(inserted)g
+(in)f(the)h(output)g(table,)j(at)e(p)s(osition)f(`outcolumn',)j
+(otherwise)e(the)227 1830 y(existing)f(output)f(column)f(will)i(b)s(e)e
+(o)m(v)m(erwritten)i(\(in)f(whic)m(h)g(case)h(it)f(m)m(ust)g(ha)m(v)m
+(e)h(a)f(compatible)h(data)227 1943 y(t)m(yp)s(e\).)i(If)29
+b(outcoln)m(um)h(is)f(greater)i(than)e(the)h(n)m(um)m(b)s(er)e(of)h
+(column)g(in)g(the)h(table,)h(then)e(the)g(new)g(column)227
+2056 y(will)j(b)s(e)f(app)s(ended)f(to)j(the)f(end)f(of)g(the)h(table.)
+46 b(Note)33 b(that)f(the)g(\014rst)f(column)g(in)h(a)g(table)g(is)g
+(at)h(coln)m(um)227 2169 y(=)j(1.)58 b(The)36 b(standard)f(indexed)g(k)
+m(eyw)m(ords)i(that)f(related)h(to)g(the)f(column)g(\(e.g.,)j(TDISPn,)e
+(TUNITn,)227 2282 y(TCRPXn,)30 b(TCDL)-8 b(Tn,)29 b(etc.\))43
+b(will)30 b(also)i(b)s(e)d(copied.)95 2541 y Fe(int)47
+b(fits_copy_col)e(/)i(ffcpcl)286 2654 y(\(fitsfile)f(*infptr,)f
+(fitsfile)h(*outfptr,)f(int)i(incolnum,)e(int)i(outcolnum,)334
+2767 y(int)g(create_col,)e(>)i(int)g(*status\);)0 3026
+y Fi(4)81 b Fj(Cop)m(y)30 b('nro)m(ws')g(consecutiv)m(e)j(ro)m(ws)d
+(from)g(one)h(table)g(to)g(another,)g(b)s(eginning)f(with)g(ro)m(w)g
+('\014rstro)m(w'.)41 b(These)227 3138 y(ro)m(ws)31 b(will)h(b)s(e)e
+(app)s(ended)g(to)i(an)m(y)f(existing)h(ro)m(ws)g(in)e(the)i(output)e
+(table.)44 b(Note)33 b(that)f(the)f(\014rst)f(ro)m(w)i(in)f(a)227
+3251 y(table)h(is)e(at)h(ro)m(w)g(=)f(1.)95 3510 y Fe(int)47
+b(fits_copy_rows)d(/)k(ffcprw)286 3623 y(\(fitsfile)e(*infptr,)f
+(fitsfile)h(*outfptr,)f(LONGLONG)h(firstrow,)334 3736
+y(LONGLONG)g(nrows,)g(>)h(int)g(*status\);)0 3995 y Fi(5)81
+b Fj(Mo)s(dify)37 b(the)g(v)m(ector)i(length)f(of)f(a)h(binary)e(table)
+i(column)f(\(e.g.,)k(c)m(hange)e(a)e(column)g(from)g(TF)m(ORMn)g(=)227
+4108 y('1E')31 b(to)h('20E'\).)g(The)e(v)m(ector)i(length)e(ma)m(y)h(b)
+s(e)f(increased)h(or)f(decreased)h(from)f(the)g(curren)m(t)h(v)-5
+b(alue.)95 4367 y Fe(int)47 b(fits_modify_vector_len)42
+b(/)48 b(ffmvec)286 4480 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e
+(LONGLONG)h(newveclen,)f(>)i(int)g(*status\))0 4770 y
+Fd(5.7.4)112 b(Read)38 b(and)h(W)-9 b(rite)36 b(Column)j(Data)e
+(Routines)0 4989 y Fj(The)e(follo)m(wing)h(routines)g(write)f(or)g
+(read)g(data)h(v)-5 b(alues)36 b(in)f(the)g(curren)m(t)g(ASCI)s(I)f(or)
+h(binary)g(table)h(extension.)0 5102 y(If)d(a)g(write)g(op)s(eration)h
+(extends)f(b)s(ey)m(ond)f(the)h(curren)m(t)g(size)h(of)f(the)g(table,)i
+(then)e(the)g(n)m(um)m(b)s(er)f(of)h(ro)m(ws)g(in)g(the)0
+5215 y(table)i(will)g(automatically)i(b)s(e)c(increased)i(and)e(the)i
+(NAXIS2)f(k)m(eyw)m(ord)h(v)-5 b(alue)35 b(will)f(b)s(e)g(up)s(dated.)
+51 b(A)m(ttempts)0 5328 y(to)31 b(read)f(b)s(ey)m(ond)g(the)h(end)e(of)
+i(the)f(table)i(will)e(result)h(in)f(an)g(error.)0 5488
+y(Automatic)d(data)e(t)m(yp)s(e)g(con)m(v)m(ersion)h(is)f(p)s(erformed)
+f(for)g(n)m(umerical)i(data)f(t)m(yp)s(es)g(\(only\))h(if)f(the)g(data)
+h(t)m(yp)s(e)f(of)g(the)0 5601 y(column)34 b(\(de\014ned)f(b)m(y)h(the)
+g(TF)m(ORMn)g(k)m(eyw)m(ord\))h(di\013ers)f(from)g(the)g(data)h(t)m(yp)
+s(e)f(of)g(the)h(arra)m(y)f(in)g(the)g(calling)0 5714
+y(routine.)65 b(ASCI)s(I)37 b(and)h(binary)f(tables)i(supp)s(ort)e(the)
+i(follo)m(wing)g(data)h(t)m(yp)s(e)e(v)-5 b(alues:)57
+b(TSTRING,)38 b(TBYTE,)p eop end
+%%Page: 54 62
+TeXDict begin 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)0 555 y Fj(TSBYTE,)e(TSHOR)-8 b(T,)27 b(TUSHOR)-8
+b(T,)28 b(TINT,)g(TUINT,)g(TLONG,)g(TLONGLONG,)g(TULONG,)g(TFLO)m(A)-8
+b(T,)0 668 y(or)25 b(TDOUBLE.)g(Binary)f(tables)i(also)f(supp)s(ort)e
+(TLOGICAL)h(\(in)m(ternally)i(mapp)s(ed)d(to)i(the)g(`c)m(har')h(data)f
+(t)m(yp)s(e\),)0 781 y(TCOMPLEX,)30 b(and)f(TDBLCOMPLEX.)0
+941 y(Note)d(that)g(it)g(is)f(*not*)h(necessary)f(to)h(insert)f(ro)m
+(ws)g(in)g(a)g(table)h(b)s(efore)f(writing)g(data)h(to)g(those)f(ro)m
+(ws)g(\(indeed,)h(it)0 1054 y(w)m(ould)h(b)s(e)g(ine\016cien)m(t)i(to)f
+(do)f(so\).)41 b(Instead,)28 b(one)g(ma)m(y)g(simply)f(write)g(data)h
+(to)h(an)m(y)e(ro)m(w)h(of)g(the)f(table,)j(whether)0
+1167 y(that)h(ro)m(w)f(of)h(data)g(already)g(exists)g(or)f(not.)0
+1327 y(Individual)g(bits)i(in)f(a)h(binary)e(table)i('X')g(or)g('B')g
+(column)f(ma)m(y)h(b)s(e)f(read/written)h(to/from)g(a)g(*c)m(har)g
+(arra)m(y)g(b)m(y)0 1440 y(sp)s(ecifying)k(the)f(TBIT)h(datat)m(yp)s
+(e.)57 b(The)35 b(*c)m(har)i(arra)m(y)f(will)g(b)s(e)f(in)m(terpreted)h
+(as)g(an)g(arra)m(y)g(of)g(logical)i(TR)m(UE)0 1553 y(\(1\))d(or)g(F)
+-10 b(ALSE)34 b(\(0\))h(v)-5 b(alues)35 b(that)g(corresp)s(ond)e(to)i
+(the)g(v)-5 b(alue)35 b(of)f(eac)m(h)i(bit)e(in)g(the)h(FITS)e('X')i
+(or)g('B')g(column.)0 1666 y(Alternativ)m(ely)-8 b(,)30
+b(the)c(v)-5 b(alues)27 b(in)e(a)i(binary)e(table)i('X')g(column)f(ma)m
+(y)h(b)s(e)e(read/written)i(8)f(bits)g(at)h(a)f(time)h(to/from)0
+1779 y(an)j(arra)m(y)h(of)g(8-bit)g(in)m(tegers)g(b)m(y)g(sp)s
+(ecifying)f(the)h(TBYTE)f(datat)m(yp)s(e.)0 1939 y(Note)25
+b(that)g(within)e(the)h(con)m(text)i(of)e(these)g(routines,)i(the)e
+(TSTRING)f(data)h(t)m(yp)s(e)g(corresp)s(onds)f(to)h(a)h(C)e('c)m
+(har**')0 2052 y(data)35 b(t)m(yp)s(e,)h(i.e.,)h(a)e(p)s(oin)m(ter)f
+(to)i(an)e(arra)m(y)h(of)g(p)s(oin)m(ters)f(to)h(an)g(arra)m(y)g(of)g
+(c)m(haracters.)54 b(This)34 b(is)g(di\013eren)m(t)h(from)0
+2165 y(the)d(k)m(eyw)m(ord)h(reading)f(and)f(writing)h(routines)g
+(where)g(TSTRING)f(corresp)s(onds)g(to)h(a)h(C)e('c)m(har*')j(data)f(t)
+m(yp)s(e,)0 2278 y(i.e.,)g(a)e(single)h(p)s(oin)m(ter)f(to)h(an)f(arra)
+m(y)g(of)g(c)m(haracters.)45 b(When)30 b(reading)i(strings)e(from)h(a)g
+(table,)i(the)e(c)m(har)h(arra)m(ys)0 2391 y(ob)m(viously)f(m)m(ust)f
+(ha)m(v)m(e)i(b)s(een)e(allo)s(cated)i(long)f(enough)f(to)h(hold)f(the)
+h(whole)f(FITS)g(table)h(string.)0 2551 y(Numerical)i(data)g(v)-5
+b(alues)33 b(are)g(automatically)j(scaled)d(b)m(y)f(the)h(TSCALn)e(and)
+h(TZER)m(On)f(k)m(eyw)m(ord)i(v)-5 b(alues)33 b(\(if)0
+2664 y(they)e(exist\).)0 2824 y(In)25 b(the)g(case)i(of)e(binary)g
+(tables)h(with)f(v)m(ector)i(elemen)m(ts,)h(the)e('felem')g(parameter)g
+(de\014nes)f(the)g(starting)h(elemen)m(t)0 2937 y(\(b)s(eginning)h
+(with)g(1,)h(not)g(0\))g(within)f(the)g(cell)i(\(a)f(cell)g(is)f
+(de\014ned)f(as)i(the)f(in)m(tersection)i(of)f(a)f(ro)m(w)h(and)e(a)i
+(column)0 3050 y(and)e(ma)m(y)h(con)m(tain)h(a)g(single)f(v)-5
+b(alue)27 b(or)g(a)g(v)m(ector)h(of)f(v)-5 b(alues\).)40
+b(The)26 b(felem)i(parameter)f(is)g(ignored)f(when)g(dealing)0
+3163 y(with)34 b(ASCI)s(I)e(tables.)52 b(Similarly)-8
+b(,)36 b(in)d(the)i(case)f(of)h(binary)e(tables)h(the)h('nelemen)m(ts')
+g(parameter)f(sp)s(eci\014es)g(the)0 3275 y(total)28
+b(n)m(um)m(b)s(er)d(of)h(v)m(ector)i(v)-5 b(alues)27
+b(to)g(b)s(e)e(read)h(or)h(written)f(\(con)m(tin)m(uing)i(on)e
+(subsequen)m(t)f(ro)m(ws)i(if)f(required\))g(and)0 3388
+y(not)31 b(the)f(n)m(um)m(b)s(er)f(of)i(table)g(cells.)0
+3637 y Fi(1)81 b Fj(W)-8 b(rite)31 b(elemen)m(ts)h(in)m(to)f(an)g(ASCI)
+s(I)e(or)h(binary)f(table)j(column.)0 3885 y(The)38 b(\014rst)f
+(routine)h(simply)g(writes)g(the)g(arra)m(y)h(of)f(v)-5
+b(alues)39 b(to)g(the)f(FITS)g(\014le)g(\(doing)g(data)h(t)m(yp)s(e)g
+(con)m(v)m(ersion)0 3998 y(if)h(necessary\))h(whereas)f(the)h(second)f
+(routine)h(will)f(substitute)h(the)f(appropriate)g(FITS)g(n)m(ull)g(v)
+-5 b(alue)41 b(for)f(all)0 4111 y(elemen)m(ts)34 b(whic)m(h)f(are)g
+(equal)h(to)f(the)g(input)f(v)-5 b(alue)34 b(of)f(n)m(ulv)-5
+b(al)33 b(\(note)h(that)f(this)g(parameter)g(giv)m(es)i(the)e(address)0
+4224 y(of)40 b(n)m(ulv)-5 b(al,)44 b(not)c(the)g(n)m(ull)g(v)-5
+b(alue)41 b(itself)7 b(\).)72 b(F)-8 b(or)40 b(in)m(teger)i(columns)e
+(the)g(FITS)g(n)m(ull)g(v)-5 b(alue)40 b(is)h(de\014ned)e(b)m(y)h(the)0
+4337 y(TNULLn)32 b(k)m(eyw)m(ord)i(\(an)g(error)e(is)i(returned)e(if)h
+(the)h(k)m(eyw)m(ord)f(do)s(esn't)g(exist\).)51 b(F)-8
+b(or)34 b(\015oating)g(p)s(oin)m(t)f(columns)0 4449 y(the)h(sp)s(ecial)
+h(IEEE)f(NaN)h(\(Not-a-Num)m(b)s(er\))h(v)-5 b(alue)35
+b(will)f(b)s(e)g(written)g(in)m(to)i(the)e(FITS)g(\014le.)52
+b(If)34 b(a)h(n)m(ull)f(p)s(oin)m(ter)0 4562 y(is)f(en)m(tered)g(for)g
+(n)m(ulv)-5 b(al,)34 b(then)f(the)g(n)m(ull)g(v)-5 b(alue)33
+b(is)g(ignored)g(and)g(this)g(routine)f(b)s(eha)m(v)m(es)i(the)f(same)g
+(as)h(the)f(\014rst)0 4675 y(routine.)41 b(The)29 b(third)g(routine)h
+(simply)f(writes)h(unde\014ned)d(pixel)k(v)-5 b(alues)30
+b(to)g(the)g(column.)41 b(The)29 b(fourth)g(routine)0
+4788 y(\014lls)e(ev)m(ery)i(column)e(in)h(the)g(table)g(with)g(n)m(ull)
+f(v)-5 b(alues,)29 b(in)e(the)h(sp)s(eci\014ed)f(ro)m(ws)h(\(ignoring)g
+(an)m(y)g(columns)g(that)g(do)0 4901 y(not)j(ha)m(v)m(e)g(a)g
+(de\014ned)e(n)m(ull)h(v)-5 b(alue\).)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(LONGLONG)f(firstrow,)334
+5375 y(LONGLONG)h(firstelem,)f(LONGLONG)g(nelements,)g(DTYPE)i(*array,)
+e(>)j(int)f(*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(LONGLONG)f(firstrow,)p eop end
+%%Page: 55 63
+TeXDict begin 55 62 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(55)286 555 y Fe(LONGLONG)46 b(firstelem,)f(LONGLONG)g(nelements,)g
+(DTYPE)i(*array,)f(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(LONGLONG)g(firstrow,)f
+(LONGLONG)h(firstelem,)382 1120 y(LONGLONG)f(nelements,)g(>)j(int)f
+(*status\))143 1346 y(int)g(fits_write_nullrows)c(/)k(ffprwu)334
+1458 y(\(fitsfile)e(*fptr,)h(LONGLONG)g(firstrow,)f(LONGLONG)h
+(nelements,)f(>)i(int)g(*status\))0 1783 y Fi(2)81 b
+Fj(Read)33 b(elemen)m(ts)i(from)e(an)g(ASCI)s(I)f(or)i(binary)e(table)i
+(column.)50 b(The)33 b(data)h(t)m(yp)s(e)g(parameter)g(sp)s(eci\014es)f
+(the)227 1896 y(data)28 b(t)m(yp)s(e)g(of)g(the)f(`n)m(ulv)-5
+b(al')29 b(and)e(`arra)m(y')h(p)s(oin)m(ters;)h(Unde\014ned)c(arra)m(y)
+j(elemen)m(ts)h(will)f(b)s(e)f(returned)f(with)227 2009
+y(a)k(v)-5 b(alue)30 b(=)e(*n)m(ullv)-5 b(al,)31 b(\(note)f(that)g
+(this)f(parameter)h(giv)m(es)g(the)g(address)e(of)h(the)h(n)m(ull)f(v)
+-5 b(alue,)30 b(not)g(the)f(n)m(ull)227 2122 y(v)-5 b(alue)31
+b(itself)7 b(\))32 b(unless)e(n)m(ulv)-5 b(al)32 b(=)e(0)h(or)g(*n)m
+(ulv)-5 b(al)31 b(=)g(0,)g(in)f(whic)m(h)h(case)h(no)e(c)m(hec)m(king)j
+(for)d(unde\014ned)f(pixels)227 2235 y(will)34 b(b)s(e)f(p)s(erformed.)
+48 b(The)33 b(second)g(routine)h(is)f(similar)h(except)g(that)g(an)m(y)
+g(unde\014ned)d(pixels)j(will)g(ha)m(v)m(e)227 2347 y(the)d(corresp)s
+(onding)e(n)m(ullarra)m(y)i(elemen)m(t)h(set)f(equal)g(to)g(TR)m(UE)f
+(\(=)h(1\).)227 2530 y(An)m(y)c(column,)g(regardless)f(of)g(it's)h(in)m
+(trinsic)g(data)g(t)m(yp)s(e,)g(ma)m(y)g(b)s(e)e(read)i(as)f(a)g
+(string.)40 b(It)26 b(should)f(b)s(e)h(noted)227 2643
+y(ho)m(w)m(ev)m(er)32 b(that)f(reading)f(a)h(n)m(umeric)f(column)g(as)h
+(a)g(string)f(is)g(10)i(-)e(100)i(times)f(slo)m(w)m(er)g(than)f
+(reading)h(the)227 2756 y(same)22 b(column)g(as)f(a)h(n)m(um)m(b)s(er)e
+(due)h(to)i(the)e(large)i(o)m(v)m(erhead)g(in)e(constructing)h(the)g
+(formatted)g(strings.)37 b(The)227 2869 y(displa)m(y)26
+b(format)g(of)f(the)h(returned)e(strings)h(will)h(b)s(e)f(determined)g
+(b)m(y)g(the)h(TDISPn)e(k)m(eyw)m(ord,)j(if)e(it)h(exists,)227
+2982 y(otherwise)32 b(b)m(y)f(the)g(data)h(t)m(yp)s(e)f(of)g(the)g
+(column.)43 b(The)30 b(length)i(of)f(the)g(returned)f(strings)h(\(not)g
+(including)227 3095 y(the)26 b(n)m(ull)f(terminating)i(c)m(haracter\))g
+(can)f(b)s(e)f(determined)g(with)g(the)h(\014ts)p 2703
+3095 28 4 v 32 w(get)p 2855 3095 V 34 w(col)p 2999 3095
+V 34 w(displa)m(y)p 3311 3095 V 33 w(width)f(routine.)227
+3208 y(The)30 b(follo)m(wing)i(TDISPn)d(displa)m(y)i(formats)f(are)h
+(curren)m(tly)f(supp)s(orted:)418 3554 y Fe(Iw.m)142
+b(Integer)418 3667 y(Ow.m)g(Octal)47 b(integer)418 3780
+y(Zw.m)142 b(Hexadecimal)45 b(integer)418 3893 y(Fw.d)142
+b(Fixed)47 b(floating)e(point)418 4006 y(Ew.d)142 b(Exponential)45
+b(floating)h(point)418 4119 y(Dw.d)142 b(Exponential)45
+b(floating)h(point)418 4232 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
+4579 y Fj(where)24 b(w)h(is)f(the)h(width)f(in)g(c)m(haracters)i(of)f
+(the)g(displa)m(y)m(ed)g(v)-5 b(alues,)27 b(m)d(is)h(the)f(minim)m(um)g
+(n)m(um)m(b)s(er)g(of)g(digits)227 4692 y(displa)m(y)m(ed,)29
+b(and)e(d)g(is)h(the)f(n)m(um)m(b)s(er)g(of)g(digits)i(to)f(the)g(righ)
+m(t)g(of)f(the)h(decimal.)41 b(The)27 b(.m)g(\014eld)g(is)h(optional.)
+95 5016 y Fe(int)47 b(fits_read_col)e(/)i(ffgcv)286 5129
+y(\(fitsfile)f(*fptr,)g(int)h(datatype,)e(int)i(colnum,)f(LONGLONG)f
+(firstrow,)g(LONGLONG)h(firstelem,)334 5242 y(LONGLONG)g(nelements,)f
+(DTYPE)h(*nulval,)g(DTYPE)g(*array,)g(int)h(*anynul,)e(int)i(*status\))
+95 5468 y(int)g(fits_read_colnull)c(/)48 b(ffgcf)286
+5581 y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(int)i(colnum,)f
+(LONGLONG)f(firstrow,)g(LONGLONG)h(firstelem,)286 5694
+y(LONGLONG)g(nelements,)f(DTYPE)h(*array,)g(char)h(*nullarray,)d(int)j
+(*anynul,)f(int)h(*status\))p eop end
+%%Page: 56 64
+TeXDict begin 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)0 555 y Fd(5.7.5)112 b(Ro)m(w)37 b(Selection)h(and)h
+(Calculator)f(Routines)0 774 y Fj(These)21 b(routines)f(all)i(parse)f
+(and)f(ev)-5 b(aluate)23 b(an)d(input)g(string)h(con)m(taining)i(a)e
+(user)f(de\014ned)g(arithmetic)i(expression.)0 887 y(The)29
+b(\014rst)f(3)i(routines)f(select)i(ro)m(ws)e(in)g(a)h(FITS)e(table,)j
+(based)e(on)g(whether)g(the)g(expression)g(ev)-5 b(aluates)31
+b(to)f(true)0 1000 y(\(not)e(equal)f(to)h(zero\))g(or)f(false)h
+(\(zero\).)41 b(The)27 b(other)g(routines)g(ev)-5 b(aluate)29
+b(the)e(expression)g(and)f(calculate)k(a)d(v)-5 b(alue)0
+1113 y(for)26 b(eac)m(h)i(ro)m(w)f(of)g(the)g(table.)40
+b(The)26 b(allo)m(w)m(ed)j(expression)d(syn)m(tax)i(is)e(describ)s(ed)g
+(in)g(the)h(ro)m(w)g(\014lter)g(section)g(in)g(the)0
+1226 y(`Extended)32 b(File)h(Name)g(Syn)m(tax')g(c)m(hapter)g(of)f
+(this)g(do)s(cumen)m(t.)46 b(The)32 b(expression)g(ma)m(y)h(also)g(b)s
+(e)e(written)i(to)g(a)0 1339 y(text)h(\014le,)h(and)e(the)h(name)f(of)h
+(the)f(\014le,)i(prep)s(ended)c(with)i(a)h('@')g(c)m(haracter)h(ma)m(y)
+f(b)s(e)f(supplied)f(for)h(the)h('expr')0 1452 y(parameter)d(\(e.g.)42
+b('@\014lename.txt'\).)g(The)30 b(expression)g(in)g(the)g(\014le)h(can)
+f(b)s(e)g(arbitrarily)g(complex)h(and)f(extend)0 1564
+y(o)m(v)m(er)35 b(m)m(ultiple)g(lines)g(of)f(the)g(\014le.)53
+b(Lines)33 b(that)i(b)s(egin)f(with)g(2)g(slash)g(c)m(haracters)i
+(\('//'\))g(will)f(b)s(e)e(ignored)i(and)0 1677 y(ma)m(y)c(b)s(e)f
+(used)f(to)i(add)f(commen)m(ts)h(to)h(the)e(\014le.)0
+1925 y Fi(1)81 b Fj(Ev)-5 b(aluate)38 b(a)f(b)s(o)s(olean)g(expression)
+g(o)m(v)m(er)h(the)g(indicated)f(ro)m(ws,)i(returning)d(an)h(arra)m(y)h
+(of)f(\015ags)g(indicating)227 2038 y(whic)m(h)31 b(ro)m(ws)g(ev)-5
+b(aluated)32 b(to)f(TR)m(UE/F)-10 b(ALSE.)31 b(Up)s(on)f(return,)g(*n)p
+2518 2038 28 4 v 33 w(go)s(o)s(d)p 2743 2038 V 33 w(ro)m(ws)g(con)m
+(tains)i(the)f(n)m(um)m(b)s(er)f(of)227 2151 y(ro)m(ws)h(that)g(ev)-5
+b(aluate)32 b(to)f(TR)m(UE.)95 2399 y Fe(int)47 b(fits_find_rows)d(/)k
+(fffrow)286 2512 y(\(fitsfile)e(*fptr,)93 b(char)47 b(*expr,)f(long)h
+(firstrow,)e(long)i(nrows,)286 2625 y(>)h(long)e(*n_good_rows,)f(char)h
+(*row_status,)92 b(int)47 b(*status\))0 2872 y Fi(2)81
+b Fj(Find)29 b(the)i(\014rst)f(ro)m(w)g(whic)m(h)g(satis\014es)h(the)g
+(input)e(b)s(o)s(olean)h(expression)95 3120 y Fe(int)47
+b(fits_find_first_row)c(/)k(ffffrw)286 3233 y(\(fitsfile)f(*fptr,)93
+b(char)47 b(*expr,)f(>)i(long)e(*rownum,)g(int)h(*status\))0
+3481 y Fi(3)81 b Fj(Ev)-5 b(aluate)35 b(an)f(expression)h(on)f(all)h
+(ro)m(ws)g(of)f(a)h(table.)54 b(If)34 b(the)g(input)g(and)g(output)g
+(\014les)g(are)h(not)g(the)f(same,)227 3594 y(cop)m(y)i(the)g(TR)m(UE)f
+(ro)m(ws)g(to)h(the)f(output)g(\014le;)j(if)d(the)g(output)g(table)h
+(is)f(not)h(empt)m(y)-8 b(,)37 b(then)e(this)g(routine)227
+3707 y(will)28 b(app)s(end)e(the)i(new)f(selected)i(ro)m(ws)e(after)h
+(the)g(existing)h(ro)m(ws.)39 b(If)27 b(the)h(\014les)g(are)f(the)h
+(same,)h(delete)g(the)227 3819 y(F)-10 b(ALSE)30 b(ro)m(ws)h(\(preserv)
+m(e)f(the)h(TR)m(UE)f(ro)m(ws\).)95 4067 y Fe(int)47
+b(fits_select_rows)d(/)j(ffsrow)286 4180 y(\(fitsfile)f(*infptr,)f
+(fitsfile)h(*outfptr,)93 b(char)46 b(*expr,)94 b(>)48
+b(int)f(*status)e(\))0 4428 y Fi(4)81 b Fj(Calculate)28
+b(an)f(expression)f(for)h(the)f(indicated)i(ro)m(ws)e(of)h(a)g(table,)i
+(returning)d(the)h(results,)g(cast)h(as)f(datat)m(yp)s(e)227
+4541 y(\(TSHOR)-8 b(T,)32 b(TDOUBLE,)h(etc\),)h(in)e(arra)m(y)-8
+b(.)48 b(If)31 b(n)m(ulv)-5 b(al==NULL,)33 b(UNDEFs)g(will)f(b)s(e)g
+(zero)s(ed)g(out.)47 b(F)-8 b(or)227 4654 y(v)m(ector)37
+b(results,)f(the)f(n)m(um)m(b)s(er)e(of)i(elemen)m(ts)i(returned)c(ma)m
+(y)j(b)s(e)e(less)h(than)g(nelemen)m(ts)g(if)g(nelemen)m(ts)h(is)227
+4767 y(not)c(an)g(ev)m(en)h(m)m(ultiple)f(of)g(the)g(result)g
+(dimension.)44 b(Call)33 b(\014ts)p 2392 4767 V 32 w(test)p
+2570 4767 V 34 w(expr)e(to)h(obtain)h(the)f(dimensions)f(of)227
+4880 y(the)g(results.)95 5127 y Fe(int)47 b(fits_calc_rows)d(/)k
+(ffcrow)286 5240 y(\(fitsfile)e(*fptr,)93 b(int)47 b(datatype,)f(char)g
+(*expr,)g(long)h(firstrow,)334 5353 y(long)g(nelements,)e(void)h
+(*nulval,)g(>)h(void)g(*array,)94 b(int)46 b(*anynul,)g(int)h
+(*status\))0 5601 y Fi(5)81 b Fj(Ev)-5 b(aluate)33 b(an)g(expression)f
+(and)h(write)f(the)h(result)g(either)g(to)h(a)f(column)f(\(if)h(the)g
+(expression)f(is)h(a)g(function)227 5714 y(of)d(other)g(columns)g(in)f
+(the)h(table\))h(or)f(to)g(a)h(k)m(eyw)m(ord)f(\(if)g(the)g(expression)
+f(ev)-5 b(aluates)32 b(to)e(a)g(constan)m(t)i(and)p eop
+end
+%%Page: 57 65
+TeXDict begin 57 64 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(57)227 555 y(is)31 b(not)f(a)h(function)f(of)h(other)f(columns)h
+(in)f(the)g(table\).)42 b(In)30 b(the)h(former)e(case,)j(the)f(parName)
+f(parameter)227 668 y(is)40 b(the)g(name)f(of)h(the)g(column)f(\(whic)m
+(h)h(ma)m(y)g(or)f(ma)m(y)h(not)g(already)g(exist\))h(in)m(to)f(whic)m
+(h)g(to)g(write)g(the)227 781 y(results,)e(and)f(parInfo)e(con)m(tains)
+j(an)f(optional)g(TF)m(ORM)g(k)m(eyw)m(ord)g(v)-5 b(alue)38
+b(if)e(a)h(new)f(column)h(is)f(b)s(eing)227 894 y(created.)42
+b(If)28 b(a)h(TF)m(ORM)h(v)-5 b(alue)29 b(is)g(not)g(sp)s(eci\014ed)g
+(then)f(a)i(default)f(format)g(will)h(b)s(e)e(used,)h(dep)s(ending)e
+(on)227 1007 y(the)35 b(expression.)54 b(If)34 b(the)h(expression)f(ev)
+-5 b(aluates)37 b(to)e(a)g(constan)m(t,)i(then)e(the)g(result)f(will)h
+(b)s(e)f(written)h(to)227 1120 y(the)28 b(k)m(eyw)m(ord)g(name)f(giv)m
+(en)h(b)m(y)g(the)f(parName)h(parameter,)h(and)d(the)i(parInfo)e
+(parameter)i(ma)m(y)g(b)s(e)f(used)227 1233 y(to)k(supply)e(an)h
+(optional)i(commen)m(t)f(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)h(exist,)g
+(then)227 1346 y(the)f(name)f(of)h(the)g(k)m(eyw)m(ord)g(m)m(ust)f(b)s
+(e)g(preceded)g(with)g(a)h('#')f(c)m(haracter,)j(otherwise)e(the)f
+(result)h(will)g(b)s(e)227 1458 y(written)h(to)g(a)g(column)f(with)g
+(that)h(name.)95 1719 y Fe(int)47 b(fits_calculator)d(/)j(ffcalc)286
+1832 y(\(fitsfile)f(*infptr,)f(char)i(*expr,)f(fitsfile)f(*outfptr,)h
+(char)g(*parName,)334 1945 y(char)h(*parInfo,)e(>)95
+b(int)47 b(*status\))0 2205 y Fi(6)81 b Fj(This)38 b(calculator)k
+(routine)e(is)f(similar)h(to)g(the)g(previous)f(routine,)j(except)f
+(that)f(the)g(expression)f(is)h(only)227 2318 y(ev)-5
+b(aluated)42 b(o)m(v)m(er)f(the)f(sp)s(eci\014ed)g(ro)m(w)g(ranges.)70
+b(nranges)39 b(sp)s(eci\014es)h(the)g(n)m(um)m(b)s(er)f(of)h(ro)m(w)h
+(ranges,)i(and)227 2431 y(\014rstro)m(w)30 b(and)g(lastro)m(w)h(giv)m
+(e)h(the)f(starting)g(and)f(ending)g(ro)m(w)g(n)m(um)m(b)s(er)f(of)i
+(eac)m(h)g(range.)95 2691 y Fe(int)47 b(fits_calculator_rng)c(/)k
+(ffcalc_rng)286 2804 y(\(fitsfile)f(*infptr,)f(char)i(*expr,)f
+(fitsfile)f(*outfptr,)h(char)g(*parName,)334 2917 y(char)h(*parInfo,)e
+(int)i(nranges,)e(long)i(*firstrow,)e(long)i(*lastrow)334
+3030 y(>)95 b(int)47 b(*status\))0 3290 y Fi(7)81 b Fj(Ev)-5
+b(aluate)36 b(the)f(giv)m(en)h(expression)f(and)g(return)f(dimension)g
+(and)h(t)m(yp)s(e)g(information)g(on)g(the)h(result.)54
+b(The)227 3403 y(returned)37 b(dimensions)f(corresp)s(ond)g(to)j(a)e
+(single)i(ro)m(w)e(en)m(try)h(of)f(the)h(requested)f(expression,)j(and)
+d(are)227 3516 y(equiv)-5 b(alen)m(t)26 b(to)f(the)g(result)f(of)g
+(\014ts)p 1380 3516 28 4 v 33 w(read)p 1585 3516 V 32
+w(tdim\(\).)40 b(Note)25 b(that)g(strings)f(are)h(considered)f(to)h(b)s
+(e)f(one)g(elemen)m(t)227 3629 y(regardless)31 b(of)g(string)f(length.)
+41 b(If)30 b(maxdim)g(==)g(0,)h(then)f(naxes)g(is)h(optional.)95
+3889 y Fe(int)47 b(fits_test_expr)d(/)k(fftexp)286 4002
+y(\(fitsfile)e(*fptr,)g(char)g(*expr,)g(int)h(maxdim)f(>)i(int)f
+(*datatype,)e(long)h(*nelem,)g(int)h(*naxis,)334 4115
+y(long)g(*naxes,)f(int)g(*status\))0 4407 y Fd(5.7.6)112
+b(Column)39 b(Binning)f(or)f(Histogramming)i(Routines)0
+4626 y Fj(The)30 b(follo)m(wing)j(routines)e(ma)m(y)g(b)s(e)g(useful)f
+(when)g(p)s(erforming)g(histogramming)h(op)s(erations)h(on)e
+(column\(s\))i(of)0 4738 y(a)f(table)g(to)g(generate)h(an)e(image)i(in)
+e(a)h(primary)e(arra)m(y)i(or)f(image)i(extension.)0
+4999 y Fi(1)81 b Fj(Calculate)27 b(the)e(histogramming)h(parameters)g
+(\(min,)h(max,)f(and)f(bin)g(size)h(for)f(eac)m(h)i(axis)f(of)f(the)h
+(histogram,)227 5112 y(based)38 b(on)g(a)g(v)-5 b(ariet)m(y)39
+b(of)f(p)s(ossible)g(input)f(parameters.)64 b(If)37 b(the)h(input)f
+(names)h(of)g(the)g(columns)g(to)h(b)s(e)227 5225 y(binned)d(are)i(n)m
+(ull,)h(then)e(the)h(routine)f(will)h(\014rst)f(lo)s(ok)h(for)f(the)h
+(CPREF)f(=)g("NAME1,)j(NAME2,)h(...")227 5337 y(k)m(eyw)m(ord)34
+b(whic)m(h)f(lists)h(the)g(preferred)e(columns.)50 b(If)32
+b(not)i(presen)m(t,)h(then)e(the)g(routine)h(will)g(assume)f(the)227
+5450 y(column)d(names)h(X,)f(Y,)h(Z,)f(and)g(T)g(for)g(up)g(to)h(4)f
+(axes)h(\(as)g(sp)s(eci\014ed)f(b)m(y)g(the)h(NAXIS)f(parameter\).)227
+5601 y(MININ)39 b(and)f(MAXIN)h(are)g(input)e(arra)m(ys)i(that)g(giv)m
+(e)h(the)f(minim)m(um)e(and)h(maxim)m(um)h(v)-5 b(alue)39
+b(for)f(the)227 5714 y(histogram,)30 b(along)f(eac)m(h)g(axis.)40
+b(Alternativ)m(ely)-8 b(,)32 b(the)c(name)g(of)h(k)m(eyw)m(ords)f(that)
+h(giv)m(e)g(the)f(min,)h(max,)g(and)p eop end
+%%Page: 58 66
+TeXDict begin 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)227 555 y Fj(binsize)e(ma)m(y)g(b)s(e)f(giv)m(e)h(with)f
+(the)h(MINNAME,)h(MAXNAME,)f(and)f(BINNAME)h(arra)m(y)g(parameters.)40
+b(If)227 668 y(the)33 b(v)-5 b(alue)34 b(=)e(DOUBLENULL)-10
+b(V)g(ALUE)33 b(and)g(no)f(k)m(eyw)m(ord)i(names)e(are)h(giv)m(en,)i
+(then)e(the)g(routine)g(will)227 781 y(use)i(the)f(TLMINn)g(and)g
+(TLMAXn)g(k)m(eyw)m(ords,)j(if)d(presen)m(t,)i(or)f(the)f(actual)i(min)
+e(and/or)h(max)g(v)-5 b(alues)227 894 y(in)30 b(the)h(column.)227
+1046 y(BINSIZEIN)j(is)h(an)g(arra)m(y)g(giving)h(the)f(binsize)g(along)
+h(eac)m(h)g(axis.)55 b(If)34 b(the)h(v)-5 b(alue)36 b(=)e(DOUBLENULL-)
+227 1159 y(V)-10 b(ALUE,)38 b(and)e(a)i(k)m(eyw)m(ord)f(name)g(is)h
+(not)f(sp)s(eci\014ed)f(with)h(BINNAME,)h(then)f(this)g(routine)g(will)
+h(\014rst)227 1272 y(lo)s(ok)d(for)f(the)g(TDBINn)g(k)m(eyw)m(ord,)i
+(or)f(else)g(will)f(use)g(a)h(binsize)f(=)g(1,)h(or)g(a)f(binsize)g
+(that)h(pro)s(duces)e(10)227 1385 y(histogram)e(bins,)f(whic)m(h)g(ev)m
+(er)h(is)g(smaller.)95 1649 y Fe(int)47 b(fits_calc_binning)143
+1761 y(Input)g(parameters:)239 1874 y(\(fitsfile)e(*fptr,)94
+b(/*)47 b(IO)g(-)h(pointer)d(to)j(table)e(to)h(be)g(binned)667
+b(*/)286 1987 y(int)47 b(naxis,)333 b(/*)47 b(I)g(-)h(number)e(of)h
+(axes/columns)e(in)i(the)g(binned)f(image)94 b(*/)286
+2100 y(char)47 b(colname[4][FLEN_VALUE],)137 b(/*)47
+b(I)h(-)f(optional)f(column)g(names)428 b(*/)286 2213
+y(double)46 b(*minin,)237 b(/*)47 b(I)h(-)f(optional)f(lower)g(bound)h
+(value)f(for)h(each)f(axis)95 b(*/)286 2326 y(double)46
+b(*maxin,)237 b(/*)47 b(I)h(-)f(optional)f(upper)g(bound)h(value,)f
+(for)h(each)f(axis)h(*/)286 2439 y(double)f(*binsizein,)f(/*)i(I)h(-)f
+(optional)f(bin)h(size)f(along)h(each)f(axis)429 b(*/)286
+2552 y(char)47 b(minname[4][FLEN_VALUE],)41 b(/*)48 b(I)f(-)h(optional)
+d(keywords)h(for)h(min)333 b(*/)286 2665 y(char)47 b
+(maxname[4][FLEN_VALUE],)41 b(/*)48 b(I)f(-)h(optional)d(keywords)h
+(for)h(max)333 b(*/)286 2778 y(char)47 b(binname[4][FLEN_VALUE],)41
+b(/*)48 b(I)f(-)h(optional)d(keywords)h(for)h(binsize)141
+b(*/)143 2891 y(Output)46 b(parameters:)286 3003 y(int)h(*colnum,)237
+b(/*)47 b(O)g(-)h(column)e(numbers,)f(to)j(be)f(binned)f(*/)286
+3116 y(long)h(*naxes,)237 b(/*)47 b(O)g(-)h(number)e(of)h(bins)g(in)g
+(each)g(histogram)e(axis)h(*/)286 3229 y(float)h(*amin,)237
+b(/*)47 b(O)g(-)h(lower)e(bound)h(of)g(the)g(histogram)e(axes)i(*/)286
+3342 y(float)g(*amax,)237 b(/*)47 b(O)g(-)h(upper)e(bound)h(of)g(the)g
+(histogram)e(axes)i(*/)286 3455 y(float)g(*binsize,)93
+b(/*)47 b(O)g(-)h(width)e(of)h(histogram)f(bins/pixels)e(on)k(each)e
+(axis)h(*/)286 3568 y(int)g(*status\))0 3832 y Fi(2)81
+b Fj(Cop)m(y)26 b(the)h(relev)-5 b(an)m(t)28 b(k)m(eyw)m(ords)f(from)g
+(the)g(header)f(of)h(the)g(table)h(that)f(is)g(b)s(eing)f(binned,)h(to)
+g(the)g(the)g(header)227 3945 y(of)e(the)h(output)e(histogram)i(image.)
+40 b(This)24 b(will)i(not)f(cop)m(y)h(the)f(table)h(structure)f(k)m
+(eyw)m(ords)g(\(e.g.,)j(NAXIS,)227 4057 y(TF)m(ORMn,)j(TTYPEn,)f
+(etc.\))44 b(nor)31 b(will)g(it)g(cop)m(y)h(the)f(k)m(eyw)m(ords)g
+(that)h(apply)e(to)i(other)f(columns)g(of)g(the)227 4170
+y(table)g(that)g(are)f(not)h(used)e(to)i(create)g(the)f(histogram.)42
+b(This)29 b(routine)h(will)g(translate)h(the)g(names)f(of)g(the)227
+4283 y(W)-8 b(orld)27 b(Co)s(ordinate)e(System)h(\(W)m(CS\))g(k)m(eyw)m
+(ords)g(for)g(the)g(binned)e(columns)h(in)m(to)i(the)f(form)f(that)h
+(is)g(need)227 4396 y(for)h(a)g(FITS)g(image)h(\(e.g.,)h(the)e(TCTYPn)f
+(table)i(k)m(eyw)m(ord)f(will)g(b)s(e)g(translated)g(to)h(the)f(CTYPEn)
+f(image)227 4509 y(k)m(eyw)m(ord\).)95 4773 y Fe(int)47
+b(fits_copy_pixlist2image)286 4886 y(\(fitsfile)f(*infptr,)141
+b(/*)47 b(I)g(-)h(pointer)e(to)h(input)f(HDU)h(*/)334
+4999 y(fitsfile)f(*outfptr,)93 b(/*)47 b(I)g(-)h(pointer)e(to)h(output)
+f(HDU)h(*/)334 5111 y(int)g(firstkey,)332 b(/*)47 b(I)g(-)h(first)e
+(HDU)h(keyword)f(to)h(start)f(with)h(*/)334 5224 y(int)g(naxis,)476
+b(/*)47 b(I)g(-)h(number)e(of)h(axes)g(in)g(the)g(image)f(*/)334
+5337 y(int)h(*colnum,)380 b(/*)47 b(I)g(-)h(numbers)e(of)h(the)g
+(columns)e(to)j(be)f(binned)94 b(*/)334 5450 y(int)47
+b(*status\))380 b(/*)47 b(IO)g(-)g(error)g(status)f(*/)0
+5714 y Fi(3)81 b Fj(W)-8 b(rite)36 b(a)f(set)h(of)f(default)h(W)m(CS)f
+(k)m(eyw)m(ords)g(to)h(the)f(histogram)h(header,)g(IF)f(the)g(W)m(CS)g
+(k)m(eyw)m(ords)h(do)f(not)p eop end
+%%Page: 59 67
+TeXDict begin 59 66 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(59)227 555 y(already)40 b(exist.)69 b(This)38 b(will)i(create)h(a)
+e(linear)h(W)m(CS)f(where)g(the)h(co)s(ordinate)g(t)m(yp)s(es)f(are)h
+(equal)g(to)g(the)227 668 y(original)32 b(column)e(names.)95
+953 y Fe(int)47 b(fits_write_keys_histo)239 1066 y(\(fitsfile)e(*fptr,)
+237 b(/*)47 b(I)h(-)f(pointer)f(to)h(table)f(to)i(be)f(binned)666
+b(*/)286 1179 y(fitsfile)46 b(*histptr,)93 b(/*)47 b(I)h(-)f(pointer)f
+(to)h(output)f(histogram)f(image)i(HDU)285 b(*/)286 1292
+y(int)47 b(naxis,)476 b(/*)47 b(I)h(-)f(number)f(of)h(axes)g(in)g(the)g
+(histogram)e(image)285 b(*/)286 1405 y(int)47 b(*colnum,)380
+b(/*)47 b(I)h(-)f(column)f(numbers)g(of)h(the)g(binned)f(columns)332
+b(*/)286 1518 y(int)47 b(*status\))0 1803 y Fi(4)81 b
+Fj(Up)s(date)29 b(the)i(W)m(CS)f(k)m(eyw)m(ords)g(in)g(a)g(histogram)h
+(image)g(header)f(that)h(giv)m(e)g(the)f(lo)s(cation)i(of)e(the)g
+(reference)227 1916 y(pixel)h(\(CRPIXn\),)f(and)g(the)h(pixel)f(size)h
+(\(CDEL)-8 b(Tn\),)31 b(in)f(the)h(binned)e(image.)95
+2201 y Fe(int)47 b(fits_rebin_wcs)239 2314 y(\(fitsfile)e(*fptr,)237
+b(/*)47 b(I)h(-)f(pointer)f(to)h(table)f(to)i(be)f(binned)523
+b(*/)286 2426 y(int)47 b(naxis,)476 b(/*)47 b(I)h(-)f(number)f(of)h
+(axes)g(in)g(the)g(histogram)e(image)142 b(*/)286 2539
+y(float)47 b(*amin,)380 b(/*)47 b(I)h(-)f(first)f(pixel)h(include)f(in)
+h(each)f(axis)381 b(*/)286 2652 y(float)47 b(*binsize,)236
+b(/*)47 b(I)h(-)f(binning)f(factor)g(for)h(each)f(axis)572
+b(*/)286 2765 y(int)47 b(*status\))0 3050 y Fi(5)81 b
+Fj(Bin)33 b(the)h(v)-5 b(alues)35 b(in)e(the)h(input)f(table)h
+(columns,)h(and)e(write)h(the)g(histogram)h(arra)m(y)f(to)g(the)g
+(output)g(FITS)227 3163 y(image)e(\(histptr\).)95 3448
+y Fe(int)47 b(fits_make_hist)143 3561 y(\(fitsfile)e(*fptr,)190
+b(/*)47 b(I)g(-)h(pointer)e(to)h(table)f(with)h(X)g(and)g(Y)h(cols;)285
+b(*/)191 3674 y(fitsfile)45 b(*histptr,)h(/*)h(I)g(-)h(pointer)e(to)h
+(output)f(FITS)h(image)619 b(*/)191 3787 y(int)47 b(bitpix,)380
+b(/*)47 b(I)g(-)h(datatype)d(for)i(image:)f(16,)h(32,)g(-32,)g(etc)238
+b(*/)191 3900 y(int)47 b(naxis,)428 b(/*)47 b(I)g(-)h(number)e(of)h
+(axes)g(in)g(the)g(histogram)e(image)190 b(*/)191 4013
+y(long)47 b(*naxes,)332 b(/*)47 b(I)g(-)h(size)e(of)i(axes)e(in)h(the)g
+(histogram)f(image)285 b(*/)191 4126 y(int)47 b(*colnum,)332
+b(/*)47 b(I)g(-)h(column)e(numbers)g(\(array)g(length)g(=)h(naxis\))190
+b(*/)191 4238 y(float)46 b(*amin,)333 b(/*)47 b(I)g(-)h(minimum)e
+(histogram)f(value,)h(for)h(each)g(axis)142 b(*/)191
+4351 y(float)46 b(*amax,)333 b(/*)47 b(I)g(-)h(maximum)e(histogram)f
+(value,)h(for)h(each)g(axis)142 b(*/)191 4464 y(float)46
+b(*binsize,)189 b(/*)47 b(I)g(-)h(bin)f(size)f(along)h(each)f(axis)811
+b(*/)191 4577 y(float)46 b(weight,)285 b(/*)47 b(I)g(-)h(binning)e
+(weighting)f(factor)h(\(FLOATNULLVALUE)e(*/)1098 4690
+y(/*)238 b(for)47 b(no)g(weighting\))1143 b(*/)191 4803
+y(int)47 b(wtcolnum,)284 b(/*)47 b(I)g(-)h(keyword)e(or)h(col)g(for)g
+(weight)284 b(\(or)47 b(NULL\))g(*/)191 4916 y(int)g(recip,)428
+b(/*)47 b(I)g(-)h(use)f(reciprocal)e(of)i(the)g(weight?)f(0)h(or)g(1)
+239 b(*/)191 5029 y(char)47 b(*selectrow,)140 b(/*)47
+b(I)g(-)h(optional)d(array)i(\(length)f(=)h(no.)g(of)477
+b(*/)1098 5142 y(/*)47 b(rows)g(in)g(the)g(table\).)93
+b(If)47 b(the)g(element)f(is)h(true)95 b(*/)1098 5255
+y(/*)47 b(then)g(the)f(corresponding)f(row)i(of)g(the)g(table)f(will)h
+(*/)1098 5368 y(/*)g(be)g(included)f(in)h(the)g(histogram,)e(otherwise)
+g(the)95 b(*/)1098 5480 y(/*)47 b(row)g(will)f(be)i(skipped.)93
+b(Ingnored)45 b(if)j(*selectrow)d(*/)1098 5593 y(/*)i(is)g(equal)f(to)i
+(NULL.)1335 b(*/)191 5706 y(int)47 b(*status\))p eop
+end
+%%Page: 60 68
+TeXDict begin 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)0 555 y Ff(5.8)135 b(Utilit)l(y)47 b(Routines)0
+809 y Fd(5.8.1)112 b(File)39 b(Chec)m(ksum)f(Routines)0
+1028 y Fj(The)33 b(follo)m(wing)h(routines)f(either)h(compute)f(or)h(v)
+-5 b(alidate)34 b(the)g(c)m(hec)m(ksums)f(for)g(the)h(CHDU.)g(The)e(D)m
+(A)-8 b(T)g(ASUM)0 1140 y(k)m(eyw)m(ord)33 b(is)f(used)f(to)i(store)f
+(the)h(n)m(umerical)f(v)-5 b(alue)33 b(of)f(the)g(32-bit,)i(1's)f
+(complemen)m(t)g(c)m(hec)m(ksum)g(for)f(the)g(data)0
+1253 y(unit)26 b(alone.)40 b(If)25 b(there)h(is)h(no)e(data)i(unit)f
+(then)f(the)h(v)-5 b(alue)27 b(is)f(set)g(to)h(zero.)40
+b(The)26 b(n)m(umerical)g(v)-5 b(alue)27 b(is)f(stored)g(as)g(an)0
+1366 y(ASCI)s(I)20 b(string)i(of)h(digits,)h(enclosed)f(in)e(quotes,)k
+(b)s(ecause)d(the)g(v)-5 b(alue)23 b(ma)m(y)f(b)s(e)f(to)s(o)i(large)g
+(to)g(represen)m(t)f(as)g(a)h(32-bit)0 1479 y(signed)28
+b(in)m(teger.)41 b(The)27 b(CHECKSUM)g(k)m(eyw)m(ord)i(is)f(used)f(to)h
+(store)h(the)f(ASCI)s(I)e(enco)s(ded)i(COMPLEMENT)f(of)0
+1592 y(the)f(c)m(hec)m(ksum)h(for)f(the)h(en)m(tire)g(HDU.)g(Storing)f
+(the)h(complemen)m(t,)h(rather)e(than)g(the)h(actual)g(c)m(hec)m(ksum,)
+h(forces)0 1705 y(the)k(c)m(hec)m(ksum)h(for)f(the)h(whole)f(HDU)h(to)g
+(equal)g(zero.)47 b(If)31 b(the)i(\014le)f(has)g(b)s(een)f(mo)s
+(di\014ed)g(since)i(the)f(c)m(hec)m(ksums)0 1818 y(w)m(ere)39
+b(computed,)i(then)e(the)g(HDU)g(c)m(hec)m(ksum)h(will)f(usually)f(not)
+h(equal)h(zero.)66 b(These)39 b(c)m(hec)m(ksum)g(k)m(eyw)m(ord)0
+1931 y(con)m(v)m(en)m(tions)34 b(are)f(based)f(on)g(a)g(pap)s(er)f(b)m
+(y)h(Rob)g(Seaman)g(published)f(in)h(the)g(pro)s(ceedings)g(of)g(the)h
+(AD)m(ASS)f(IV)0 2044 y(conference)h(in)e(Baltimore)j(in)d(No)m(v)m(em)
+m(b)s(er)i(1994)h(and)d(a)h(later)h(revision)f(in)f(June)g(1995.)47
+b(See)32 b(App)s(endix)e(B)i(for)0 2157 y(the)f(de\014nition)f(of)g
+(the)h(parameters)f(used)g(in)g(these)h(routines.)0 2407
+y Fi(1)81 b Fj(Compute)33 b(and)g(write)h(the)g(D)m(A)-8
+b(T)g(ASUM)35 b(and)e(CHECKSUM)g(k)m(eyw)m(ord)h(v)-5
+b(alues)34 b(for)f(the)h(CHDU)g(in)m(to)h(the)227 2520
+y(curren)m(t)d(header.)46 b(If)32 b(the)g(k)m(eyw)m(ords)h(already)g
+(exist,)g(their)g(v)-5 b(alues)32 b(will)h(b)s(e)e(up)s(dated)g(only)h
+(if)h(necessary)227 2633 y(\(i.e.,)f(if)f(the)f(\014le)h(has)f(b)s(een)
+f(mo)s(di\014ed)h(since)g(the)h(original)h(k)m(eyw)m(ord)e(v)-5
+b(alues)31 b(w)m(ere)g(computed\).)95 2883 y Fe(int)47
+b(fits_write_chksum)c(/)48 b(ffpcks)286 2996 y(\(fitsfile)e(*fptr,)g(>)
+h(int)g(*status\))0 3246 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)29 b(in)f(the)h(CHDU,)g
+(assuming)f(that)h(the)f(D)m(A)-8 b(T)g(ASUM)30 b(k)m(eyw)m(ord)227
+3359 y(exists)36 b(and)f(already)h(has)f(the)h(correct)g(v)-5
+b(alue.)56 b(This)35 b(routine)g(calculates)j(the)e(new)f(c)m(hec)m
+(ksum)h(for)f(the)227 3471 y(curren)m(t)40 b(header)g(unit,)j(adds)c
+(it)i(to)g(the)f(data)h(unit)f(c)m(hec)m(ksum,)k(enco)s(des)c(the)g(v)
+-5 b(alue)41 b(in)m(to)g(an)f(ASCI)s(I)227 3584 y(string,)31
+b(and)f(writes)g(the)h(string)f(to)h(the)g(CHECKSUM)e(k)m(eyw)m(ord.)95
+3834 y Fe(int)47 b(fits_update_chksum)c(/)48 b(ffupck)286
+3947 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*status\))0 4197
+y Fi(3)81 b Fj(V)-8 b(erify)35 b(the)f(CHDU)h(b)m(y)g(computing)f(the)h
+(c)m(hec)m(ksums)g(and)f(comparing)h(them)f(with)g(the)h(k)m(eyw)m
+(ords.)53 b(The)227 4310 y(data)34 b(unit)f(is)g(v)m(eri\014ed)g
+(correctly)h(if)f(the)h(computed)f(c)m(hec)m(ksum)g(equals)h(the)f(v)-5
+b(alue)34 b(of)f(the)g(D)m(A)-8 b(T)g(ASUM)227 4423 y(k)m(eyw)m(ord.)64
+b(The)37 b(c)m(hec)m(ksum)i(for)f(the)g(en)m(tire)g(HDU)h(\(header)f
+(plus)f(data)i(unit\))e(is)h(correct)h(if)f(it)h(equals)227
+4536 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)g(this)g(routine)g(are)g(in)m(tegers)i
+(whic)m(h)e(will)227 4649 y(ha)m(v)m(e)k(a)f(v)-5 b(alue)35
+b(=)f(1)h(if)f(the)h(data)g(or)f(HDU)h(is)g(v)m(eri\014ed)f(correctly)
+-8 b(,)38 b(a)d(v)-5 b(alue)35 b(=)f(0)h(if)f(the)h(D)m(A)-8
+b(T)g(ASUM)36 b(or)227 4762 y(CHECKSUM)29 b(k)m(eyw)m(ord)g(is)h(not)f
+(presen)m(t,)h(or)f(v)-5 b(alue)30 b(=)f(-1)h(if)f(the)h(computed)f(c)m
+(hec)m(ksum)h(is)f(not)h(correct.)95 5125 y Fe(int)47
+b(fits_verify_chksum)c(/)48 b(ffvcks)286 5238 y(\(fitsfile)e(*fptr,)g
+(>)h(int)g(*dataok,)f(int)h(*hduok,)e(int)i(*status\))0
+5488 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)41 b(for)g(the)g(CHDU)g(without)g(creating)h(or)f(mo)s
+(difying)f(the)227 5601 y(CHECKSUM)33 b(and)h(D)m(A)-8
+b(T)g(ASUM)35 b(k)m(eyw)m(ords.)52 b(This)33 b(routine)h(is)g(used)f
+(in)m(ternally)i(b)m(y)f(\013v)m(c)m(ks,)i(but)d(ma)m(y)227
+5714 y(b)s(e)d(useful)g(in)g(other)g(situations)h(as)g(w)m(ell.)p
+eop end
+%%Page: 61 69
+TeXDict begin 61 68 bop 0 299 a Fh(5.8.)72 b(UTILITY)30
+b(R)m(OUTINES)2693 b Fj(61)95 555 y Fe(int)47 b(fits_get_chksum/)d
+(/ffgcks)286 668 y(\(fitsfile)i(*fptr,)g(>)h(unsigned)f(long)g
+(*datasum,)g(unsigned)f(long)i(*hdusum,)334 781 y(int)g(*status\))0
+1022 y Fi(5)81 b Fj(Enco)s(de)23 b(a)h(c)m(hec)m(ksum)g(v)-5
+b(alue)24 b(in)m(to)g(a)g(16-c)m(haracter)j(string.)38
+b(If)23 b(complm)h(is)f(non-zero)i(\(true\))f(then)f(the)h(32-bit)227
+1135 y(sum)30 b(v)-5 b(alue)31 b(will)f(b)s(e)g(complemen)m(ted)h(b)s
+(efore)f(enco)s(ding.)95 1376 y Fe(int)47 b(fits_encode_chksum)c(/)48
+b(ffesum)286 1489 y(\(unsigned)e(long)g(sum,)h(int)g(complm,)f(>)h
+(char)g(*ascii\);)0 1730 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)f(in)m(to)g(a)h
+(unsigned)e(long)h(v)-5 b(alue.)39 b(If)23 b(is)g(non-zero)g(\(true\).)
+39 b(then)23 b(the)227 1842 y(32-bit)33 b(sum)d(v)-5
+b(alue)32 b(will)g(b)s(e)f(complemen)m(ted)h(after)g(deco)s(ding.)44
+b(The)31 b(c)m(hec)m(ksum)h(v)-5 b(alue)32 b(is)g(also)g(returned)227
+1955 y(as)f(the)f(v)-5 b(alue)31 b(of)g(the)f(function.)95
+2196 y Fe(unsigned)46 b(long)h(fits_decode_chksum)42
+b(/)48 b(ffdsum)525 2309 y(\(char)e(*ascii,)g(int)h(complm,)f(>)h
+(unsigned)f(long)h(*sum\);)0 2597 y Fd(5.8.2)112 b(Date)38
+b(and)g(Time)g(Utilit)m(y)f(Routines)0 2816 y Fj(The)29
+b(follo)m(wing)i(routines)f(help)f(to)i(construct)f(or)f(parse)h(the)g
+(FITS)f(date/time)i(strings.)41 b(Starting)30 b(in)f(the)h(y)m(ear)0
+2929 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)31 b(\(and)h(the)f(v)-5 b(alues)32 b(of)f(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
+3042 y(form)j('YYYY-MM-DD')k(\(date)e(only\))f(or)g
+('YYYY-MM-DDThh:mm:ss.ddd...')61 b(\(date)38 b(and)e(time\))h(where)0
+3154 y(the)30 b(n)m(um)m(b)s(er)f(of)i(decimal)g(places)g(in)f(the)g
+(seconds)g(v)-5 b(alue)31 b(is)f(optional.)42 b(These)30
+b(times)h(are)f(in)g(UTC.)g(The)g(older)0 3267 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)e(B)i(for)g(the)0
+3380 y(de\014nition)j(of)h(the)f(parameters)h(used)e(in)h(these)h
+(routines.)0 3621 y Fi(1)81 b Fj(Get)23 b(the)f(curren)m(t)f(system)i
+(date.)38 b(C)22 b(already)g(pro)m(vides)g(standard)f(library)h
+(routines)g(for)f(getting)j(the)e(curren)m(t)227 3734
+y(date)k(and)e(time,)j(but)d(this)h(routine)g(is)g(pro)m(vided)g(for)f
+(compatibilit)m(y)k(with)c(the)h(F)-8 b(ortran)26 b(FITSIO)e(library)-8
+b(.)227 3847 y(The)30 b(returned)f(y)m(ear)j(has)e(4)g(digits)h
+(\(1999,)i(2000,)g(etc.\))95 4088 y Fe(int)47 b
+(fits_get_system_date/ffgsd)o(t)286 4201 y(\()h(>)f(int)g(*day,)g(int)f
+(*month,)g(int)h(*year,)f(int)h(*status)f(\))0 4442 y
+Fi(2)81 b Fj(Get)34 b(the)g(curren)m(t)g(system)f(date)i(and)e(time)h
+(string)g(\('YYYY-MM-DDThh:mm:ss'\).)53 b(The)33 b(time)i(will)f(b)s(e)
+227 4555 y(in)26 b(UTC/GMT)g(if)g(a)m(v)-5 b(ailable,)29
+b(as)e(indicated)f(b)m(y)g(a)g(returned)f(timeref)h(v)-5
+b(alue)27 b(=)e(0.)40 b(If)26 b(the)g(returned)e(v)-5
+b(alue)227 4668 y(of)31 b(timeref)g(=)g(1)g(then)f(this)h(indicates)g
+(that)h(it)f(w)m(as)g(not)g(p)s(ossible)f(to)h(con)m(v)m(ert)i(the)d
+(lo)s(cal)i(time)g(to)f(UTC,)227 4780 y(and)f(th)m(us)g(the)h(lo)s(cal)
+g(time)g(w)m(as)g(returned.)95 5021 y Fe(int)47 b
+(fits_get_system_time/ffgst)o(m)286 5134 y(\(>)h(char)e(*datestr,)f
+(int)95 b(*timeref,)45 b(int)i(*status\))0 5375 y Fi(3)81
+b Fj(Construct)26 b(a)i(date)g(string)f(from)g(the)g(input)f(date)i(v)
+-5 b(alues.)40 b(If)27 b(the)g(y)m(ear)h(is)g(b)s(et)m(w)m(een)f(1900)i
+(and)e(1998,)j(inclu-)227 5488 y(siv)m(e,)38 b(then)c(the)i(returned)d
+(date)j(string)f(will)g(ha)m(v)m(e)i(the)e(old)g(FITS)f(format)i
+(\('dd/mm/yy'\),)h(otherwise)227 5601 y(the)32 b(date)f(string)g(will)h
+(ha)m(v)m(e)g(the)g(new)e(FITS)h(format)g(\('YYYY-MM-DD'\).)36
+b(Use)31 b(\014ts)p 3229 5601 28 4 v 33 w(time2str)h(instead)227
+5714 y(to)f(alw)m(a)m(ys)h(return)e(a)g(date)h(string)g(using)f(the)g
+(new)g(FITS)g(format.)p eop end
+%%Page: 62 70
+TeXDict begin 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)95 555 y Fe(int)47 b(fits_date2str/ffdt2s)286
+668 y(\(int)g(year,)f(int)h(month,)f(int)h(day,)g(>)g(char)g(*datestr,)
+e(int)i(*status\))0 928 y Fi(4)81 b Fj(Construct)34 b(a)i(new-format)f
+(date)h(+)f(time)h(string)f(\('YYYY-MM-DDThh:mm:ss.ddd...'\).)57
+b(If)34 b(the)i(y)m(ear,)227 1041 y(mon)m(th,)d(and)e(da)m(y)h(v)-5
+b(alues)32 b(all)h(=)e(0)h(then)g(only)g(the)g(time)g(is)g(enco)s(ded)f
+(with)h(format)g('hh:mm:ss.ddd...'.)227 1154 y(The)j(decimals)h
+(parameter)g(sp)s(eci\014es)e(ho)m(w)i(man)m(y)f(decimal)h(places)g(of)
+f(fractional)i(seconds)e(to)h(include)227 1266 y(in)30
+b(the)h(string.)41 b(If)29 b(`decimals')j(is)f(negativ)m(e,)h(then)f
+(only)f(the)h(date)g(will)f(b)s(e)g(return)f(\('YYYY-MM-DD'\).)95
+1526 y Fe(int)47 b(fits_time2str/fftm2s)286 1639 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 1752 y(int)h(decimals,)f(>)h(char)g(*datestr,)e(int)i(*status\))0
+2012 y Fi(5)81 b Fj(Return)44 b(the)g(date)i(as)f(read)f(from)h(the)g
+(input)e(string,)49 b(where)44 b(the)h(string)g(ma)m(y)g(b)s(e)f(in)h
+(either)g(the)g(old)227 2125 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 2237 y(p)s(oin)m(ters)31 b(ma)m(y)f(b)s(e)g(supplied)f(for)h
+(an)m(y)h(un)m(w)m(an)m(ted)g(output)f(date)h(parameters.)95
+2497 y Fe(int)47 b(fits_str2date/ffs2dt)286 2610 y(\(char)g(*datestr,)e
+(>)i(int)g(*year,)f(int)h(*month,)f(int)h(*day,)f(int)h(*status\))0
+2870 y Fi(6)81 b Fj(Return)30 b(the)h(date)h(and)f(time)h(as)f(read)g
+(from)g(the)h(input)e(string,)h(where)g(the)h(string)f(ma)m(y)h(b)s(e)e
+(in)h(either)h(the)227 2983 y(old)d(or)f(new)g(FITS)g(format.)40
+b(The)28 b(returned)f(hours,)h(min)m(utes,)h(and)f(seconds)g(v)-5
+b(alues)29 b(will)f(b)s(e)g(set)h(to)g(zero)227 3095
+y(if)k(the)h(input)e(string)h(do)s(es)g(not)h(include)f(the)g(time)h
+(\('dd/mm/yy')f(or)h('YYYY-MM-DD'\))j(.)c(Similarly)-8
+b(,)227 3208 y(the)36 b(returned)e(y)m(ear,)j(mon)m(th,)g(and)d(date)i
+(v)-5 b(alues)36 b(will)f(b)s(e)g(set)h(to)g(zero)g(if)f(the)g(date)h
+(is)f(not)h(included)e(in)227 3321 y(the)29 b(input)f(string)h
+(\('hh:mm:ss.ddd...'\).)40 b(Null)29 b(p)s(oin)m(ters)f(ma)m(y)i(b)s(e)
+e(supplied)f(for)i(an)m(y)g(un)m(w)m(an)m(ted)g(output)227
+3434 y(date)i(and)f(time)h(parameters.)95 3694 y Fe(int)47
+b(fits_str2time/ffs2tm)286 3807 y(\(char)g(*datestr,)e(>)i(int)g
+(*year,)f(int)h(*month,)f(int)h(*day,)f(int)h(*hour,)286
+3920 y(int)g(*minute,)f(double)g(*second,)f(int)i(*status\))0
+4210 y Fd(5.8.3)112 b(General)39 b(Utilit)m(y)e(Routines)0
+4429 y Fj(The)30 b(follo)m(wing)i(utilit)m(y)f(routines)g(ma)m(y)g(b)s
+(e)e(useful)h(for)g(certain)h(applications.)0 4689 y
+Fi(1)81 b Fj(Return)30 b(the)h(revision)g(n)m(um)m(b)s(er)f(of)h(the)g
+(CFITSIO)f(library)-8 b(.)42 b(The)31 b(revision)g(n)m(um)m(b)s(er)f
+(will)h(b)s(e)f(incremen)m(ted)227 4802 y(with)g(eac)m(h)i(new)e
+(release)h(of)g(CFITSIO.)95 5061 y Fe(float)47 b(fits_get_version)c(/)
+48 b(ffvers)e(\()h(>)h(float)e(*version\))0 5321 y Fi(2)81
+b Fj(W)-8 b(rite)34 b(an)g(80-c)m(haracter)i(message)e(to)g(the)g
+(CFITSIO)e(error)h(stac)m(k.)51 b(Application)34 b(programs)f(should)g
+(not)227 5434 y(normally)e(write)f(to)i(the)e(stac)m(k,)i(but)e(there)g
+(ma)m(y)h(b)s(e)f(some)h(situations)g(where)f(this)g(is)h(desirable.)95
+5694 y Fe(void)47 b(fits_write_errmsg)c(/)48 b(ffpmsg)e(\(char)g
+(*err_msg\))p eop end
+%%Page: 63 71
+TeXDict begin 63 70 bop 0 299 a Fh(5.8.)72 b(UTILITY)30
+b(R)m(OUTINES)2693 b Fj(63)0 555 y Fi(3)81 b Fj(Con)m(v)m(ert)31
+b(a)g(c)m(haracter)h(string)e(to)h(upp)s(ercase)e(\(op)s(erates)j(in)e
+(place\).)95 817 y Fe(void)47 b(fits_uppercase)d(/)j(ffupch)g(\(char)f
+(*string\))0 1079 y Fi(4)81 b Fj(Compare)43 b(the)i(input)e(template)i
+(string)f(against)h(the)g(reference)f(string)g(to)h(see)g(if)f(they)g
+(matc)m(h.)82 b(The)227 1192 y(template)36 b(string)f(ma)m(y)g(con)m
+(tain)g(wildcard)f(c)m(haracters:)51 b('*')35 b(will)g(matc)m(h)g(an)m
+(y)g(sequence)g(of)f(c)m(haracters)227 1305 y(\(including)j(zero)h(c)m
+(haracters\))g(and)e(')10 b(?')60 b(will)38 b(matc)m(h)f(an)m(y)g
+(single)h(c)m(haracter)g(in)f(the)g(reference)g(string.)227
+1418 y(The)e('#')h(c)m(haracter)h(will)f(matc)m(h)g(an)m(y)g
+(consecutiv)m(e)h(string)f(of)f(decimal)i(digits)f(\(0)g(-)f(9\).)57
+b(If)35 b(casesen)h(=)227 1531 y(CASESEN)c(=)h(TR)m(UE)h(then)f(the)g
+(matc)m(h)i(will)e(b)s(e)g(case)h(sensitiv)m(e,)i(otherwise)e(the)f
+(case)i(of)e(the)h(letters)227 1644 y(will)g(b)s(e)f(ignored)h(if)g
+(casesen)g(=)g(CASEINSEN)e(=)h(F)-10 b(ALSE.)34 b(The)f(returned)f(MA)
+-8 b(TCH)34 b(parameter)h(will)227 1757 y(b)s(e)30 b(TR)m(UE)g(if)g
+(the)g(2)h(strings)f(matc)m(h,)h(and)f(EXA)m(CT)g(will)g(b)s(e)g(TR)m
+(UE)g(if)g(the)g(matc)m(h)h(is)f(exact)i(\(i.e.,)g(if)e(no)227
+1870 y(wildcard)k(c)m(haracters)i(w)m(ere)f(used)e(in)h(the)h(matc)m
+(h\).)53 b(Both)35 b(strings)g(m)m(ust)f(b)s(e)f(68)j(c)m(haracters)f
+(or)g(less)f(in)227 1983 y(length.)95 2245 y Fe(void)47
+b(fits_compare_str)c(/)48 b(ffcmps)334 2358 y(\(char)e(*templt,)g(char)
+h(*string,)e(int)i(casesen,)f(>)h(int)g(*match,)f(int)h(*exact\))0
+2620 y Fi(5)81 b Fj(Split)30 b(a)i(string)f(con)m(taining)h(a)g(list)f
+(of)g(names)g(\(t)m(ypically)j(\014le)d(names)g(or)g(column)f(names\))i
+(in)m(to)g(individual)227 2733 y(name)23 b(tok)m(ens)g(b)m(y)g(a)g
+(sequence)g(of)g(calls)g(to)h(\014ts)p 1814 2733 28 4
+v 32 w(split)p 2018 2733 V 33 w(names.)38 b(The)22 b(names)h(in)f(the)h
+(list)g(m)m(ust)f(b)s(e)g(delimited)227 2846 y(b)m(y)45
+b(a)f(comma)i(and/or)e(spaces.)83 b(This)44 b(routine)g(ignores)h
+(spaces)g(and)f(commas)h(that)g(o)s(ccur)f(within)227
+2959 y(paren)m(theses,)36 b(brac)m(k)m(ets,)h(or)e(curly)f(brac)m(k)m
+(ets.)54 b(It)35 b(also)g(strips)f(an)m(y)h(leading)g(and)f(trailing)h
+(blanks)f(from)227 3072 y(the)d(returned)e(name.)227
+3223 y(This)h(routine)g(is)h(similar)f(to)h(the)g(ANSI)f(C)g('strtok')h
+(function:)227 3374 y(The)37 b(\014rst)f(call)i(to)g(\014ts)p
+1033 3374 V 32 w(split)p 1237 3374 V 33 w(names)f(has)g(a)g(non-n)m
+(ull)f(input)g(string.)61 b(It)37 b(\014nds)e(the)i(\014rst)f(name)h
+(in)g(the)227 3487 y(string)26 b(and)f(terminates)h(it)h(b)m(y)e(o)m(v)
+m(erwriting)i(the)f(next)g(c)m(haracter)h(of)f(the)g(string)f(with)h(a)
+g(n)m(ull)f(terminator)227 3600 y(and)31 b(returns)g(a)h(p)s(oin)m(ter)
+f(to)i(the)e(name.)45 b(Eac)m(h)32 b(subsequen)m(t)f(call,)j(indicated)
+e(b)m(y)f(a)h(NULL)g(v)-5 b(alue)32 b(of)g(the)227 3713
+y(input)f(string,)i(returns)e(the)h(next)h(name,)f(searc)m(hing)h(from)
+f(just)g(past)g(the)g(end)f(of)i(the)f(previous)g(name.)227
+3826 y(It)f(returns)e(NULL)h(when)g(no)g(further)f(names)h(are)h
+(found.)143 4088 y Fe(char)47 b(*fits_split_names\(char)42
+b(*namelist\))0 4350 y Fj(The)30 b(follo)m(wing)i(example)f(sho)m(ws)f
+(ho)m(w)g(a)h(string)f(w)m(ould)h(b)s(e)e(split)i(in)m(to)g(3)g(names:)
+191 4612 y Fe(myfile[1][bin)44 b(\(x,y\)=4],)h(file2.fits)93
+b(file3.fits)191 4725 y(^^^^^^^^^^^^^^^^^^^^^^)c(^^^^^^^^^^)k
+(^^^^^^^^^^)382 4838 y(1st)47 b(name)619 b(2nd)47 b(name)190
+b(3rd)47 b(name)0 5100 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)i(only)e(legal)j(c)m(haracters)f
+(\(A-Z,0-9,)h(h)m(yphen,)d(and)g(underscore\))227 5213
+y(or)e(that)g(the)f(k)m(eyw)m(ord)h(record)f(con)m(tains)i(only)e
+(legal)i(prin)m(table)f(ASCI)s(I)e(c)m(haracters)95 5475
+y Fe(int)47 b(fits_test_keyword)c(/)48 b(fftkey)e(\(char)g(*keyname,)g
+(>)h(int)g(*status\))95 5701 y(int)g(fits_test_record)d(/)j(fftrec)f
+(\(char)h(*card,)f(>)h(int)g(*status\))p eop end
+%%Page: 64 72
+TeXDict begin 64 71 bop 0 299 a Fj(64)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(7)81 b Fj(T)-8 b(est)25 b(whether)f(the)h
+(curren)m(t)f(header)h(con)m(tains)g(an)m(y)g(NULL)g(\(ASCI)s(I)e(0\))j
+(c)m(haracters.)40 b(These)24 b(c)m(haracters)j(are)227
+668 y(illegal)37 b(in)d(the)h(header,)g(but)f(they)g(will)h(go)g
+(undetected)g(b)m(y)f(most)h(of)g(the)f(CFITSIO)f(k)m(eyw)m(ord)i
+(header)227 781 y(routines,)29 b(b)s(ecause)f(the)h(n)m(ull)f(is)g(in)m
+(terpreted)g(as)h(the)f(normal)g(end-of-string)h(terminator.)41
+b(This)27 b(routine)227 894 y(returns)h(the)g(p)s(osition)h(of)g(the)g
+(\014rst)f(n)m(ull)g(c)m(haracter)i(in)f(the)f(header,)h(or)g(zero)g
+(if)g(there)g(are)g(no)f(n)m(ulls.)40 b(F)-8 b(or)227
+1007 y(example)37 b(a)f(returned)f(v)-5 b(alue)37 b(of)f(110)h(w)m
+(ould)f(indicate)h(that)g(the)f(\014rst)f(NULL)h(is)g(lo)s(cated)h(in)f
+(the)g(30th)227 1120 y(c)m(haracter)28 b(of)f(the)g(second)f(k)m(eyw)m
+(ord)h(in)f(the)h(header)f(\(recall)i(that)f(eac)m(h)h(header)e(record)
+h(is)f(80)h(c)m(haracters)227 1233 y(long\).)45 b(Note)33
+b(that)f(this)g(is)f(one)h(of)g(the)g(few)f(CFITSIO)f(routines)h(in)h
+(whic)m(h)f(the)h(returned)e(v)-5 b(alue)32 b(is)g(not)227
+1346 y(necessarily)g(equal)e(to)i(the)e(status)h(v)-5
+b(alue\).)95 1597 y Fe(int)47 b(fits_null_check)d(/)j(ffnchk)g(\(char)f
+(*card,)g(>)h(int)g(*status\))0 1849 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)h(of)f(the)g(name.)227
+1962 y(The)34 b(k)m(eyw)m(ord)h(name)f(normally)h(o)s(ccupies)f(the)h
+(\014rst)e(8)i(c)m(haracters)g(of)g(the)f(record,)i(except)f(under)e
+(the)227 2075 y(HIERAR)m(CH)e(con)m(v)m(en)m(tion)h(where)e(the)h(name)
+f(can)h(b)s(e)f(up)f(to)i(70)g(c)m(haracters)h(in)e(length.)95
+2326 y Fe(int)47 b(fits_get_keyname)d(/)j(ffgknm)286
+2439 y(\(char)g(*card,)f(>)h(char)g(*keyname,)e(int)i(*keylength,)e
+(int)i(*status\))0 2691 y Fi(9)81 b Fj(P)m(arse)29 b(a)h(header)f(k)m
+(eyw)m(ord)h(record,)f(returning)g(the)g(v)-5 b(alue)30
+b(\(as)g(a)f(literal)i(c)m(haracter)g(string\))e(and)g(commen)m(t)227
+2804 y(strings.)40 b(If)27 b(the)g(k)m(eyw)m(ord)h(has)f(no)g(v)-5
+b(alue)28 b(\(columns)f(9-10)i(not)f(equal)f(to)h('=)g('\),)g(then)f(a)
+h(n)m(ull)f(v)-5 b(alue)28 b(string)227 2916 y(is)j(returned)e(and)h
+(the)g(commen)m(t)i(string)e(is)g(set)h(equal)g(to)g(column)f(9)h(-)g
+(80)g(of)g(the)f(input)g(string.)95 3168 y Fe(int)47
+b(fits_parse_value)d(/)j(ffpsvc)286 3281 y(\(char)g(*card,)f(>)h(char)g
+(*value,)f(char)g(*comment,)g(int)h(*status\))0 3533
+y Fi(10)f Fj(Construct)26 b(an)h(arra)m(y)g(indexed)f(k)m(eyw)m(ord)h
+(name)f(\(R)m(OOT)g(+)h(nnn\).)38 b(This)26 b(routine)g(app)s(ends)f
+(the)i(sequence)227 3645 y(n)m(um)m(b)s(er)i(to)i(the)g(ro)s(ot)g
+(string)f(to)h(create)h(a)f(k)m(eyw)m(ord)g(name)f(\(e.g.,)i('NAXIS')f
+(+)f(2)h(=)f('NAXIS2'\))95 3897 y Fe(int)47 b(fits_make_keyn)d(/)k
+(ffkeyn)286 4010 y(\(char)f(*keyroot,)e(int)i(value,)f(>)h(char)g
+(*keyname,)e(int)i(*status\))0 4261 y Fi(11)f Fj(Construct)41
+b(a)h(sequence)f(k)m(eyw)m(ord)h(name)g(\(n)f(+)g(R)m(OOT\).)g(This)g
+(routine)g(concatenates)j(the)e(sequence)227 4374 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)g(to)g(create)h(a)f
+(k)m(eyw)m(ord)g(name)g(\(e.g.,)j(1)d(+)f('CTYP')g(=)g('1CTYP'\))95
+4739 y Fe(int)47 b(fits_make_nkey)d(/)k(ffnkey)286 4852
+y(\(int)f(value,)f(char)h(*keyroot,)e(>)i(char)g(*keyname,)e(int)i
+(*status\))0 5103 y Fi(12)f Fj(Determine)41 b(the)g(data)f(t)m(yp)s(e)h
+(of)f(a)h(k)m(eyw)m(ord)f(v)-5 b(alue)41 b(string.)70
+b(This)39 b(routine)i(parses)e(the)i(k)m(eyw)m(ord)f(v)-5
+b(alue)227 5216 y(string)28 b(to)h(determine)f(its)g(data)h(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,)e(logical,)227 5329 y(in)m(teger,)k(\015oating)g(p)
+s(oin)m(t,)e(or)h(complex,)g(resp)s(ectiv)m(ely)-8 b(.)95
+5581 y Fe(int)47 b(fits_get_keytype)d(/)j(ffdtyp)286
+5694 y(\(char)g(*value,)f(>)h(char)g(*dtype,)e(int)i(*status\))p
+eop end
+%%Page: 65 73
+TeXDict begin 65 72 bop 0 299 a Fh(5.8.)72 b(UTILITY)30
+b(R)m(OUTINES)2693 b Fj(65)0 555 y Fi(13)46 b Fj(Determine)39
+b(the)f(in)m(teger)h(data)g(t)m(yp)s(e)f(of)g(an)g(in)m(teger)h(k)m
+(eyw)m(ord)f(v)-5 b(alue)39 b(string.)63 b(The)37 b(returned)g(datat)m
+(yp)s(e)227 668 y(v)-5 b(alue)36 b(is)f(the)g(minim)m(um)f(in)m(teger)i
+(datat)m(yp)s(e)g(\(starting)g(from)f(top)g(of)g(the)g(follo)m(wing)i
+(list)e(and)g(w)m(orking)227 781 y(do)m(wn\))c(required)e(to)i(store)g
+(the)g(in)m(teger)h(v)-5 b(alue:)191 1045 y Fe(Data)47
+b(Type)285 b(Range)239 1158 y(TSBYTE:)236 b(-128)47 b(to)g(127)239
+1271 y(TBYTE:)332 b(128)47 b(to)g(255)239 1384 y(TSHORT:)236
+b(-32768)46 b(to)i(32767)239 1497 y(TUSHORT:)236 b(32768)46
+b(to)i(65535)239 1610 y(TINT)380 b(-2147483648)45 b(to)i(2147483647)239
+1722 y(TUINT)380 b(2147483648)45 b(to)i(4294967295)239
+1835 y(TLONGLONG)140 b(-9223372036854775808)43 b(to)k
+(9223372036854775807)80 2099 y Fj(The)30 b(*neg)h(parameter)g(returns)e
+(1)i(if)f(the)h(input)e(v)-5 b(alue)31 b(is)g(negativ)m(e)h(and)e
+(returns)f(0)i(if)f(it)h(is)g(non-negativ)m(e.)95 2363
+y Fe(int)47 b(fits_get_inttype)d(/)j(ffinttyp)286 2476
+y(\(char)g(*value,)f(>)h(int)g(*datatype,)e(int)i(*neg,)f(int)h
+(*status\))0 2740 y Fi(14)f Fj(Return)35 b(the)g(class)h(of)g(an)f
+(input)g(header)g(record.)56 b(The)35 b(record)g(is)g(classi\014ed)h
+(in)m(to)h(one)e(of)h(the)f(follo)m(wing)227 2853 y(categories)d(\(the)
+e(class)g(v)-5 b(alues)30 b(are)f(de\014ned)f(in)h(\014tsio.h\).)41
+b(Note)31 b(that)e(this)h(is)f(one)h(of)f(the)g(few)g(CFITSIO)227
+2966 y(routines)i(that)f(do)s(es)h(not)f(return)f(a)i(status)g(v)-5
+b(alue.)334 3230 y Fe(Class)94 b(Value)619 b(Keywords)95
+3343 y(TYP_STRUC_KEY)92 b(10)j(SIMPLE,)46 b(BITPIX,)g(NAXIS,)g(NAXISn,)
+g(EXTEND,)g(BLOCKED,)1002 3456 y(GROUPS,)g(PCOUNT,)g(GCOUNT,)g(END)1002
+3569 y(XTENSION,)g(TFIELDS,)f(TTYPEn,)h(TBCOLn,)g(TFORMn,)g(THEAP,)1002
+3681 y(and)h(the)g(first)f(4)i(COMMENT)e(keywords)f(in)i(the)g(primary)
+f(array)1002 3794 y(that)h(define)f(the)h(FITS)g(format.)95
+3907 y(TYP_CMPRS_KEY)92 b(20)j(The)47 b(experimental)e(keywords)g(used)
+i(in)g(the)g(compressed)1002 4020 y(image)g(format)f(ZIMAGE,)g
+(ZCMPTYPE,)f(ZNAMEn,)h(ZVALn,)1002 4133 y(ZTILEn,)g(ZBITPIX,)g
+(ZNAXISn,)f(ZSCALE,)h(ZZERO,)g(ZBLANK)95 4246 y(TYP_SCAL_KEY)140
+b(30)95 b(BSCALE,)46 b(BZERO,)g(TSCALn,)g(TZEROn)95 4359
+y(TYP_NULL_KEY)140 b(40)95 b(BLANK,)46 b(TNULLn)95 4472
+y(TYP_DIM_KEY)188 b(50)95 b(TDIMn)95 4585 y(TYP_RANG_KEY)140
+b(60)95 b(TLMINn,)46 b(TLMAXn,)g(TDMINn,)g(TDMAXn,)g(DATAMIN,)f
+(DATAMAX)95 4698 y(TYP_UNIT_KEY)140 b(70)95 b(BUNIT,)46
+b(TUNITn)95 4811 y(TYP_DISP_KEY)140 b(80)95 b(TDISPn)95
+4924 y(TYP_HDUID_KEY)d(90)j(EXTNAME,)46 b(EXTVER,)g(EXTLEVEL,)f
+(HDUNAME,)g(HDUVER,)h(HDULEVEL)95 5036 y(TYP_CKSUM_KEY)f(100)94
+b(CHECKSUM,)46 b(DATASUM)95 5149 y(TYP_WCS_KEY)141 b(110)94
+b(WCS)47 b(keywords)f(defined)g(in)h(the)g(the)g(WCS)f(papers,)g
+(including:)1002 5262 y(CTYPEn,)g(CUNITn,)g(CRVALn,)g(CRPIXn,)g
+(CROTAn,)f(CDELTn)1002 5375 y(CDj_is,)h(PVj_ms,)g(LONPOLEs,)f(LATPOLEs)
+1002 5488 y(TCTYPn,)h(TCTYns,)g(TCUNIn,)g(TCUNns,)g(TCRVLn,)f(TCRVns,)h
+(TCRPXn,)1002 5601 y(TCRPks,)g(TCDn_k,)g(TCn_ks,)g(TPVn_m,)g(TPn_ms,)f
+(TCDLTn,)h(TCROTn)1002 5714 y(jCTYPn,)g(jCTYns,)g(jCUNIn,)g(jCUNns,)g
+(jCRVLn,)f(jCRVns,)h(iCRPXn,)p eop end
+%%Page: 66 74
+TeXDict begin 66 73 bop 0 299 a Fj(66)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)1002 555 y Fe(iCRPns,)46 b(jiCDn,)94 b(jiCDns,)46
+b(jPVn_m,)g(jPn_ms,)f(jCDLTn,)h(jCROTn)1002 668 y(\(i,j,m,n)g(are)h
+(integers,)e(s)i(is)h(any)f(letter\))95 781 y(TYP_REFSYS_KEY)d(120)j
+(EQUINOXs,)f(EPOCH,)g(MJD-OBSs,)f(RADECSYS,)g(RADESYSs,)g(DATE-OBS)95
+894 y(TYP_COMM_KEY)140 b(130)47 b(COMMENT,)f(HISTORY,)f(\(blank)h
+(keyword\))95 1007 y(TYP_CONT_KEY)140 b(140)47 b(CONTINUE)95
+1120 y(TYP_USER_KEY)140 b(150)47 b(all)g(other)g(keywords)95
+1346 y(int)g(fits_get_keyclass)c(/)48 b(ffgkcl)e(\(char)g(*card\))0
+1628 y Fi(15)g Fj(P)m(arse)28 b(the)g('TF)m(ORM')g(binary)f(table)h
+(column)g(format)f(string.)40 b(This)27 b(routine)g(parses)g(the)h
+(input)f(TF)m(ORM)227 1740 y(c)m(haracter)38 b(string)d(and)g(returns)g
+(the)g(in)m(teger)i(data)g(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,)i(and,)227 1853 y(in)e(the)f(case)i(of)
+f(c)m(haracter)h(string)f(\014elds,)g(the)g(length)g(of)g(the)g(unit)f
+(string.)54 b(See)34 b(App)s(endix)f(B)i(for)g(the)227
+1966 y(allo)m(w)m(ed)41 b(v)-5 b(alues)38 b(for)h(the)f(returned)g(t)m
+(yp)s(eco)s(de)h(parameter.)65 b(A)39 b(n)m(ull)f(p)s(oin)m(ter)h(ma)m
+(y)g(b)s(e)f(giv)m(en)h(for)g(an)m(y)227 2079 y(output)30
+b(parameters)h(that)g(are)g(not)f(needed.)143 2361 y
+Fe(int)47 b(fits_binary_tform)c(/)48 b(ffbnfm)334 2474
+y(\(char)e(*tform,)g(>)i(int)f(*typecode,)e(long)h(*repeat,)g(long)g
+(*width,)382 2587 y(int)h(*status\))143 2813 y(int)g
+(fits_binary_tformll)c(/)k(ffbnfmll)334 2926 y(\(char)f(*tform,)g(>)i
+(int)f(*typecode,)e(LONGLONG)g(*repeat,)h(long)g(*width,)382
+3039 y(int)h(*status\))0 3321 y Fi(16)f Fj(P)m(arse)38
+b(the)f('TF)m(ORM')h(k)m(eyw)m(ord)g(v)-5 b(alue)37 b(that)h(de\014nes)
+e(the)h(column)g(format)h(in)e(an)h(ASCI)s(I)f(table.)62
+b(This)227 3434 y(routine)29 b(parses)g(the)g(input)f(TF)m(ORM)h(c)m
+(haracter)h(string)f(and)g(returns)e(the)i(data)h(t)m(yp)s(e)f(co)s
+(de,)h(the)f(width)227 3546 y(of)f(the)f(column,)h(and)f(\(if)h(it)g
+(is)f(a)h(\015oating)g(p)s(oin)m(t)g(column\))f(the)h(n)m(um)m(b)s(er)e
+(of)h(decimal)i(places)f(to)g(the)f(righ)m(t)227 3659
+y(of)39 b(the)f(decimal)h(p)s(oin)m(t.)65 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)g
+(table,)227 3772 y(with)26 b(the)h(follo)m(wing)h(additional)f(rules:)
+38 b(in)m(teger)28 b(columns)e(that)h(are)f(b)s(et)m(w)m(een)h(1)g(and)
+f(4)g(c)m(haracters)i(wide)227 3885 y(are)i(de\014ned)e(to)j(b)s(e)d
+(short)i(in)m(tegers)g(\(co)s(de)g(=)g(TSHOR)-8 b(T\).)29
+b(Wider)g(in)m(teger)i(columns)e(are)h(de\014ned)e(to)j(b)s(e)227
+3998 y(regular)39 b(in)m(tegers)g(\(co)s(de)g(=)f(TLONG\).)h(Similarly)
+-8 b(,)41 b(Fixed)e(decimal)g(p)s(oin)m(t)f(columns)g(\(with)h(TF)m
+(ORM)227 4111 y(=)c('Fw.d'\))g(are)h(de\014ned)d(to)j(b)s(e)e(single)i
+(precision)f(reals)h(\(co)s(de)f(=)g(TFLO)m(A)-8 b(T\))35
+b(if)g(w)g(is)g(b)s(et)m(w)m(een)g(1)h(and)227 4224 y(7)42
+b(c)m(haracters)h(wide,)h(inclusiv)m(e.)75 b(Wider)41
+b('F')h(columns)f(will)h(return)e(a)i(double)f(precision)h(data)g(co)s
+(de)227 4337 y(\(=)32 b(TDOUBLE\).)h('Ew.d')f(format)g(columns)g(will)g
+(ha)m(v)m(e)i(dataco)s(de)f(=)e(TFLO)m(A)-8 b(T,)33 b(and)e('Dw.d')i
+(format)227 4450 y(columns)45 b(will)h(ha)m(v)m(e)h(dataco)s(de)f(=)f
+(TDOUBLE.)g(A)h(n)m(ull)f(p)s(oin)m(ter)h(ma)m(y)f(b)s(e)g(giv)m(en)i
+(for)e(an)m(y)g(output)227 4563 y(parameters)31 b(that)g(are)g(not)f
+(needed.)95 4845 y Fe(int)47 b(fits_ascii_tform)d(/)j(ffasfm)286
+4958 y(\(char)g(*tform,)f(>)h(int)g(*typecode,)e(long)i(*width,)e(int)i
+(*decimals,)334 5070 y(int)g(*status\))0 5352 y Fi(17)f
+Fj(Calculate)32 b(the)f(starting)g(column)g(p)s(ositions)f(and)g(total)
+i(ASCI)s(I)d(table)j(width)d(based)i(on)f(the)h(input)e(arra)m(y)227
+5465 y(of)e(ASCI)s(I)e(table)i(TF)m(ORM)g(v)-5 b(alues.)40
+b(The)26 b(SP)-8 b(A)m(CE)27 b(input)e(parameter)i(de\014nes)f(ho)m(w)h
+(man)m(y)f(blank)h(spaces)227 5578 y(to)40 b(lea)m(v)m(e)i(b)s(et)m(w)m
+(een)e(eac)m(h)g(column)g(\(it)g(is)f(recommended)g(to)h(ha)m(v)m(e)h
+(one)e(space)h(b)s(et)m(w)m(een)g(columns)f(for)227 5691
+y(b)s(etter)31 b(h)m(uman)e(readabilit)m(y\).)p eop end
+%%Page: 67 75
+TeXDict begin 67 74 bop 0 299 a Fh(5.8.)72 b(UTILITY)30
+b(R)m(OUTINES)2693 b Fj(67)95 555 y Fe(int)47 b(fits_get_tbcol)d(/)k
+(ffgabc)286 668 y(\(int)f(tfields,)f(char)g(**tform,)g(int)h(space,)f
+(>)h(long)g(*rowlen,)334 781 y(long)g(*tbcol,)f(int)g(*status\))0
+1017 y Fi(18)g Fj(P)m(arse)27 b(a)g(template)h(header)e(record)g(and)g
+(return)g(a)g(formatted)h(80-c)m(haracter)j(string)c(suitable)h(for)f
+(app)s(end-)227 1129 y(ing)40 b(to)f(\(or)h(deleting)g(from\))f(a)g
+(FITS)g(header)g(\014le.)67 b(This)38 b(routine)h(is)g(useful)g(for)f
+(parsing)h(lines)g(from)227 1242 y(an)33 b(ASCI)s(I)f(template)i
+(\014le)f(and)g(reformatting)h(them)f(in)m(to)h(legal)h(FITS)d(header)h
+(records.)49 b(The)32 b(format-)227 1355 y(ted)i(string)g(ma)m(y)g
+(then)f(b)s(e)g(passed)h(to)g(the)g(\014ts)p 1880 1355
+28 4 v 32 w(write)p 2114 1355 V 33 w(record,)h(\013mcrd,)f(or)g(\014ts)
+p 3007 1355 V 32 w(delete)p 3270 1355 V 34 w(k)m(ey)h(routines)e(to)227
+1468 y(app)s(end)c(or)h(mo)s(dify)g(a)h(FITS)e(header)h(record.)95
+1704 y Fe(int)47 b(fits_parse_template)c(/)k(ffgthd)286
+1817 y(\(char)g(*templt,)e(>)j(char)e(*card,)g(int)h(*keytype,)f(int)h
+(*status\))0 2052 y Fj(The)31 b(input)g(templt)h(c)m(haracter)h(string)
+f(generally)h(should)d(con)m(tain)j(3)f(tok)m(ens:)44
+b(\(1\))33 b(the)f(KEYNAME,)g(\(2\))h(the)0 2165 y(V)-10
+b(ALUE,)37 b(and)f(\(3\))i(the)f(COMMENT)g(string.)59
+b(The)37 b(TEMPLA)-8 b(TE)36 b(string)h(m)m(ust)f(adhere)h(to)h(the)e
+(follo)m(wing)0 2278 y(format:)0 2514 y Fi(-)80 b Fj(The)32
+b(KEYNAME)h(tok)m(en)h(m)m(ust)f(b)s(egin)f(in)h(columns)f(1-8)i(and)e
+(b)s(e)g(a)h(maxim)m(um)g(of)g(8)g(c)m(haracters)h(long.)49
+b(A)227 2626 y(legal)30 b(FITS)e(k)m(eyw)m(ord)h(name)f(ma)m(y)h(only)f
+(con)m(tain)i(the)f(c)m(haracters)g(A-Z,)g(0-9,)h(and)e('-')h(\(min)m
+(us)f(sign\))h(and)227 2739 y(underscore.)40 b(This)27
+b(routine)i(will)g(automatically)i(con)m(v)m(ert)f(an)m(y)f(lo)m(w)m
+(ercase)i(c)m(haracters)f(to)g(upp)s(ercase)d(in)227
+2852 y(the)k(output)f(string.)42 b(If)30 b(the)h(\014rst)f(8)h(c)m
+(haracters)h(of)f(the)g(template)h(line)f(are)g(blank)f(then)h(the)g
+(remainder)227 2965 y(of)g(the)f(line)h(is)g(considered)f(to)h(b)s(e)f
+(a)g(FITS)g(commen)m(t)h(\(with)g(a)g(blank)f(k)m(eyw)m(ord)g(name\).)0
+3201 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 3314 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,)h(logical,)j(or)c(c)m(haracter)h(string\))f
+(is)227 3427 y(automatically)35 b(determined)c(and)h(the)g(output)f
+(CARD)h(string)g(is)g(formatted)g(accordingly)-8 b(.)47
+b(The)31 b(v)-5 b(alue)227 3539 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)g(as)h(a)g(string)g(\(e.g.)48
+b(if)33 b(it)g(is)f(a)h(string)g(of)f(n)m(umeric)h(digits\))g(b)m(y)227
+3652 y(enclosing)g(it)f(in)f(single)h(quotes.)45 b(If)31
+b(the)h(v)-5 b(alue)32 b(tok)m(en)g(is)g(a)g(c)m(haracter)h(string)e
+(that)i(con)m(tains)f(1)g(or)g(more)227 3765 y(em)m(b)s(edded)39
+b(blank)g(space)h(c)m(haracters)h(or)e(slash)h(\('/'\))h(c)m(haracters)
+g(then)e(the)g(en)m(tire)i(c)m(haracter)g(string)227
+3878 y(m)m(ust)31 b(b)s(e)e(enclosed)i(in)f(single)h(quotes.)0
+4114 y Fi(-)80 b Fj(The)28 b(COMMENT)g(tok)m(en)h(is)f(optional,)i(but)
+e(if)g(presen)m(t)g(m)m(ust)g(b)s(e)g(separated)g(from)g(the)h(V)-10
+b(ALUE)28 b(tok)m(en)h(b)m(y)227 4227 y(a)i(blank)f(space)h(or)f(a)h
+('/')g(c)m(haracter.)0 4462 y Fi(-)80 b Fj(One)29 b(exception)h(to)f
+(the)g(ab)s(o)m(v)m(e)i(rules)d(is)h(that)g(if)g(the)g(\014rst)g
+(non-blank)f(c)m(haracter)i(in)f(the)g(\014rst)f(8)h(c)m(haracters)227
+4575 y(of)24 b(the)h(template)g(string)f(is)g(a)g(min)m(us)g(sign)g
+(\('-'\))h(follo)m(w)m(ed)h(b)m(y)e(a)g(single)h(tok)m(en,)h(or)e(a)h
+(single)f(tok)m(en)h(follo)m(w)m(ed)227 4688 y(b)m(y)k(an)g(equal)h
+(sign,)g(then)f(it)g(is)h(in)m(terpreted)f(as)h(the)f(name)g(of)h(a)f
+(k)m(eyw)m(ord)h(whic)m(h)f(is)g(to)h(b)s(e)e(deleted)i(from)227
+4801 y(the)h(FITS)e(header.)0 5036 y Fi(-)80 b Fj(The)32
+b(second)g(exception)h(is)f(that)h(if)f(the)g(template)h(string)f
+(starts)h(with)e(a)i(min)m(us)e(sign)h(and)f(is)h(follo)m(w)m(ed)i(b)m
+(y)227 5149 y(2)f(tok)m(ens)g(\(without)g(an)f(equals)h(sign)g(b)s(et)m
+(w)m(een)g(them\))f(then)g(the)h(second)f(tok)m(en)i(is)e(in)m
+(terpreted)h(as)g(the)227 5262 y(new)f(name)h(for)f(the)h(k)m(eyw)m
+(ord)g(sp)s(eci\014ed)f(b)m(y)h(\014rst)f(tok)m(en.)48
+b(In)32 b(this)g(case)i(the)f(old)g(k)m(eyw)m(ord)g(name)f(\(\014rst)
+227 5375 y(tok)m(en\))c(is)e(returned)e(in)i(c)m(haracters)h(1-8)g(of)g
+(the)f(returned)e(CARD)j(string,)g(and)e(the)h(new)f(k)m(eyw)m(ord)i
+(name)227 5488 y(\(the)35 b(second)e(tok)m(en\))j(is)e(returned)e(in)i
+(c)m(haracters)h(41-48)h(of)e(the)g(returned)e(CARD)i(string.)51
+b(These)34 b(old)227 5601 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)g(whic)m(h)g(will)g(c)m(hange)h
+(the)f(k)m(eyw)m(ord)227 5714 y(name.)p eop end
+%%Page: 68 76
+TeXDict begin 68 75 bop 0 299 a Fj(68)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(The)g(k)m(eyt)m(yp)s(e)h(output)f(parameter)h
+(indicates)g(ho)m(w)g(the)f(returned)g(CARD)g(string)g(should)g(b)s(e)f
+(in)m(terpreted:)382 784 y Fe(keytype)857 b(interpretation)382
+897 y(-------)475 b(-------------------------)o(----)o(---)o(----)o
+(----)o(---)o(----)o(--)525 1010 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 1123 y(to)f(the)g(new)g(name)g(given)f(in)h(characters)e(41)
+j(-)f(48)g(of)g(CARD.)525 1349 y(-1)572 b(delete)46 b(the)h(keyword)f
+(with)h(this)f(name)h(from)g(the)f(FITS)h(header.)573
+1575 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 1688 y(keyword)f(does)h(not)g(already)e(exist,)
+h(otherwise)g(update)1193 1801 y(the)h(keyword)f(value)g(and/or)g
+(comment)g(field)h(if)g(is)g(already)f(exists.)573 2026
+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 2252 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 2481 y Fj(EXAMPLES:)30 b(The)g(follo)m(wing)i(lines)e
+(illustrate)i(v)-5 b(alid)31 b(input)e(template)j(strings:)286
+2710 y Fe(INTVAL)46 b(7)i(/)f(This)g(is)g(an)g(integer)f(keyword)286
+2823 y(RVAL)524 b(34.6)142 b(/)239 b(This)46 b(is)i(a)f(floating)f
+(point)g(keyword)286 2936 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 3049 y(lval)i(F)g(/)h(This)f(is)g(a)g(boolean)f(keyword)
+859 3162 y(This)h(is)g(a)g(comment)f(keyword)g(with)h(a)g(blank)f
+(keyword)g(name)286 3275 y(SVAL1)h(=)g('Hello)f(world')142
+b(/)95 b(this)47 b(is)g(a)g(string)f(keyword)286 3388
+y(SVAL2)94 b('123.5')g(this)47 b(is)g(also)f(a)i(string)e(keyword)286
+3501 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 3614
+y(#)48 b(the)f(following)e(template)h(line)g(deletes)g(the)h(DATE)g
+(keyword)286 3727 y(-)h(DATE)286 3840 y(#)g(the)f(following)e(template)
+h(line)g(modifies)g(the)h(NAME)f(keyword)g(to)h(OBJECT)286
+3952 y(-)h(NAME)e(OBJECT)0 4182 y Fi(19)g Fj(T)-8 b(ranslate)32
+b(a)g(k)m(eyw)m(ord)g(name)f(in)m(to)h(a)g(new)f(name,)h(based)f(on)g
+(a)h(set)f(of)h(patterns.)43 b(This)31 b(routine)g(is)h(useful)227
+4294 y(for)j(translating)h(k)m(eyw)m(ords)g(in)e(cases)i(suc)m(h)f(as)h
+(adding)e(or)h(deleting)h(columns)f(in)g(a)g(table,)j(or)d(cop)m(ying)
+227 4407 y(a)41 b(column)g(from)f(one)h(table)g(to)g(another,)j(or)c
+(extracting)j(an)d(arra)m(y)h(from)f(a)h(cell)h(in)e(a)h(binary)f
+(table)227 4520 y(column)31 b(in)m(to)g(an)g(image)g(extension.)42
+b(In)30 b(these)h(cases,)h(it)f(is)g(necessary)g(to)g(translate)h(the)f
+(names)f(of)h(the)227 4633 y(k)m(eyw)m(ords)f(asso)s(ciated)i(with)d
+(the)h(original)h(table)g(column\(s\))f(in)m(to)g(the)g(appropriate)g
+(k)m(eyw)m(ord)g(name)g(in)227 4746 y(the)37 b(\014nal)f(\014le.)58
+b(F)-8 b(or)37 b(example,)i(if)d(column)h(2)f(is)h(deleted)g(from)e(a)i
+(table,)i(then)d(the)h(v)-5 b(alue)36 b(of)h('n')f(in)g(all)227
+4859 y(the)c(TF)m(ORMn)g(and)f(TTYPEn)f(k)m(eyw)m(ords)i(for)g(columns)
+f(3)h(and)f(higher)h(m)m(ust)f(b)s(e)g(decremen)m(ted)i(b)m(y)e(1.)227
+4972 y(Ev)m(en)j(more)g(complex)h(translations)f(are)h(sometimes)f
+(needed)g(to)h(con)m(v)m(ert)g(the)f(W)m(CS)g(k)m(eyw)m(ords)g(when)227
+5085 y(extracting)e(an)f(image)g(out)g(of)f(a)h(table)g(column)g(cell)g
+(in)m(to)h(a)e(separate)i(image)f(extension.)227 5230
+y(The)g(user)f(passes)i(an)f(arra)m(y)g(of)h(patterns)f(to)h(b)s(e)e
+(matc)m(hed.)44 b(Input)30 b(pattern)h(n)m(um)m(b)s(er)f(i)i(is)f
+(pattern[i][0],)227 5343 y(and)j(output)f(pattern)h(n)m(um)m(b)s(er)f
+(i)h(is)g(pattern[i][1].)53 b(Keyw)m(ords)34 b(are)g(matc)m(hed)h
+(against)g(the)f(input)f(pat-)227 5456 y(terns.)41 b(If)30
+b(a)g(matc)m(h)i(is)e(found)f(then)h(the)h(k)m(eyw)m(ord)g(is)f
+(re-written)h(according)g(to)g(the)g(output)f(pattern.)227
+5601 y(Order)41 b(is)h(imp)s(ortan)m(t.)76 b(The)41 b(\014rst)h(matc)m
+(h)h(is)f(accepted.)77 b(The)41 b(fastest)i(matc)m(h)g(will)f(b)s(e)g
+(made)g(when)227 5714 y(templates)32 b(with)e(the)h(same)f(\014rst)g(c)
+m(haracter)i(are)f(group)s(ed)e(together.)p eop end
+%%Page: 69 77
+TeXDict begin 69 76 bop 0 299 a Fh(5.8.)72 b(UTILITY)30
+b(R)m(OUTINES)2693 b Fj(69)227 555 y(Sev)m(eral)32 b(c)m(haracters)f
+(ha)m(v)m(e)h(sp)s(ecial)f(meanings:)466 772 y Fe(i,j)47
+b(-)g(single)f(digits,)g(preserved)f(in)j(output)e(template)466
+885 y(n)h(-)h(column)e(number)g(of)h(one)g(or)g(more)g(digits,)f
+(preserved)f(in)i(output)f(template)466 998 y(m)h(-)h(generic)e(number)
+g(of)h(one)g(or)g(more)g(digits,)e(preserved)h(in)h(output)f(template)
+466 1111 y(a)h(-)h(coordinate)d(designator,)g(preserved)g(in)i(output)f
+(template)466 1224 y(#)h(-)h(number)e(of)h(one)g(or)g(more)g(digits)466
+1337 y(?)g(-)h(any)f(character)466 1450 y(*)g(-)h(only)e(allowed)g(in)h
+(first)g(character)e(position,)g(to)j(match)e(all)657
+1563 y(keywords;)f(only)i(useful)f(as)h(last)g(pattern)e(in)j(the)f
+(list)227 1780 y Fj(i,)31 b(j,)f(n,)g(and)g(m)g(are)h(returned)e(b)m(y)
+i(the)f(routine.)227 1926 y(F)-8 b(or)27 b(example,)g(the)f(input)f
+(pattern)h("iCTYPn")g(will)g(matc)m(h)h("1CTYP5")g(\(if)f(n)p
+3003 1926 28 4 v 32 w(v)-5 b(alue)26 b(is)g(5\);)i(the)e(output)227
+2038 y(pattern)31 b("CTYPEi")f(will)h(b)s(e)f(re-written)h(as)f
+("CTYPE1".)42 b(Notice)32 b(that)f("i")g(is)g(preserv)m(ed.)227
+2184 y(The)f(follo)m(wing)i(output)e(patterns)g(are)h(sp)s(ecial:)227
+2330 y("-")h(-)e(do)h(not)f(cop)m(y)h(a)g(k)m(eyw)m(ord)g(that)g(matc)m
+(hes)g(the)g(corresp)s(onding)e(input)h(pattern)227 2475
+y("+")h(-)g(cop)m(y)g(the)f(input)g(unc)m(hanged)227
+2621 y(The)f(inrec)h(string)g(could)g(b)s(e)f(just)g(the)h(8-c)m(har)h
+(k)m(eyw)m(ord)f(name,)g(or)f(the)h(en)m(tire)h(80-c)m(har)g(header)f
+(record.)227 2734 y(Characters)h(9)g(-)f(80)h(in)g(the)f(input)g
+(string)g(simply)g(get)h(app)s(ended)e(to)i(the)g(translated)g(k)m(eyw)
+m(ord)f(name.)227 2879 y(If)h(n)p 375 2879 V 33 w(range)g(=)g(0,)i
+(then)e(only)h(k)m(eyw)m(ords)f(with)h('n')f(equal)h(to)g(n)p
+2410 2879 V 32 w(v)-5 b(alue)32 b(will)g(b)s(e)f(considered)g(as)h(a)g
+(pattern)227 2992 y(matc)m(h.)70 b(If)39 b(n)p 722 2992
+V 32 w(range)h(=)f(+1,)j(then)e(all)g(v)-5 b(alues)40
+b(of)g('n')f(greater)i(than)e(or)h(equal)g(to)g(n)p 3269
+2992 V 33 w(v)-5 b(alue)40 b(will)g(b)s(e)f(a)227 3105
+y(matc)m(h,)32 b(and)e(if)g(-1,)h(then)f(v)-5 b(alues)31
+b(of)g('n')f(less)g(than)h(or)f(equal)h(to)g(n)p 2530
+3105 V 32 w(v)-5 b(alue)31 b(will)g(matc)m(h.)0 3337
+y Fe(int)47 b(fits_translate_keyword\()286 3450 y(char)g(*inrec,)380
+b(/*)47 b(I)h(-)f(input)f(string)g(*/)286 3563 y(char)h(*outrec,)332
+b(/*)47 b(O)h(-)f(output)f(converted)f(string,)h(or)h(*/)1241
+3676 y(/*)238 b(a)47 b(null)g(string)f(if)h(input)g(does)f(not)95
+b(*/)1241 3788 y(/*)238 b(match)46 b(any)h(of)g(the)g(patterns)f(*/)286
+3901 y(char)h(*patterns[][2],/*)c(I)48 b(-)f(pointer)f(to)h(input)f(/)i
+(output)e(string)g(*/)1241 4014 y(/*)238 b(templates)45
+b(*/)286 4127 y(int)i(npat,)524 b(/*)47 b(I)h(-)f(number)f(of)h
+(templates)f(passed)g(*/)286 4240 y(int)h(n_value,)380
+b(/*)47 b(I)h(-)f(base)g('n')g(template)e(value)h(of)i(interest)d(*/)
+286 4353 y(int)i(n_offset,)332 b(/*)47 b(I)h(-)f(offset)f(to)h(be)g
+(applied)f(to)h(the)g('n')g(*/)1241 4466 y(/*)238 b(value)46
+b(in)i(the)e(output)h(string)f(*/)286 4579 y(int)h(n_range,)380
+b(/*)47 b(I)h(-)f(controls)f(range)g(of)h('n')g(template)f(*/)1241
+4692 y(/*)238 b(values)46 b(of)h(interest)f(\(-1,0,)g(or)h(+1\))g(*/)
+286 4805 y(int)g(*pat_num,)332 b(/*)47 b(O)h(-)f(matched)f(pattern)g
+(number)g(\(0)h(based\))f(or)h(-1)g(*/)286 4918 y(int)g(*i,)620
+b(/*)47 b(O)h(-)f(value)f(of)i(i,)f(if)g(any,)g(else)f(0)i(*/)286
+5031 y(int)f(*j,)620 b(/*)47 b(O)h(-)f(value)f(of)i(j,)f(if)g(any,)g
+(else)f(0)i(*/)286 5143 y(int)f(*m,)620 b(/*)47 b(O)h(-)f(value)f(of)i
+(m,)f(if)g(any,)g(else)f(0)i(*/)286 5256 y(int)f(*n,)620
+b(/*)47 b(O)h(-)f(value)f(of)i(n,)f(if)g(any,)g(else)f(0)i(*/)286
+5369 y(int)f(*status\))380 b(/*)47 b(IO)g(-)h(error)e(status)g(*/)80
+5601 y Fj(Here)25 b(is)f(an)g(example)g(of)g(some)h(of)f(the)g
+(patterns)g(used)f(to)i(con)m(v)m(ert)g(the)f(k)m(eyw)m(ords)h(asso)s
+(ciated)g(with)f(an)g(image)227 5714 y(in)30 b(a)h(cell)h(of)e(a)h
+(table)g(column)f(in)m(to)i(the)e(k)m(eyw)m(ords)h(appropriate)f(for)h
+(an)f(IMA)m(GE)h(extension:)p eop end
+%%Page: 70 78
+TeXDict begin 70 77 bop 0 299 a Fj(70)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)191 555 y Fe(char)47 b(*patterns[][2])c(=)48
+b({{"TSCALn",)92 b("BSCALE")i(},)h(/*)47 b(Standard)e(FITS)i(keywords)e
+(*/)143 668 y({"TZEROn",)93 b("BZERO")141 b(},)143 781
+y({"TUNITn",)93 b("BUNIT")141 b(},)143 894 y({"TNULLn",)93
+b("BLANK")141 b(},)143 1007 y({"TDMINn",)93 b("DATAMIN")45
+b(},)143 1120 y({"TDMAXn",)93 b("DATAMAX")45 b(},)143
+1233 y({"iCTYPn",)93 b("CTYPEi")g(},)i(/*)47 b(Coordinate)e(labels)h
+(*/)143 1346 y({"iCTYna",)93 b("CTYPEia")45 b(},)143
+1458 y({"iCUNIn",)93 b("CUNITi")g(},)i(/*)47 b(Coordinate)e(units)i(*/)
+143 1571 y({"iCUNna",)93 b("CUNITia")45 b(},)143 1684
+y({"iCRVLn",)93 b("CRVALi")g(},)i(/*)47 b(WCS)g(keywords)f(*/)143
+1797 y({"iCRVna",)93 b("CRVALia")45 b(},)143 1910 y({"iCDLTn",)93
+b("CDELTi")g(},)143 2023 y({"iCDEna",)g("CDELTia")45
+b(},)143 2136 y({"iCRPXn",)93 b("CRPIXi")g(},)143 2249
+y({"iCRPna",)g("CRPIXia")45 b(},)143 2362 y({"ijPCna",)93
+b("PCi_ja")g(},)143 2475 y({"ijCDna",)g("CDi_ja")g(},)143
+2588 y({"iVn_ma",)g("PVi_ma")g(},)143 2700 y({"iSn_ma",)g("PSi_ma")g
+(},)143 2813 y({"iCRDna",)g("CRDERia")45 b(},)143 2926
+y({"iCSYna",)93 b("CSYERia")45 b(},)143 3039 y({"iCROTn",)93
+b("CROTAi")g(},)143 3152 y({"WCAXna",)g("WCSAXESa"},)143
+3265 y({"WCSNna",)g("WCSNAMEa"}};)0 3517 y Fi(20)46 b
+Fj(T)-8 b(ranslate)26 b(the)f(k)m(eyw)m(ords)g(in)g(the)g(input)e(HDU)j
+(in)m(to)g(the)f(k)m(eyw)m(ords)g(that)h(are)f(appropriate)g(for)f(the)
+h(output)227 3630 y(HDU.)32 b(This)d(is)i(a)f(driv)m(er)h(routine)f
+(that)h(calls)g(the)g(previously)f(describ)s(ed)f(routine.)0
+3881 y Fe(int)47 b(fits_translate_keywords\()143 3994
+y(fitsfile)f(*infptr,)141 b(/*)47 b(I)g(-)h(pointer)e(to)h(input)f(HDU)
+h(*/)143 4107 y(fitsfile)f(*outfptr,)93 b(/*)47 b(I)g(-)h(pointer)e(to)
+h(output)f(HDU)h(*/)143 4220 y(int)g(firstkey,)332 b(/*)47
+b(I)g(-)h(first)e(HDU)h(record)f(number)g(to)h(start)g(with)f(*/)143
+4333 y(char)h(*patterns[][2],/*)c(I)k(-)h(pointer)e(to)h(input)f(/)i
+(output)e(keyword)g(templates)f(*/)143 4446 y(int)i(npat,)524
+b(/*)47 b(I)g(-)h(number)e(of)h(templates)e(passed)h(*/)143
+4559 y(int)h(n_value,)380 b(/*)47 b(I)g(-)h(base)e('n')h(template)f
+(value)g(of)h(interest)f(*/)143 4672 y(int)h(n_offset,)332
+b(/*)47 b(I)g(-)h(offset)e(to)h(be)g(applied)f(to)h(the)g('n')g(*/)1193
+4785 y(/*)238 b(value)47 b(in)g(the)g(output)f(string)g(*/)143
+4898 y(int)h(n_range,)380 b(/*)47 b(I)g(-)h(controls)d(range)i(of)g
+('n')g(template)e(*/)1098 5011 y(/*)238 b(values)46 b(of)h(interest)f
+(\(-1,0,)g(or)h(+1\))g(*/)143 5123 y(int)g(*status\))380
+b(/*)47 b(IO)g(-)h(error)e(status)g(*/)0 5375 y Fi(21)g
+Fj(P)m(arse)35 b(the)g(input)f(string)h(con)m(taining)h(a)f(list)h(of)f
+(ro)m(ws)f(or)h(ro)m(w)g(ranges,)h(and)e(return)g(in)m(teger)i(arra)m
+(ys)f(con-)227 5488 y(taining)27 b(the)f(\014rst)f(and)g(last)i(ro)m(w)
+f(in)f(eac)m(h)i(range.)40 b(F)-8 b(or)26 b(example,)i(if)d(ro)m(wlist)
+i(=)e("3-5,)k(6,)e(8-9")h(then)d(it)i(will)227 5601 y(return)34
+b(n)m(umranges)h(=)g(3,)h(rangemin)f(=)g(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
+5714 y(n)m(um)m(b)s(er)31 b(of)h(ranges)f(will)h(b)s(e)g(returned.)43
+b('maxro)m(ws')32 b(is)g(the)g(maxim)m(um)g(n)m(um)m(b)s(er)e(of)i(ro)m
+(ws)g(in)f(the)h(table;)p eop end
+%%Page: 71 79
+TeXDict begin 71 78 bop 0 299 a Fh(5.8.)72 b(UTILITY)30
+b(R)m(OUTINES)2693 b Fj(71)227 555 y(an)m(y)30 b(ro)m(ws)f(or)g(ranges)
+g(larger)h(than)f(this)g(will)g(b)s(e)g(ignored.)40 b(The)29
+b(ro)m(ws)g(m)m(ust)g(b)s(e)f(sp)s(eci\014ed)h(in)f(increasing)227
+668 y(order,)33 b(and)f(the)g(ranges)h(m)m(ust)f(not)g(o)m(v)m(erlap.)
+48 b(A)33 b(min)m(us)e(sign)i(ma)m(y)g(b)s(e)e(use)h(to)h(sp)s(ecify)f
+(all)h(the)g(ro)m(ws)f(to)227 781 y(the)h(upp)s(er)d(or)j(lo)m(w)m(er)h
+(b)s(ound,)d(so)i("50-")h(means)e(all)i(the)f(ro)m(ws)f(from)g(50)h(to)
+h(the)e(end)g(of)h(the)f(table,)j(and)227 894 y("-")d(means)e(all)h
+(the)g(ro)m(ws)f(in)g(the)h(table,)g(from)f(1)h(-)g(maxro)m(ws.)191
+1143 y Fe(int)47 b(fits_parse_range)c(/)48 b(ffrwrg\(char)c(*rowlist,)i
+(LONGLONG)f(maxrows,)h(int)h(maxranges,)e(>)334 1256
+y(int)i(*numranges,)e(long)h(*rangemin,)f(long)i(*rangemax,)e(int)i
+(*status\))191 1481 y(int)g(fits_parse_rangell)c(/)k(ffrwrgll\(char)d
+(*rowlist,)i(LONGLONG)f(maxrows,)h(int)h(maxranges,)e(>)334
+1594 y(int)i(*numranges,)e(LONGLONG)g(*rangemin,)g(LONGLONG)h
+(*rangemax,)f(int)i(*status\))0 1843 y Fi(22)f Fj(Chec)m(k)37
+b(that)g(the)g(Header)g(\014ll)g(b)m(ytes)g(\(if)g(an)m(y\))g(are)g
+(all)h(blank.)59 b(These)36 b(are)h(the)g(b)m(ytes)g(that)g(ma)m(y)h
+(follo)m(w)227 1956 y(END)e(k)m(eyw)m(ord)g(and)f(b)s(efore)g(the)h(b)s
+(eginning)f(of)h(data)g(unit,)g(or)g(the)g(end)f(of)g(the)h(HDU)g(if)g
+(there)f(is)h(no)227 2069 y(data)31 b(unit.)191 2318
+y Fe(int)47 b(ffchfl\(fitsfile)c(*fptr,)k(>)g(int)g(*status\))0
+2566 y Fi(23)f Fj(Chec)m(k)30 b(that)g(the)f(Data)i(\014ll)e(b)m(ytes)h
+(\(if)g(an)m(y\))g(are)g(all)g(zero)g(\(for)f(IMA)m(GE)i(or)e(BINAR)-8
+b(Y)30 b(T)-8 b(able)30 b(HDU\))h(or)e(all)227 2679 y(blanks)g(\(for)g
+(ASCI)s(I)f(table)i(HDU\).)g(These)f(\014le)g(b)m(ytes)h(ma)m(y)f(b)s
+(e)g(lo)s(cated)h(after)g(the)f(last)h(v)-5 b(alid)29
+b(data)h(b)m(yte)227 2792 y(in)g(the)h(HDU)g(and)f(b)s(efore)g(the)g
+(ph)m(ysical)h(end)f(of)h(the)f(HDU.)191 3041 y Fe(int)47
+b(ffcdfl\(fitsfile)c(*fptr,)k(>)g(int)g(*status\))0 3290
+y Fi(24)f Fj(Estimate)35 b(the)e(ro)s(ot-mean-squared)h(\(RMS\))f
+(noise)h(in)f(an)g(image.)51 b(These)33 b(routines)g(are)h(mainly)f
+(for)g(use)227 3403 y(with)25 b(the)g(Hcompress)g(image)i(compression)e
+(algorithm.)40 b(They)24 b(return)g(an)h(estimate)i(of)e(the)h(RMS)f
+(noise)227 3515 y(in)38 b(the)f(bac)m(kground)h(pixels)f(of)h(the)g
+(image.)64 b(This)36 b(robust)h(algorithm)i(\(written)f(b)m(y)f(Ric)m
+(hard)h(White,)227 3628 y(STScI\))e(\014rst)f(attempts)i(to)g(estimate)
+h(the)f(RMS)e(v)-5 b(alue)37 b(as)g(1.68)g(times)g(the)f(median)g(of)h
+(the)f(absolute)227 3741 y(di\013erences)26 b(b)s(et)m(w)m(een)h
+(successiv)m(e)g(pixels)f(in)g(the)g(image.)41 b(If)25
+b(the)h(median)g(=)f(0,)j(then)d(the)h(algorithm)h(falls)227
+3854 y(bac)m(k)h(to)f(computing)g(the)g(RMS)f(of)h(the)g(di\013erence)g
+(b)s(et)m(w)m(een)h(successiv)m(e)g(pixels,)f(after)h(sev)m(eral)g
+(N-sigma)227 3967 y(rejection)e(cycles)g(to)g(remo)m(v)m(e)g(extreme)g
+(v)-5 b(alues.)39 b(The)25 b(input)e(parameters)j(are:)38
+b(the)25 b(arra)m(y)g(of)g(image)i(pixel)227 4080 y(v)-5
+b(alues)30 b(\(either)h(\015oat)f(or)g(short)f(v)-5 b(alues\),)31
+b(the)f(n)m(um)m(b)s(er)e(of)i(v)-5 b(alues)30 b(in)g(the)g(arra)m(y)-8
+b(,)31 b(the)f(v)-5 b(alue)30 b(that)g(is)g(used)227
+4193 y(to)h(represen)m(t)g(n)m(ull)f(pixels)h(\(en)m(ter)g(a)g(v)m(ery)
+g(large)g(n)m(um)m(b)s(er)e(if)h(there)h(are)g(no)f(n)m(ull)g
+(pixels\).)191 4442 y Fe(int)47 b(fits_rms_float)d(\(float)i(fdata[],)f
+(int)i(npix,)g(float)f(in_null_value,)907 4555 y(>)h(double)f(*rms,)h
+(int)g(*status\))191 4668 y(int)g(fits_rms_short)d(\(short)i(fdata[],)f
+(int)i(npix,)g(short)f(in_null_value,)907 4780 y(>)h(double)f(*rms,)h
+(int)g(*status\))0 5029 y Fi(25)f Fj(W)-8 b(as)33 b(CFITSIO)d(compiled)
+h(with)h(the)f(-D)p 1612 5029 28 4 v 34 w(REENTRANT)g(directiv)m(e)i
+(so)e(that)h(it)g(ma)m(y)h(b)s(e)d(safely)j(used)d(in)227
+5142 y(m)m(ulti-threaded)d(en)m(vironmen)m(ts?)40 b(The)26
+b(follo)m(wing)i(function)e(returns)f(1)i(if)f(y)m(es,)i(0)f(if)f(no.)
+40 b(Note,)28 b(ho)m(w)m(ev)m(er,)227 5255 y(that)35
+b(ev)m(en)g(if)g(the)f(-D)p 991 5255 V 34 w(REENTRANT)f(directiv)m(e)j
+(w)m(as)f(sp)s(eci\014ed,)g(this)f(do)s(es)g(not)h(guaran)m(tee)h(that)
+f(the)227 5368 y(CFITSIO)29 b(routines)h(are)h(thread-safe,)g(b)s
+(ecause)g(some)f(compilers)h(ma)m(y)g(not)g(supp)s(ort)d(this)j
+(feature.)0 5617 y Fe(int)47 b(fits_is_reentrant\(void\))p
+eop end
+%%Page: 72 80
+TeXDict begin 72 79 bop 0 299 a Fj(72)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 end
+%%Page: 73 81
+TeXDict begin 73 80 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
+614 2180 V 34 w(data)i(function)e(in)h(CFITSIO)e(pro)m(vides)i(a)g
+(unique)e(metho)s(d)i(of)g(executing)h(an)e(arbitrary)0
+2293 y(user-supplied)35 b(`w)m(ork')i(function)f(that)h(op)s(erates)g
+(on)g(ro)m(ws)f(of)h(data)g(in)f(FITS)g(tables)h(or)f(on)h(pixels)f(in)
+h(FITS)0 2406 y(images.)i(Rather)24 b(than)e(explicitly)j(reading)e
+(and)g(writing)g(the)g(FITS)g(images)h(or)f(columns)g(of)g(data,)i(one)
+f(instead)0 2518 y(calls)36 b(the)g(CFITSIO)d(iterator)k(routine,)g
+(passing)e(to)h(it)g(the)f(name)g(of)h(the)f(user's)g(w)m(ork)g
+(function)g(that)h(is)f(to)0 2631 y(b)s(e)30 b(executed)h(along)g(with)
+f(a)h(list)g(of)f(all)h(the)f(table)i(columns)e(or)g(image)h(arra)m(ys)
+g(that)g(are)f(to)h(b)s(e)f(passed)g(to)h(the)0 2744
+y(w)m(ork)37 b(function.)61 b(The)37 b(CFITSIO)e(iterator)k(function)e
+(then)g(do)s(es)g(all)h(the)f(w)m(ork)g(of)h(allo)s(cating)h(memory)e
+(for)0 2857 y(the)28 b(arra)m(ys,)h(reading)f(the)g(input)e(data)j
+(from)e(the)h(FITS)f(\014le,)h(passing)g(them)g(to)g(the)g(w)m(ork)g
+(function,)g(and)f(then)0 2970 y(writing)36 b(an)m(y)h(output)f(data)h
+(bac)m(k)h(to)f(the)f(FITS)g(\014le)g(after)h(the)g(w)m(ork)g(function)
+f(exits.)59 b(Because)38 b(it)f(is)g(often)0 3083 y(more)g(e\016cien)m
+(t)i(to)f(pro)s(cess)f(only)g(a)h(subset)f(of)g(the)g(total)i(table)g
+(ro)m(ws)e(at)h(one)f(time,)j(the)e(iterator)g(function)0
+3196 y(can)31 b(determine)f(the)h(optim)m(um)f(amoun)m(t)h(of)f(data)h
+(to)g(pass)f(in)g(eac)m(h)i(iteration)f(and)f(rep)s(eatedly)h(call)g
+(the)g(w)m(ork)0 3309 y(function)f(un)m(til)h(the)f(en)m(tire)i(table)f
+(b)s(een)e(pro)s(cessed.)0 3469 y(F)-8 b(or)37 b(man)m(y)f
+(applications)h(this)e(single)i(CFITSIO)d(iterator)k(function)d(can)h
+(e\013ectiv)m(ely)j(replace)e(all)g(the)f(other)0 3582
+y(CFITSIO)g(routines)i(for)f(reading)h(or)f(writing)h(data)g(in)f(FITS)
+g(images)i(or)e(tables.)64 b(Using)37 b(the)h(iterator)h(has)0
+3695 y(sev)m(eral)32 b(imp)s(ortan)m(t)e(adv)-5 b(an)m(tages)32
+b(o)m(v)m(er)g(the)f(traditional)g(metho)s(d)f(of)h(reading)f(and)g
+(writing)g(FITS)g(data)h(\014les:)136 3961 y Fc(\017)46
+b Fj(It)33 b(cleanly)h(separates)g(the)f(data)h(I/O)f(from)f(the)h
+(routine)g(that)h(op)s(erates)f(on)g(the)g(data.)49 b(This)32
+b(leads)h(to)227 4074 y(a)e(more)g(mo)s(dular)e(and)h(`ob)5
+b(ject)31 b(orien)m(ted')h(programming)e(st)m(yle.)136
+4268 y Fc(\017)46 b Fj(It)27 b(simpli\014es)f(the)h(application)h
+(program)f(b)m(y)f(eliminating)i(the)f(need)g(to)g(allo)s(cate)i
+(memory)e(for)f(the)h(data)227 4381 y(arra)m(ys)e(and)f(eliminates)i
+(most)e(of)h(the)f(calls)i(to)f(the)g(CFITSIO)d(routines)j(that)g
+(explicitly)h(read)e(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)h(as)e(p)s(ossible.)44
+b(This)31 b(is)g(esp)s(ecially)i(imp)s(ortan)m(t)227
+4801 y(when)44 b(pro)s(cessing)g(tabular)h(data)h(since)f(the)g
+(iterator)h(function)e(will)h(calculate)i(the)e(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)f(the)h(table)g(to)g
+(b)s(e)f(passed)g(at)i(one)e(time)i(to)f(the)g(user's)e(w)m(ork)i
+(function)f(on)h(eac)m(h)227 5027 y(iteration.)136 5222
+y Fc(\017)46 b Fj(Mak)m(es)39 b(it)e(p)s(ossible)g(for)g(larger)h(pro)5
+b(jects)37 b(to)h(dev)m(elop)g(a)g(library)e(of)i(w)m(ork)f(functions)f
+(that)i(all)g(ha)m(v)m(e)h(a)227 5335 y(uniform)29 b(calling)j
+(sequence)f(and)f(are)h(all)g(indep)s(enden)m(t)e(of)i(the)f(details)i
+(of)e(the)h(FITS)e(\014le)i(format.)0 5601 y(There)f(are)h(basically)h
+(2)g(steps)e(in)h(using)f(the)h(CFITSIO)e(iterator)j(function.)42
+b(The)30 b(\014rst)g(step)h(is)g(to)g(design)g(the)0
+5714 y(w)m(ork)26 b(function)f(itself)h(whic)m(h)f(m)m(ust)h(ha)m(v)m
+(e)g(a)g(prescrib)s(ed)e(set)i(of)g(input)f(parameters.)39
+b(One)25 b(of)h(these)g(parameters)1905 5942 y(73)p eop
+end
+%%Page: 74 82
+TeXDict begin 74 81 bop 0 299 a Fj(74)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)f(a)g(structure)g(con)m(taining)i(p)s(oin)m(ters)d(to)i
+(the)f(arra)m(ys)h(of)f(data;)h(the)f(w)m(ork)h(function)e(can)i(p)s
+(erform)d(an)m(y)i(desired)0 668 y(op)s(erations)k(on)h(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)e(data)i(w)m(ere)f(read)g(from)0 781 y(the)e(\014le)f(or)g
+(ho)m(w)h(the)f(output)g(data)h(get)h(written)e(bac)m(k)h(to)h(the)e
+(\014le.)0 941 y(The)24 b(second)h(step)g(is)f(to)i(design)e(the)h
+(driv)m(er)g(routine)f(that)i(op)s(ens)e(all)h(the)g(necessary)g(FITS)f
+(\014les)h(and)f(initializes)0 1054 y(the)41 b(input)g(parameters)g(to)
+h(the)g(iterator)g(function.)73 b(The)41 b(driv)m(er)g(program)g(calls)
+h(the)g(CFITSIO)e(iterator)0 1167 y(function)30 b(whic)m(h)g(then)g
+(reads)g(the)h(data)g(and)f(passes)g(it)h(to)g(the)g(user's)e(w)m(ork)i
+(function.)0 1327 y(The)20 b(follo)m(wing)i(2)f(sections)g(describ)s(e)
+f(these)h(steps)g(in)f(more)g(detail.)39 b(There)20 b(are)h(also)g(sev)
+m(eral)h(example)f(programs)0 1440 y(included)30 b(with)g(the)g
+(CFITSIO)f(distribution)h(whic)m(h)g(illustrate)i(ho)m(w)e(to)h(use)f
+(the)h(iterator)g(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)f(iterator)j(w)m(ork)f(function)f(m)m(ust)g
+(ha)m(v)m(e)i(the)f(follo)m(wing)h(set)f(of)g(input)e(parameters)i
+(\(the)0 2156 y(function)30 b(can)h(b)s(e)e(giv)m(en)j(an)m(y)f
+(desired)e(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)24
+b({)f(the)f(total)j(n)m(um)m(b)s(er)c(of)h(table)i(ro)m(ws)e(or)g
+(image)i(pixels)f(that)g(will)f(b)s(e)g(passed)g(to)h(the)g(w)m(ork)f
+(function)227 2928 y(during)29 b(1)i(or)g(more)f(iterations.)136
+3129 y Fc(\017)46 b Fj(o\013set)d({)f(the)h(o\013set)f(applied)g(to)h
+(the)f(\014rst)f(table)i(ro)m(w)f(or)g(image)h(pixel)f(to)h(b)s(e)e
+(passed)g(to)i(the)f(w)m(ork)227 3241 y(function.)55
+b(In)34 b(other)i(w)m(ords,)g(this)f(is)g(the)g(n)m(um)m(b)s(er)f(of)h
+(ro)m(ws)h(or)f(pixels)g(that)h(are)f(skipp)s(ed)f(o)m(v)m(er)i(b)s
+(efore)227 3354 y(starting)30 b(the)g(iterations.)42
+b(If)28 b(o\013set)j(=)e(0,)h(then)f(all)h(the)f(table)i(ro)m(ws)e(or)g
+(image)i(pixels)e(will)h(b)s(e)e(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)h(ro)m(w)f(or)
+g(image)i(pixel)e(\(starting)i(with)e(1\))h(that)f(is)h(b)s(eing)e
+(passed)227 3781 y(in)k(this)h(particular)f(call)i(to)f(the)g(w)m(ork)f
+(function.)136 3982 y Fc(\017)46 b Fj(n)m(v)-5 b(alues)35
+b({)g(the)f(n)m(um)m(b)s(er)g(of)g(table)h(ro)m(ws)g(or)f(image)i
+(pixels)e(that)h(are)g(b)s(eing)f(passed)g(in)g(this)h(particular)227
+4095 y(call)h(to)g(the)f(w)m(ork)f(function.)54 b(n)m(v)-5
+b(alues)35 b(will)g(alw)m(a)m(ys)h(b)s(e)e(less)h(than)f(or)h(equal)g
+(to)h(totaln)g(and)e(will)h(ha)m(v)m(e)227 4208 y(the)f(same)f(v)-5
+b(alue)34 b(on)f(eac)m(h)h(iteration,)i(except)e(p)s(ossibly)f(on)g
+(the)g(last)h(call)h(whic)m(h)e(ma)m(y)g(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)g(passed)f(to)i(the)f(w)m(ork)g(function.)42
+b(There)30 b(is)227 4635 y(one)h(arra)m(y)g(for)f(eac)m(h)i(image)f(or)
+f(table)i(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)f(or)g
+(image.)42 b(Eac)m(h)29 b(structure)g(con)m(tains)h(a)g(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)g(as)g(other)
+g(descriptiv)m(e)g(parameters)g(ab)s(out)f(that)h(arra)m(y)-8
+b(.)136 5149 y Fc(\017)46 b Fj(*userP)m(oin)m(ter)26
+b({)g(a)f(user)f(supplied)g(p)s(oin)m(ter)h(that)h(can)f(b)s(e)f(used)h
+(to)g(pass)g(ancillary)h(information)f(from)g(the)227
+5262 y(driv)m(er)h(function)g(to)g(the)g(w)m(ork)g(function.)39
+b(This)25 b(p)s(oin)m(ter)h(is)g(passed)g(to)g(the)h(CFITSIO)d
+(iterator)j(function)227 5375 y(whic)m(h)37 b(then)f(passes)g(it)h(on)g
+(to)g(the)f(w)m(ork)h(function)f(without)h(an)m(y)g(mo)s(di\014cation.)
+59 b(It)37 b(ma)m(y)g(p)s(oin)m(t)f(to)i(a)227 5488 y(single)29
+b(n)m(um)m(b)s(er,)f(to)h(an)f(arra)m(y)h(of)g(v)-5 b(alues,)29
+b(to)g(a)g(structure)f(con)m(taining)i(an)e(arbitrary)g(set)h(of)g
+(parameters)227 5601 y(of)e(di\013eren)m(t)h(t)m(yp)s(es,)g(or)f(it)h
+(ma)m(y)f(b)s(e)g(a)g(n)m(ull)g(p)s(oin)m(ter)g(if)g(it)h(is)f(not)g
+(needed.)40 b(The)26 b(w)m(ork)h(function)g(m)m(ust)g(cast)227
+5714 y(this)k(p)s(oin)m(ter)f(to)h(the)g(appropriate)f(data)h(t)m(yp)s
+(e)g(b)s(efore)f(using)f(it)i(it.)p eop end
+%%Page: 75 83
+TeXDict begin 75 82 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(75)0 555 y(The)23
+b(totaln,)k(o\013set,)g(narra)m(ys,)e(data,)h(and)d(userP)m(oin)m(ter)i
+(parameters)f(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.)57 b(Only)34
+b(\014rstn,)i(n)m(v)-5 b(alues,)37 b(and)d(the)i(arra)m(ys)f(of)h(data)
+g(p)s(oin)m(ted)f(to)h(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)i(call)f(to)f
+(the)f(w)m(ork)h(function.)0 941 y(Note)43 b(that)g(the)f(iterator)h
+(treats)g(an)f(image)h(as)f(a)g(long)h(1-D)g(arra)m(y)f(of)h(pixels)f
+(regardless)g(of)g(it's)h(in)m(trinsic)0 1054 y(dimensionalit)m(y)-8
+b(.)52 b(The)33 b(total)j(n)m(um)m(b)s(er)c(of)i(pixels)g(is)g(just)f
+(the)h(pro)s(duct)e(of)i(the)g(size)h(of)e(eac)m(h)i(dimension,)g(and)0
+1167 y(the)e(order)g(of)g(the)g(pixels)g(is)g(the)g(same)g(as)g(the)h
+(order)e(that)h(they)h(are)f(stored)g(in)g(the)g(FITS)f(\014le.)48
+b(If)33 b(the)g(w)m(ork)0 1280 y(function)27 b(needs)g(to)h(kno)m(w)f
+(the)h(n)m(um)m(b)s(er)e(and)h(size)h(of)g(the)f(image)i(dimensions)d
+(then)h(these)h(parameters)g(can)g(b)s(e)0 1393 y(passed)i(via)h(the)f
+(userP)m(oin)m(ter)i(structure.)0 1553 y(The)e(iteratorCol)i(structure)
+e(is)g(curren)m(tly)h(de\014ned)e(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)g(reading)g(or)g(writing)g(the)f(elemen)m
+(ts)j(in)d(this)h(structure,)g(it)h(is)e(recommended)h(that)g(pro-)0
+4377 y(grammers)c(use)g(the)h(access)h(functions)d(that)i(are)g(pro)m
+(vided)f(for)g(this)h(purp)s(ose.)0 4538 y(The)25 b(\014rst)g(\014v)m
+(e)h(elemen)m(ts)h(in)f(this)f(structure)h(m)m(ust)f(b)s(e)g(initially)
+j(de\014ned)c(b)m(y)i(the)g(driv)m(er)f(routine)h(b)s(efore)f(calling)0
+4650 y(the)f(iterator)h(routine.)38 b(The)23 b(CFITSIO)f(iterator)j
+(routine)f(uses)f(this)g(information)h(to)g(determine)g(what)f(column)0
+4763 y(or)32 b(arra)m(y)h(to)h(pass)e(to)h(the)g(w)m(ork)f(function,)h
+(and)f(whether)g(the)g(arra)m(y)h(is)g(to)g(b)s(e)f(input)g(to)h(the)f
+(w)m(ork)h(function,)0 4876 y(output)g(from)g(the)h(w)m(ork)f
+(function,)h(or)g(b)s(oth.)49 b(The)33 b(CFITSIO)f(iterator)i(function)
+f(\014lls)h(in)f(the)g(v)-5 b(alues)34 b(of)g(the)0 4989
+y(remaining)c(structure)g(elemen)m(ts)i(b)s(efore)e(passing)g(it)h(to)g
+(the)g(w)m(ork)f(function.)0 5149 y(The)d(arra)m(y)g(structure)g
+(elemen)m(t)i(is)e(a)g(p)s(oin)m(ter)g(to)h(the)g(actual)g(data)g(arra)
+m(y)g(and)e(it)i(m)m(ust)f(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)i(is)f(used.)41
+b(The)31 b(`rep)s(eat')g(structure)g(elemen)m(t)h(giv)m(e)g(the)g(n)m
+(um)m(b)s(er)d(of)i(data)h(v)-5 b(alues)31 b(in)g(eac)m(h)0
+5375 y(ro)m(w)f(of)g(the)g(table,)i(so)e(that)h(the)f(total)i(n)m(um)m
+(b)s(er)c(of)i(data)h(v)-5 b(alues)30 b(in)g(the)g(arra)m(y)h(is)f(giv)
+m(en)h(b)m(y)f(rep)s(eat)g(*)g(n)m(v)-5 b(alues.)0 5488
+y(In)36 b(the)g(case)i(of)e(image)i(arra)m(ys)f(and)e(ASCI)s(I)g
+(tables,)k(rep)s(eat)e(will)g(alw)m(a)m(ys)g(b)s(e)f(equal)h(to)g(1.)59
+b(When)37 b(the)f(data)0 5601 y(t)m(yp)s(e)k(is)f(a)h(c)m(haracter)h
+(string,)h(the)e(arra)m(y)g(p)s(oin)m(ter)f(is)h(actually)h(a)f(p)s
+(oin)m(ter)f(to)i(an)e(arra)m(y)h(of)g(string)f(p)s(oin)m(ters)0
+5714 y(\(i.e.,)31 b(c)m(har)e(**arra)m(y\).)42 b(The)29
+b(other)g(output)g(structure)f(elemen)m(ts)j(are)e(pro)m(vided)g(for)f
+(con)m(v)m(enience)k(in)c(case)i(that)p eop end
+%%Page: 76 84
+TeXDict begin 76 83 bop 0 299 a Fj(76)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)36 b(is)g(needed)f(within)g(the)h(w)m(ork)g
+(function.)56 b(An)m(y)35 b(other)h(information)g(ma)m(y)g(b)s(e)f
+(passed)h(from)f(the)0 668 y(driv)m(er)30 b(routine)h(to)g(the)f(w)m
+(ork)h(function)f(via)h(the)f(userP)m(oin)m(ter)h(parameter.)0
+828 y(Up)s(on)g(completion,)j(the)e(w)m(ork)h(routine)f(m)m(ust)g
+(return)f(an)h(in)m(teger)h(status)f(v)-5 b(alue,)34
+b(with)d(0)i(indicating)g(success)0 941 y(and)e(an)m(y)g(other)g(v)-5
+b(alue)32 b(indicating)g(an)f(error)g(whic)m(h)g(will)g(cause)h(the)f
+(iterator)i(function)e(to)h(immediately)g(exit)0 1054
+y(at)27 b(that)f(p)s(oin)m(t.)39 b(Return)25 b(status)i(v)-5
+b(alues)26 b(in)f(the)h(range)h(1)f({)g(1000)i(should)c(b)s(e)i(a)m(v)m
+(oided)h(since)f(these)h(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)24 b(of)g(-1)g(ma)m(y)g
+(b)s(e)f(used)f(to)j(force)f(the)f(CFITSIO)f(iterator)j(function)0
+1280 y(to)i(stop)g(at)g(that)h(p)s(oin)m(t)e(and)g(return)g(con)m(trol)
+i(to)f(the)g(driv)m(er)f(routine)h(after)g(writing)f(an)m(y)h(output)f
+(arra)m(ys)h(to)h(the)0 1393 y(FITS)e(\014le.)40 b(CFITSIO)26
+b(do)s(es)g(not)i(considered)f(this)g(to)h(b)s(e)e(an)h(error)g
+(condition,)i(so)e(an)m(y)g(further)f(pro)s(cessing)h(b)m(y)0
+1506 y(the)k(application)g(program)f(will)h(con)m(tin)m(ue)h(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)h(driv)m(er)f(function)g(m)m
+(ust)h(op)s(en)e(the)i(necessary)f(FITS)g(\014les)g(and)g(p)s(osition)g
+(them)g(to)h(the)g(correct)0 2200 y(HDU.)23 b(It)f(m)m(ust)g(also)i
+(initialize)g(the)e(follo)m(wing)i(parameters)e(in)g(the)h(iteratorCol)
+h(structure)d(\(de\014ned)g(ab)s(o)m(v)m(e\))j(for)0
+2313 y(eac)m(h)31 b(column)f(or)g(image)h(b)s(efore)e(calling)j(the)e
+(CFITSIO)e(iterator)j(function.)40 b(Sev)m(eral)31 b(`constructor')g
+(routines)0 2426 y(are)g(pro)m(vided)f(in)g(CFITSIO)f(for)h(this)g
+(purp)s(ose.)136 2670 y Fc(\017)46 b Fj(*fptr)30 b({)h(The)f
+(\014ts\014le)g(p)s(oin)m(ter)g(to)i(the)e(table)h(or)g(image.)136
+2853 y Fc(\017)46 b Fj(coln)m(um)30 b({)f(the)h(n)m(um)m(b)s(er)e(of)h
+(the)h(column)f(in)g(the)g(table.)42 b(This)28 b(v)-5
+b(alue)30 b(is)f(ignored)g(in)g(the)h(case)g(of)g(images.)227
+2966 y(If)j(coln)m(um)h(equals)g(0,)g(then)g(the)f(column)g(name)h
+(will)f(b)s(e)g(used)g(to)h(iden)m(tify)g(the)f(column)h(to)g(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)32 b({)e(the)g(name)h(\(TTYPEn)e(k)m
+(eyw)m(ord\))i(of)f(the)h(column.)40 b(This)29 b(is)i(only)f(required)f
+(if)h(coln)m(um)h(=)f(0)227 3374 y(and)g(is)g(ignored)h(for)f(images.)
+136 3556 y Fc(\017)46 b Fj(datat)m(yp)s(e)29 b({)g(The)e(desired)h
+(data)g(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.)40 b(F)-8 b(or)28 b(n)m(umer-)227
+3669 y(ical)h(data)f(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)g(data)g(t)m(yp)s(e)g(in)f
+(the)g(FITS)g(\014le,)227 3782 y(in)h(whic)m(h)h(case)g(CFITSIO)e(will)
+i(do)g(the)f(con)m(v)m(ersion.)42 b(Allo)m(w)m(ed)30
+b(v)-5 b(alues)29 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)f(v)-5
+b(alue)33 b(of)g(data)h(t)m(yp)s(e)f(equals)g(0,)i(then)d(the)h
+(existing)h(data)g(t)m(yp)s(e)f(of)g(the)g(column)g(or)227
+4121 y(image)f(will)f(b)s(e)e(used)h(without)g(an)m(y)h(con)m(v)m
+(ersion.)136 4303 y Fc(\017)46 b Fj(iot)m(yp)s(e)37 b({)f(de\014nes)e
+(whether)h(the)h(data)g(arra)m(y)g(is)g(to)g(b)s(e)f(input)g(to)h(the)g
+(w)m(ork)f(function)h(\(i.e,)i(read)d(from)227 4416 y(the)42
+b(FITS)e(\014le\),)k(or)d(output)g(from)g(the)g(w)m(ork)g(function)g
+(\(i.e.,)k(written)c(to)h(the)f(FITS)g(\014le\))g(or)g(b)s(oth.)227
+4529 y(Allo)m(w)m(ed)30 b(v)-5 b(alues)29 b(are)f(InputCol,)g
+(OutputCol,)h(or)f(InputOutputCol.)38 b(V)-8 b(ariable-length)30
+b(arra)m(y)f(columns)227 4642 y(are)h(supp)s(orted)e(as)i(InputCol)e
+(or)i(InputOutputCol)d(t)m(yp)s(es,)j(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)g(routine)g(has)g(initialized)j(all)e
+(these)f(parameters,)h(it)g(can)g(then)f(call)h(the)g(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)g(or)h
+(images)g(that)g(are)g(to)g(b)s(e)f(passed)g(to)h(the)f(w)m(ork)h
+(function.)p eop end
+%%Page: 77 85
+TeXDict begin 77 84 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(77)136 555 y Fc(\017)46 b Fj(*data)32 b({)f(p)s(oin)m(ter)f(to)h
+(arra)m(y)g(of)f(structures)g(con)m(taining)i(information)f(ab)s(out)f
+(eac)m(h)h(column)g(or)f(image.)136 736 y Fc(\017)46
+b Fj(o\013set)31 b({)f(if)f(p)s(ositiv)m(e,)i(this)f(n)m(um)m(b)s(er)e
+(of)i(ro)m(ws)f(at)h(the)g(b)s(eginning)f(of)h(the)f(table)i(\(or)f
+(pixels)f(in)h(the)f(image\))227 849 y(will)i(b)s(e)f(skipp)s(ed)f(and)
+g(will)i(not)g(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)e(the)i
+(n)m(um)m(b)s(er)e(of)h(table)h(ro)m(ws)g(\(or)f(n)m(um)m(b)s(er)f(of)i
+(image)g(pixels\))g(that)g(are)g(to)g(b)s(e)227 1143
+y(passed)29 b(to)h(the)f(w)m(ork)h(function)e(on)h(eac)m(h)i
+(iteration.)42 b(If)28 b(nP)m(erLo)s(op)h(=)g(0)g(then)g(CFITSIO)f
+(will)i(calculate)227 1256 y(the)22 b(optim)m(um)g(n)m(um)m(b)s(er)e
+(for)h(greatest)j(e\016ciency)-8 b(.)39 b(If)21 b(nP)m(erLo)s(op)g(is)h
+(negativ)m(e,)k(then)21 b(all)i(the)f(ro)m(ws)f(or)h(pixels)227
+1368 y(will)36 b(b)s(e)f(passed)g(at)h(one)g(time,)i(and)c(the)i(w)m
+(ork)g(function)f(will)h(only)f(b)s(e)g(called)i(once.)56
+b(If)35 b(an)m(y)h(v)-5 b(ariable)227 1481 y(length)33
+b(arra)m(ys)g(are)g(b)s(eing)f(pro)s(cessed,)h(then)g(the)f(nP)m(erLo)s
+(op)h(v)-5 b(alue)33 b(is)f(ignored,)i(and)e(the)h(iterator)h(will)227
+1594 y(alw)m(a)m(ys)e(pro)s(cess)e(one)h(ro)m(w)f(of)h(the)f(table)i
+(at)f(a)g(time.)136 1775 y Fc(\017)46 b Fj(*w)m(orkFn)f(-)f(the)h(name)
+f(\(actually)i(the)f(address\))f(of)g(the)g(w)m(ork)h(function)f(that)h
+(is)f(to)h(b)s(e)f(called)h(b)m(y)227 1888 y(\014ts)p
+354 1888 28 4 v 33 w(iterate)p 643 1888 V 34 w(data.)136
+2069 y Fc(\017)h Fj(*userP)m(oin)m(ter)34 b(-)f(this)g(is)g(a)g(user)f
+(supplied)g(p)s(oin)m(ter)h(that)g(can)g(b)s(e)g(used)f(to)h(pass)g
+(ancillary)h(information)227 2182 y(from)f(the)g(driv)m(er)g(routine)g
+(to)h(the)f(w)m(ork)g(function.)48 b(It)33 b(ma)m(y)h(p)s(oin)m(t)f(to)
+h(a)f(single)h(n)m(um)m(b)s(er,)e(an)h(arra)m(y)-8 b(,)35
+b(or)227 2295 y(to)c(a)g(structure)f(con)m(taining)i(an)e(arbitrary)g
+(set)h(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)27
+b(=)h(0)h(on)g(input;)f(a)h(non-zero)h(output)e(v)-5
+b(alue)29 b(indicates)227 2588 y(an)i(error.)0 2828 y(When)f(\014ts)p
+392 2828 V 32 w(iterate)p 680 2828 V 35 w(data)h(is)f(called)h(it)f
+(\014rst)g(allo)s(cates)i(memory)e(to)h(hold)e(all)i(the)f(requested)g
+(columns)g(of)g(data)0 2941 y(or)f(image)i(pixel)e(arra)m(ys.)41
+b(It)29 b(then)g(reads)g(the)h(input)e(data)i(from)f(the)g(FITS)f
+(tables)i(or)g(images)g(in)m(to)g(the)g(arra)m(ys)0 3054
+y(then)h(passes)h(the)g(structure)f(with)g(p)s(oin)m(ters)h(to)g(these)
+g(data)h(arra)m(ys)f(to)g(the)g(w)m(ork)g(function.)44
+b(After)32 b(the)g(w)m(ork)0 3167 y(function)37 b(returns,)g(the)h
+(iterator)g(function)f(writes)g(an)m(y)g(output)g(columns)f(of)h(data)h
+(or)f(images)h(bac)m(k)g(to)g(the)0 3279 y(FITS)31 b(\014les.)46
+b(It)32 b(then)g(rep)s(eats)g(this)g(pro)s(cess)g(for)f(an)m(y)i
+(remaining)f(sets)g(of)h(ro)m(ws)f(or)g(image)h(pixels)f(un)m(til)h(it)
+f(has)0 3392 y(pro)s(cessed)27 b(the)i(en)m(tire)g(table)f(or)g(image)i
+(or)e(un)m(til)g(the)g(w)m(ork)g(function)g(returns)f(a)h(non-zero)h
+(status)f(v)-5 b(alue.)40 b(The)0 3505 y(iterator)33
+b(then)f(frees)g(the)h(memory)e(that)i(it)g(initially)g(allo)s(cated)h
+(and)e(returns)f(con)m(trol)i(to)g(the)f(driv)m(er)g(routine)0
+3618 y(that)f(called)h(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,)i(o\013set,)h(\014rstn,)d(and)f(n)m(v)-5
+b(alues)35 b(parameters)f(that)h(are)f(passed)g(to)h(the)f(w)m(ork)g
+(function)g(are)h(useful)0 4312 y(for)f(determining)g(ho)m(w)g(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)g(left)h(to)g(do.)52 b(On)0 4425 y(the)36
+b(v)m(ery)h(\014rst)f(call)h(to)g(the)f(w)m(ork)h(function)f(\014rstn)f
+(will)h(b)s(e)g(equal)h(to)g(o\013set)g(+)f(1;)k(the)c(w)m(ork)g
+(function)g(ma)m(y)0 4538 y(need)31 b(to)g(p)s(erform)f(v)-5
+b(arious)31 b(initialization)i(tasks)f(b)s(efore)e(starting)i(to)f(pro)
+s(cess)g(the)g(data.)43 b(Similarly)-8 b(,)32 b(\014rstn)d(+)0
+4650 y(n)m(v)-5 b(alues)29 b(-)f(1)h(will)f(b)s(e)g(equal)g(to)h
+(totaln)h(on)e(the)g(last)h(iteration,)i(at)e(whic)m(h)f(p)s(oin)m(t)g
+(the)g(w)m(ork)h(function)e(ma)m(y)i(need)0 4763 y(to)k(p)s(erform)f
+(some)h(clean)h(up)d(op)s(erations)i(b)s(efore)g(exiting)h(for)e(the)h
+(last)h(time.)48 b(The)33 b(w)m(ork)f(function)h(can)g(also)0
+4876 y(force)e(an)f(early)h(termination)g(of)g(the)g(iterations)g(b)m
+(y)g(returning)e(a)i(status)g(v)-5 b(alue)30 b(=)g(-1.)0
+5036 y(The)f(narra)m(ys)g(and)g(iteratorCol.datat)m(yp)s(e)j(argumen)m
+(ts)e(allo)m(w)g(the)g(w)m(ork)f(function)g(to)h(double)f(c)m(hec)m(k)i
+(that)f(the)0 5149 y(n)m(um)m(b)s(er)k(of)i(input)f(arra)m(ys)h(and)f
+(their)g(data)i(t)m(yp)s(es)e(ha)m(v)m(e)i(the)f(exp)s(ected)g(v)-5
+b(alues.)57 b(The)35 b(iteratorCol.fptr)i(and)0 5262
+y(iteratorCol.coln)m(um)d(structure)d(elemen)m(ts)h(can)g(b)s(e)f(used)
+f(if)i(the)f(w)m(ork)h(function)f(needs)g(to)h(read)f(or)g(write)h(the)
+0 5375 y(v)-5 b(alues)31 b(of)g(other)g(k)m(eyw)m(ords)g(in)g(the)g
+(FITS)f(\014le)h(asso)s(ciated)h(with)f(the)g(arra)m(y)-8
+b(.)43 b(This)30 b(should)g(generally)i(only)f(b)s(e)0
+5488 y(done)j(during)e(the)i(initialization)j(step)c(or)h(during)f(the)
+h(clean)g(up)f(step)h(after)g(the)g(last)h(set)f(of)g(data)g(has)g(b)s
+(een)0 5601 y(pro)s(cessed.)40 b(Extra)29 b(FITS)f(\014le)h(I/O)g
+(during)e(the)i(main)g(pro)s(cessing)g(lo)s(op)g(of)g(the)g(w)m(ork)g
+(function)g(can)g(seriously)0 5714 y(degrade)i(the)f(sp)s(eed)g(of)g
+(the)h(program.)p eop end
+%%Page: 78 86
+TeXDict begin 78 85 bop 0 299 a Fj(78)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)35 b(arra)m(y)e(columns)g(are)g(b)s
+(eing)f(pro)s(cessed,)h(then)g(the)g(iterator)h(will)f(op)s(erate)h(on)
+f(one)g(ro)m(w)g(of)0 668 y(the)j(table)g(at)g(a)g(time.)57
+b(In)34 b(this)i(case)g(the)g(the)f(rep)s(eat)h(elemen)m(t)h(in)e(the)h
+(in)m(teratorCol)h(structure)e(will)h(b)s(e)e(set)0 781
+y(equal)d(to)g(the)g(n)m(um)m(b)s(er)e(of)h(elemen)m(ts)i(in)e(the)h
+(curren)m(t)f(ro)m(w)g(that)h(is)g(b)s(eing)f(pro)s(cessed.)0
+941 y(One)j(imp)s(ortan)m(t)g(feature)h(of)f(the)h(iterator)h(is)e
+(that)h(the)f(\014rst)g(elemen)m(t)i(in)e(eac)m(h)h(arra)m(y)g(that)g
+(is)f(passed)g(to)h(the)0 1054 y(w)m(ork)f(function)g(giv)m(es)h(the)f
+(v)-5 b(alue)33 b(that)h(is)f(used)f(to)h(represen)m(t)g(n)m(ull)g(or)g
+(unde\014ned)d(v)-5 b(alues)34 b(in)e(the)h(arra)m(y)-8
+b(.)49 b(The)0 1167 y(real)41 b(data)g(then)g(b)s(egins)f(with)g(the)g
+(second)h(elemen)m(t)h(of)f(the)f(arra)m(y)h(\(i.e.,)k(arra)m(y[1],)g
+(not)c(arra)m(y[0]\).)73 b(If)40 b(the)0 1280 y(\014rst)e(arra)m(y)h
+(elemen)m(t)h(is)f(equal)g(to)g(zero,)j(then)c(this)g(indicates)i(that)
+f(all)h(the)e(arra)m(y)h(elemen)m(ts)h(ha)m(v)m(e)g(de\014ned)0
+1393 y(v)-5 b(alues)33 b(and)f(there)h(are)g(no)g(unde\014ned)d(v)-5
+b(alues.)48 b(If)33 b(arra)m(y[0])h(is)f(not)g(equal)g(to)g(zero,)i
+(then)d(this)h(indicates)g(that)0 1506 y(some)h(of)g(the)g(data)h(v)-5
+b(alues)34 b(are)g(unde\014ned)d(and)j(this)f(v)-5 b(alue)35
+b(\(arra)m(y[0]\))h(is)d(used)g(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.,)i
+(those)e(arra)m(ys)g(that)g(will)g(b)s(e)f(written)g(bac)m(k)h(to)h
+(the)e(FITS)g(\014le)g(b)m(y)h(the)g(iterator)0 1732
+y(function)h(after)i(the)f(w)m(ork)f(function)h(exits\))h(the)f(w)m
+(ork)g(function)f(m)m(ust)h(set)g(the)g(\014rst)f(arra)m(y)h(elemen)m
+(t)h(to)g(the)0 1844 y(desired)g(n)m(ull)g(v)-5 b(alue)37
+b(if)g(necessary)-8 b(,)40 b(otherwise)e(the)f(\014rst)g(elemen)m(t)h
+(should)e(b)s(e)h(set)g(to)h(zero)g(to)g(indicate)g(that)0
+1957 y(there)30 b(are)h(no)e(n)m(ull)h(v)-5 b(alues)31
+b(in)e(the)h(output)g(arra)m(y)-8 b(.)42 b(CFITSIO)28
+b(de\014nes)h(2)h(v)-5 b(alues,)31 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)f(n)m(ull)g(v)-5 b(alues)36 b(for)g(\015oat)h(and)
+e(double)h(data)h(t)m(yp)s(es,)0 2183 y(resp)s(ectiv)m(ely)-8
+b(.)60 b(In)35 b(the)i(case)g(of)f(c)m(haracter)i(string)e(data)h(t)m
+(yp)s(es,)h(a)e(n)m(ull)h(string)f(is)g(alw)m(a)m(ys)i(used)d(to)i
+(represen)m(t)0 2296 y(unde\014ned)28 b(strings.)0 2456
+y(In)33 b(some)h(applications)g(it)g(ma)m(y)g(b)s(e)f(necessary)h(to)g
+(recursiv)m(ely)g(call)h(the)f(iterator)h(function.)50
+b(An)33 b(example)h(of)0 2569 y(this)27 b(is)g(giv)m(en)h(b)m(y)f(one)h
+(of)f(the)h(example)f(programs)g(that)h(is)f(distributed)f(with)h
+(CFITSIO:)f(it)i(\014rst)e(calls)i(a)g(w)m(ork)0 2682
+y(function)38 b(that)g(writes)h(out)f(a)g(2D)h(histogram)g(image.)65
+b(That)38 b(w)m(ork)g(function)g(in)f(turn)g(calls)j(another)e(w)m(ork)
+0 2795 y(function)29 b(that)h(reads)g(the)f(`X')i(and)e(`Y')h(columns)f
+(in)g(a)h(table)h(to)f(calculate)i(the)d(v)-5 b(alue)31
+b(of)e(eac)m(h)i(2D)f(histogram)0 2908 y(image)i(pixel.)41
+b(Graphically)-8 b(,)32 b(the)e(program)g(structure)g(can)h(b)s(e)f
+(describ)s(ed)f(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(,)42 b(it)d(should)e(b)s(e)h(noted)g(that)h(the)g
+(table)g(columns)f(or)g(image)i(arra)m(ys)f(that)g(are)f(passed)g(to)h
+(the)g(w)m(ork)0 3512 y(function)c(do)h(not)g(all)g(ha)m(v)m(e)h(to)f
+(come)h(from)e(the)h(same)g(FITS)f(\014le)g(and)g(instead)h(ma)m(y)g
+(come)h(from)e(an)m(y)h(com-)0 3625 y(bination)d(of)g(sources)g(as)h
+(long)f(as)h(they)f(ha)m(v)m(e)h(the)f(same)h(length.)49
+b(The)32 b(length)i(of)f(the)g(\014rst)f(table)i(column)f(or)0
+3738 y(image)f(arra)m(y)f(is)f(used)f(b)m(y)i(the)f(iterator)i(if)e
+(they)h(do)f(not)h(all)g(ha)m(v)m(e)h(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)36 b(of)f(the)g(iterator)h(routines)f(are)g(listed)h(b)s
+(elo)m(w.)54 b(Most)36 b(of)f(these)h(routines)e(do)h(not)g(ha)m(v)m(e)
+i(a)e(corresp)s(onding)0 4432 y(short)30 b(function)g(name.)0
+4678 y Fi(1)81 b Fj(Iterator)32 b(`constructor')h(functions)e(that)i
+(set)f(the)g(v)-5 b(alue)32 b(of)g(elemen)m(ts)h(in)f(the)g
+(iteratorCol)h(structure)e(that)227 4791 y(de\014ne)k(the)h(columns)f
+(or)h(arra)m(ys.)56 b(These)36 b(set)g(the)g(\014ts\014le)f(p)s(oin)m
+(ter,)i(column)e(name,)j(column)d(n)m(um)m(b)s(er,)227
+4904 y(datat)m(yp)s(e,)28 b(and)e(iot)m(yp)s(e,)i(resp)s(ectiv)m(ely)-8
+b(.)41 b(The)25 b(last)i(2)g(routines)f(allo)m(w)h(all)g(the)f
+(parameters)h(to)f(b)s(e)g(set)g(with)227 5017 y(one)31
+b(function)f(call)i(\(one)f(supplies)e(the)i(column)f(name,)h(the)f
+(other)h(the)f(column)g(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 end
+%%Page: 79 87
+TeXDict begin 79 86 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(79)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)e(that)g(return)g(the)g(v)-5
+b(alue)38 b(of)f(the)g(elemen)m(t)i(in)e(the)g(iteratorCol)i(structure)
+227 1933 y(that)31 b(describ)s(es)f(a)h(particular)f(data)h(column)g
+(or)f(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)j(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 end
+%%Page: 80 88
+TeXDict begin 80 87 bop 0 299 a Fj(80)1455 b Fh(CHAPTER)30
+b(6.)112 b(THE)30 b(CFITSIO)e(ITERA)-8 b(TOR)30 b(FUNCTION)p
+eop end
+%%Page: 81 89
+TeXDict begin 81 88 bop 0 1225 a Fg(Chapter)65 b(7)0
+1687 y Fm(W)-19 b(orld)77 b(Co)6 b(ordinate)78 b(System)f(Routines)0
+2180 y Fj(The)36 b(FITS)g(comm)m(unit)m(y)h(has)f(adopted)h(a)g(set)g
+(of)g(k)m(eyw)m(ord)g(con)m(v)m(en)m(tions)h(that)f(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)g(lo)s(cations)h(in)e(an)h(image)h(and)e(the)g(corresp)s
+(onding)g(celestial)j(co)s(ordinates)0 2406 y(on)25 b(the)h(sky)-8
+b(,)27 b(or)e(more)g(generally)-8 b(,)29 b(that)d(de\014ne)e(w)m(orld)h
+(co)s(ordinates)i(that)e(are)h(to)g(b)s(e)f(asso)s(ciated)i(with)e(an)m
+(y)h(pixel)0 2518 y(lo)s(cation)h(in)e(an)h(n-dimensional)f(FITS)g
+(arra)m(y)-8 b(.)40 b(CFITSIO)24 b(is)h(distributed)g(with)g(a)h(a)g
+(few)f(self-con)m(tained)i(W)-8 b(orld)0 2631 y(Co)s(ordinate)30
+b(System)g(\(W)m(CS\))g(routines,)g(ho)m(w)m(ev)m(er,)i(these)e
+(routines)g(DO)f(NOT)h(supp)s(ort)e(all)j(the)f(latest)h(W)m(CS)0
+2744 y(con)m(v)m(en)m(tions,)38 b(so)c(it)h(is)g(STR)m(ONGL)-8
+b(Y)34 b(RECOMMENDED)h(that)g(soft)m(w)m(are)h(dev)m(elop)s(ers)e(use)g
+(a)h(more)g(robust)0 2857 y(external)c(W)m(CS)g(library)-8
+b(.)40 b(Sev)m(eral)32 b(recommended)e(libraries)g(are:)95
+3138 y Fe(WCSLIB)47 b(-)95 b(supported)45 b(by)i(Mark)g(Calabretta)95
+3251 y(WCSTools)f(-)h(supported)f(by)h(Doug)g(Mink)95
+3364 y(AST)g(library)f(-)i(developed)d(by)i(the)g(U.K.)g(Starlink)e
+(project)0 3644 y Fj(More)30 b(information)f(ab)s(out)g(the)g(W)m(CS)g
+(k)m(eyw)m(ord)h(con)m(v)m(en)m(tions)h(and)d(links)h(to)h(all)g(of)f
+(these)g(W)m(CS)g(libraries)h(can)0 3757 y(b)s(e)g(found)f(on)h(the)h
+(FITS)e(Supp)s(ort)g(O\016ce)h(w)m(eb)g(site)i(at)f(h)m
+(ttp://\014ts.gsfc.nasa.go)m(v)j(under)29 b(the)h(W)m(CS)h(link.)0
+3917 y(The)40 b(functions)h(pro)m(vided)g(in)f(these)i(external)f(W)m
+(CS)g(libraries)h(will)f(need)g(access)h(to)f(the)h(W)m(CS)f(k)m(eyw)m
+(ords)0 4030 y(con)m(tained)36 b(in)f(the)h(FITS)e(\014le)i(headers.)55
+b(One)35 b(con)m(v)m(enien)m(t)i(w)m(a)m(y)f(to)g(pass)f(this)g
+(information)h(to)g(the)f(external)0 4143 y(library)c(is)f(to)i(use)f
+(the)g(\014ts)p 942 4143 28 4 v 32 w(hdr2str)f(routine)h(in)g(CFITSIO)e
+(\(de\014ned)h(b)s(elo)m(w\))h(to)h(cop)m(y)g(the)f(header)g(k)m(eyw)m
+(ords)0 4256 y(in)m(to)k(one)e(long)i(string,)f(and)f(then)g(pass)g
+(this)h(string)f(to)i(an)e(in)m(terface)i(routine)f(in)f(the)h
+(external)g(library)f(that)0 4369 y(will)d(extract)h(the)f(necessary)f
+(W)m(CS)h(information)g(\(e.g.,)h(the)f('w)m(cspih')g(routine)f(in)g
+(the)h(W)m(CSLIB)f(library)h(and)0 4482 y(the)h('astFitsChan')g(and)f
+('astPutCards')g(functions)g(in)g(the)h(AST)e(library\).)0
+4763 y Fi(1)81 b Fj(Concatenate)38 b(the)f(header)f(k)m(eyw)m(ords)h
+(in)f(the)g(CHDU)h(in)m(to)h(a)f(single)g(long)g(string)f(of)h(c)m
+(haracters.)60 b(Eac)m(h)227 4876 y(80-c)m(haracter)28
+b(\014xed-length)c(k)m(eyw)m(ord)h(record)g(is)g(app)s(ended)d(to)k
+(the)f(output)f(c)m(haracter)i(string,)g(in)e(order,)227
+4989 y(with)h(no)f(in)m(terv)m(ening)i(separator)f(or)g(terminating)h
+(c)m(haracters.)40 b(The)24 b(last)i(header)e(record)h(is)f(terminated)
+227 5101 y(with)33 b(a)g(NULL)f(c)m(haracter.)49 b(This)32
+b(routine)h(allo)s(cates)i(memory)d(for)h(the)g(returned)e(c)m
+(haracter)j(arra)m(y)-8 b(,)35 b(so)227 5214 y(the)c(calling)h(program)
+e(m)m(ust)g(free)h(the)f(memory)g(when)g(\014nished.)227
+5375 y(There)c(are)h(2)f(related)h(routines:)39 b(\014ts)p
+1514 5375 V 32 w(hdr2str)25 b(simply)h(concatenates)j(all)e(the)f
+(existing)h(k)m(eyw)m(ords)g(in)f(the)227 5488 y(header;)40
+b(\014ts)p 682 5488 V 32 w(con)m(v)m(ert)p 1003 5488
+V 34 w(hdr2str)35 b(is)i(similar,)h(except)f(that)g(if)f(the)h(CHDU)f
+(is)h(a)f(tile)i(compressed)e(image)227 5601 y(\(stored)28
+b(in)g(a)f(binary)g(table\))i(then)e(it)h(will)g(\014rst)f(con)m(v)m
+(ert)i(that)f(header)g(bac)m(k)g(to)g(that)g(of)g(a)g(normal)g(FITS)227
+5714 y(image)k(b)s(efore)e(concatenating)j(the)d(k)m(eyw)m(ords.)1905
+5942 y(81)p eop end
+%%Page: 82 90
+TeXDict begin 82 89 bop 0 299 a Fj(82)1169 b Fh(CHAPTER)29
+b(7.)112 b(W)m(ORLD)31 b(COORDINA)-8 b(TE)30 b(SYSTEM)f(R)m(OUTINES)227
+555 y Fj(Selected)h(k)m(eyw)m(ords)e(ma)m(y)h(b)s(e)e(excluded)h(from)g
+(the)g(returned)f(c)m(haracter)j(string.)40 b(If)27 b(the)i(second)f
+(param-)227 668 y(eter)h(\(no)s(commen)m(ts\))g(is)f(TR)m(UE)g
+(\(nonzero\))h(then)e(an)m(y)i(COMMENT,)f(HISTOR)-8 b(Y,)27
+b(or)h(blank)g(k)m(eyw)m(ords)227 781 y(in)i(the)h(header)f(will)h(not)
+f(b)s(e)g(copied)h(to)g(the)g(output)f(string.)227 924
+y(The)25 b('exclist')j(parameter)e(ma)m(y)g(b)s(e)f(used)g(to)h(supply)
+e(a)i(list)h(of)e(k)m(eyw)m(ords)h(that)h(are)f(to)g(b)s(e)f(excluded)g
+(from)227 1037 y(the)k(output)g(c)m(haracter)h(string.)41
+b(Wild)29 b(card)g(c)m(haracters)h(\(*,)g(?,)f(and)g(#\))g(ma)m(y)g(b)s
+(e)f(used)g(in)h(the)g(excluded)227 1150 y(k)m(eyw)m(ord)h(names.)41
+b(If)29 b(no)g(additional)i(k)m(eyw)m(ords)f(are)g(to)g(b)s(e)f
+(excluded,)h(then)f(set)h(nexc)g(=)f(0)h(and)f(sp)s(ecify)227
+1263 y(NULL)i(for)f(the)g(the)h(**exclist)i(parameter.)95
+1478 y Fe(int)47 b(fits_hdr2str)286 1591 y(\(fitsfile)f(*fptr,)g(int)h
+(nocomments,)d(char)j(**exclist,)e(int)i(nexc,)286 1704
+y(>)h(char)e(**header,)g(int)h(*nkeys,)e(int)i(*status\))95
+1930 y(int)g(fits_convert_hdr2str)c(/)k(ffcnvthdr2str)286
+2043 y(\(fitsfile)f(*fptr,)g(int)h(nocomments,)d(char)j(**exclist,)e
+(int)i(nexc,)286 2155 y(>)h(char)e(**header,)g(int)h(*nkeys,)e(int)i
+(*status\))0 2371 y Fi(2)81 b Fj(The)24 b(follo)m(wing)j(CFITSIO)d
+(routine)i(is)f(sp)s(eci\014cally)h(designed)f(for)h(use)f(in)g
+(conjunction)g(with)g(the)h(W)m(CSLIB)227 2484 y(library)-8
+b(.)40 b(It)27 b(is)h(not)f(exp)s(ected)h(that)g(applications)g
+(programmers)f(will)h(call)g(this)f(routine)h(directly)-8
+b(,)29 b(but)d(it)227 2597 y(is)33 b(do)s(cumen)m(ted)g(here)g(for)g
+(completeness.)50 b(This)33 b(routine)g(extracts)h(arra)m(ys)g(from)e
+(a)i(binary)e(table)i(that)227 2710 y(con)m(tain)i(W)m(CS)e
+(information)h(using)f(the)g(-T)-8 b(AB)36 b(table)f(lo)s(okup)f(con)m
+(v)m(en)m(tion.)55 b(See)35 b(the)f(do)s(cumen)m(tation)227
+2822 y(pro)m(vided)c(with)g(the)h(W)m(CSLIB)f(library)g(for)g(more)h
+(information.)95 3038 y Fe(int)47 b(fits_read_wcstab)334
+3151 y(\(fitsfile)e(*fptr,)h(int)h(nwtb,)g(wtbarr)f(*wtb,)g(int)h
+(*status\);)0 3477 y Ff(7.1)180 b(Self-con)l(tained)46
+b(W)l(CS)f(Routines)0 3728 y Fj(The)21 b(follo)m(wing)i(routines)e(DO)g
+(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)j(that)d(ha)m(v)m(e)i(b)s(een)e(appro)m(v)m(ed)0
+3841 y(as)34 b(part)g(of)g(the)g(FITS)f(standard.)50
+b(Consequen)m(tly)-8 b(,)35 b(the)f(follo)m(wing)i(routines)d(ARE)h(NO)
+m(W)h(DEPRECA)-8 b(TED.)0 3953 y(It)30 b(is)g(STR)m(ONGL)-8
+b(Y)30 b(RECOMMENDED)h(that)g(soft)m(w)m(are)g(dev)m(elop)s(ers)f(not)h
+(use)f(these)g(routines,)g(and)g(instead)0 4066 y(use)g(an)g(external)i
+(W)m(CS)e(library)-8 b(,)31 b(as)f(describ)s(ed)f(in)i(the)f(previous)g
+(section.)0 4227 y(These)21 b(routines)g(are)g(included)f(mainly)h(for)
+g(bac)m(kw)m(ard)g(compatibilit)m(y)j(with)c(existing)i(soft)m(w)m
+(are.)39 b(They)21 b(supp)s(ort)0 4339 y(the)30 b(follo)m(wing)i
+(standard)d(map)g(pro)5 b(jections:)41 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 4452 y(are)f(the)g(legal)h(v)-5 b(alues)29
+b(for)f(the)h(co)s(ordt)m(yp)s(e)f(parameter\).)41 b(These)28
+b(routines)h(are)g(based)f(on)g(similar)h(functions)f(in)0
+4565 y(Classic)j(AIPS.)f(All)h(the)g(angular)f(quan)m(tities)i(are)f
+(giv)m(en)g(in)f(units)g(of)g(degrees.)0 4781 y Fi(1)81
+b Fj(Get)41 b(the)f(v)-5 b(alues)41 b(of)g(the)f(basic)h(set)g(of)f
+(standard)g(FITS)f(celestial)k(co)s(ordinate)e(system)g(k)m(eyw)m(ords)
+f(from)227 4894 y(the)33 b(header)f(of)h(a)f(FITS)g(image)i(\(i.e.,)g
+(the)f(primary)f(arra)m(y)g(or)h(an)f(IMA)m(GE)i(extension\).)47
+b(These)33 b(v)-5 b(alues)227 5006 y(ma)m(y)35 b(then)f(b)s(e)g(passed)
+f(to)i(the)g(\014ts)p 1462 5006 28 4 v 32 w(pix)p 1618
+5006 V 32 w(to)p 1730 5006 V 34 w(w)m(orld)f(and)g(\014ts)p
+2321 5006 V 32 w(w)m(orld)p 2573 5006 V 33 w(to)p 2686
+5006 V 33 w(pix)g(routines)g(that)h(p)s(erform)e(the)227
+5119 y(co)s(ordinate)f(transformations.)42 b(If)30 b(an)m(y)h(or)f(all)
+i(of)f(the)g(W)m(CS)f(k)m(eyw)m(ords)h(are)g(not)g(presen)m(t,)g(then)g
+(default)227 5232 y(v)-5 b(alues)26 b(will)f(b)s(e)f(returned.)38
+b(If)24 b(the)i(\014rst)e(co)s(ordinate)i(axis)f(is)g(the)g
+(declination-lik)m(e)j(co)s(ordinate,)f(then)e(this)227
+5345 y(routine)31 b(will)f(sw)m(ap)h(them)f(so)h(that)g(the)f
+(longitudinal-lik)m(e)j(co)s(ordinate)e(is)f(returned)g(as)g(the)h
+(\014rst)e(axis.)227 5488 y(The)34 b(\014rst)g(routine)h(\(\013gics\))h
+(returns)e(the)h(primary)f(W)m(CS,)g(whereas)h(the)g(second)g(routine)f
+(returns)g(the)227 5601 y(particular)24 b(v)m(ersion)h(of)f(the)g(W)m
+(CS)f(sp)s(eci\014ed)g(b)m(y)h(the)g('v)m(ersion')h(parameter,)h(whic)m
+(h)d(m)m(uc)m(h)h(b)s(e)f(a)h(c)m(haracter)227 5714 y(ranging)31
+b(from)f('A')h(to)g('Z')f(\(or)h(a)g(blank)f(c)m(haracter,)i(whic)m(h)e
+(is)g(equiv)-5 b(alen)m(t)32 b(to)f(calling)h(\013gics\).)p
+eop end
+%%Page: 83 91
+TeXDict begin 83 90 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(83)227 555
+y(If)35 b(the)h(\014le)f(uses)g(the)g(new)m(er)h('CDj)p
+1454 555 28 4 v 32 w(i')g(W)m(CS)f(transformation)h(matrix)g(k)m(eyw)m
+(ords)f(instead)h(of)f(old)h(st)m(yle)227 668 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)f
+(routine)h(will)g(calculate)j(and)c(return)g(the)h(v)-5
+b(alues)227 781 y(of)33 b(the)g(equiv)-5 b(alen)m(t)35
+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)h(from)e(the)i(new-st)m(yle)g(k)m(eyw)m(ords)227
+894 y(to)e(the)f(old-st)m(yle)h(v)-5 b(alues)31 b(is)g(sometimes)g
+(only)g(an)g(appro)m(ximation,)h(so)e(if)h(the)g(appro)m(ximation)h(is)
+e(larger)227 1007 y(than)37 b(an)h(in)m(ternally)g(de\014ned)e
+(threshold)h(lev)m(el,)k(then)c(CFITSIO)f(will)i(still)g(return)e(the)i
+(appro)m(ximate)227 1120 y(W)m(CS)32 b(k)m(eyw)m(ord)h(v)-5
+b(alues,)33 b(but)e(will)h(also)h(return)e(with)h(status)g(=)f(APPR)m
+(O)m(X)p 2908 1120 V 34 w(W)m(CS)p 3149 1120 V 33 w(KEY,)g(to)i(w)m
+(arn)f(the)227 1233 y(calling)k(program)e(that)h(appro)m(ximations)g
+(ha)m(v)m(e)g(b)s(een)f(made.)52 b(It)35 b(is)f(then)g(up)f(to)i(the)f
+(calling)i(program)227 1346 y(to)30 b(decide)g(whether)e(the)h(appro)m
+(ximations)h(are)g(su\016cien)m(tly)f(accurate)i(for)e(the)g
+(particular)g(application,)227 1458 y(or)46 b(whether)e(more)i(precise)
+g(W)m(CS)f(transformations)h(m)m(ust)f(b)s(e)g(p)s(erformed)f(using)g
+(new-st)m(yle)j(W)m(CS)227 1571 y(k)m(eyw)m(ords)31 b(directly)-8
+b(.)95 1824 y Fe(int)47 b(fits_read_img_coord)c(/)k(ffgics)286
+1937 y(\(fitsfile)f(*fptr,)g(>)h(double)f(*xrefval,)g(double)g
+(*yrefval,)334 2050 y(double)g(*xrefpix,)f(double)i(*yrefpix,)e(double)
+h(*xinc,)g(double)g(*yinc,)334 2163 y(double)g(*rot,)h(char)f
+(*coordtype,)f(int)i(*status\))95 2389 y(int)g
+(fits_read_img_coord_versio)o(n)42 b(/)47 b(ffgicsa)286
+2502 y(\(fitsfile)f(*fptr,)g(char)g(version,)g(>)h(double)f(*xrefval,)g
+(double)g(*yrefval,)334 2615 y(double)g(*xrefpix,)f(double)i(*yrefpix,)
+e(double)h(*xinc,)g(double)g(*yinc,)334 2728 y(double)g(*rot,)h(char)f
+(*coordtype,)f(int)i(*status\))0 2981 y Fi(2)81 b Fj(Get)30
+b(the)f(v)-5 b(alues)30 b(of)f(the)h(standard)e(FITS)h(celestial)j(co)s
+(ordinate)e(system)f(k)m(eyw)m(ords)h(from)f(the)g(header)g(of)h(a)227
+3094 y(FITS)23 b(table)i(where)e(the)h(X)g(and)g(Y)g(\(or)g(RA)g(and)f
+(DEC\))h(co)s(ordinates)h(are)f(stored)g(in)f(2)h(separate)h(columns)
+227 3207 y(of)30 b(the)f(table)h(\(as)g(in)f(the)h(Ev)m(en)m(t)g(List)g
+(table)g(format)f(that)h(is)g(often)f(used)g(b)m(y)g(high)g(energy)g
+(astroph)m(ysics)227 3320 y(missions\).)71 b(These)40
+b(v)-5 b(alues)40 b(ma)m(y)h(then)f(b)s(e)f(passed)h(to)h(the)f(\014ts)
+p 2511 3320 V 33 w(pix)p 2668 3320 V 32 w(to)p 2780 3320
+V 34 w(w)m(orld)g(and)g(\014ts)p 3383 3320 V 32 w(w)m(orld)p
+3635 3320 V 33 w(to)p 3748 3320 V 33 w(pix)227 3432 y(routines)31
+b(that)f(p)s(erform)f(the)i(co)s(ordinate)g(transformations.)95
+3685 y Fe(int)47 b(fits_read_tbl_coord)c(/)k(ffgtcs)286
+3798 y(\(fitsfile)f(*fptr,)g(int)h(xcol,)f(int)h(ycol,)f(>)i(double)e
+(*xrefval,)334 3911 y(double)g(*yrefval,)f(double)i(*xrefpix,)e(double)
+h(*yrefpix,)f(double)h(*xinc,)334 4024 y(double)g(*yinc,)g(double)g
+(*rot,)h(char)f(*coordtype,)f(int)i(*status\))0 4277
+y Fi(3)81 b Fj(Calculate)42 b(the)g(celestial)h(co)s(ordinate)f
+(corresp)s(onding)e(to)i(the)f(input)f(X)h(and)g(Y)g(pixel)g(lo)s
+(cation)i(in)e(the)227 4390 y(image.)95 4643 y Fe(int)47
+b(fits_pix_to_world)c(/)48 b(ffwldp)286 4756 y(\(double)e(xpix,)h
+(double)f(ypix,)g(double)g(xrefval,)g(double)g(yrefval,)334
+4869 y(double)g(xrefpix,)g(double)g(yrefpix,)f(double)h(xinc,)h(double)
+f(yinc,)334 4982 y(double)g(rot,)h(char)f(*coordtype,)f(>)j(double)e
+(*xpos,)g(double)g(*ypos,)334 5095 y(int)h(*status\))0
+5348 y Fi(4)81 b Fj(Calculate)42 b(the)g(X)f(and)f(Y)h(pixel)h(lo)s
+(cation)g(corresp)s(onding)e(to)i(the)f(input)f(celestial)k(co)s
+(ordinate)e(in)f(the)227 5461 y(image.)95 5714 y Fe(int)47
+b(fits_world_to_pix)c(/)48 b(ffxypx)p eop end
+%%Page: 84 92
+TeXDict begin 84 91 bop 0 299 a Fj(84)1169 b Fh(CHAPTER)29
+b(7.)112 b(W)m(ORLD)31 b(COORDINA)-8 b(TE)30 b(SYSTEM)f(R)m(OUTINES)286
+555 y Fe(\(double)46 b(xpos,)h(double)f(ypos,)g(double)g(xrefval,)g
+(double)g(yrefval,)334 668 y(double)g(xrefpix,)g(double)g(yrefpix,)f
+(double)h(xinc,)h(double)f(yinc,)334 781 y(double)g(rot,)h(char)f
+(*coordtype,)f(>)j(double)e(*xpix,)g(double)g(*ypix,)334
+894 y(int)h(*status\))p eop end
+%%Page: 85 93
+TeXDict begin 85 92 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)h(allo)m(w)h(for)e(the)h(creation)h(and)
+e(manipulation)h(of)g(FITS)f(HDU)h(Groups,)h(as)f(de\014ned)e(in)h("A)0
+2293 y(Hierarc)m(hical)f(Grouping)c(Con)m(v)m(en)m(tion)j(for)e(FITS")h
+(b)m(y)f(Jennings,)g(P)m(ence,)h(F)-8 b(olk)32 b(and)e(Sc)m(hlesinger:)
+0 2453 y(h)m(ttp://\014ts.gsfc.nasa.go)m(v/group.h)m(tml)0
+2613 y(A)38 b(group)g(is)g(a)g(collection)j(of)d(HDUs)h(whose)f(asso)s
+(ciation)h(is)g(de\014ned)d(b)m(y)i(a)h Fa(gr)-5 b(ouping)40
+b(table)p Fj(.)65 b(HDUs)38 b(whic)m(h)0 2726 y(are)46
+b(part)f(of)g(a)g(group)g(are)h(referred)e(to)i(as)f
+Fa(memb)-5 b(er)47 b(HDUs)d Fj(or)h(simply)g(as)g Fa(memb)-5
+b(ers)p Fj(.)86 b(Grouping)45 b(table)0 2839 y(mem)m(b)s(er)40
+b(HDUs)i(ma)m(y)f(themselv)m(es)h(b)s(e)f(grouping)f(tables,)45
+b(th)m(us)40 b(allo)m(wing)j(for)e(the)g(construction)g(of)g(op)s(en-)0
+2952 y(ended)30 b(hierarc)m(hies)h(of)f(HDUs.)0 3112
+y(Grouping)c(tables)i(con)m(tain)g(one)f(ro)m(w)g(for)f(eac)m(h)i(mem)m
+(b)s(er)e(HDU.)i(The)e(grouping)g(table)i(columns)e(pro)m(vide)h(iden-)
+0 3225 y(ti\014cation)i(information)f(that)g(allo)m(ws)h(applications)f
+(to)g(reference)g(or)g("p)s(oin)m(t)g(to")g(the)g(mem)m(b)s(er)f(HDUs.)
+40 b(Mem-)0 3338 y(b)s(er)27 b(HDUs)h(are)g(exp)s(ected,)h(but)e(not)h
+(required,)f(to)i(con)m(tain)g(a)f(set)g(of)g(GRPIDn/GRPLCn)f(k)m(eyw)m
+(ords)h(in)f(their)0 3451 y(headers)j(for)h(eac)m(h)g(grouping)g(table)
+g(that)g(they)g(are)g(referenced)g(b)m(y)-8 b(.)41 b(In)30
+b(this)h(sense,)g(the)g(GRPIDn/GRPLCn)0 3563 y(k)m(eyw)m(ords)d("link")
+g(the)g(mem)m(b)s(er)f(HDU)h(bac)m(k)g(to)g(its)g(Grouping)f(table.)41
+b(Note)29 b(that)f(a)f(mem)m(b)s(er)g(HDU)h(need)g(not)0
+3676 y(reside)i(in)g(the)g(same)g(FITS)f(\014le)i(as)f(its)g(grouping)g
+(table,)h(and)e(that)i(a)f(giv)m(en)h(HDU)g(ma)m(y)g(b)s(e)e
+(referenced)h(b)m(y)g(up)0 3789 y(to)h(999)h(grouping)e(tables)h(sim)m
+(ultaneously)-8 b(.)0 3949 y(Grouping)22 b(tables)i(are)f(implemen)m
+(ted)g(as)g(FITS)f(binary)g(tables)h(with)g(up)e(to)j(six)e
+(pre-de\014ned)g(column)g(TTYPEn)0 4062 y(v)-5 b(alues:)36
+b('MEMBER)p 752 4062 28 4 v 34 w(XTENSION',)20 b('MEMBER)p
+1789 4062 V 33 w(NAME',)h('MEMBER)p 2620 4062 V 34 w(VERSION',)f
+('MEMBER)p 3590 4062 V 34 w(POSITION',)0 4175 y('MEMBER)p
+451 4175 V 34 w(URI)p 653 4175 V 32 w(TYPE')g(and)g('MEMBER)p
+1601 4175 V 34 w(LOCA)-8 b(TION'.)20 b(The)f(\014rst)h(three)g(columns)
+g(allo)m(w)i(mem)m(b)s(er)e(HDUs)0 4288 y(to)28 b(b)s(e)f(iden)m
+(ti\014ed)g(b)m(y)g(reference)h(to)g(their)f(XTENSION,)g(EXTNAME)g(and)
+g(EXTVER)g(k)m(eyw)m(ord)g(v)-5 b(alues.)40 b(The)0 4401
+y(fourth)29 b(column)h(allo)m(ws)i(mem)m(b)s(er)d(HDUs)i(to)g(b)s(e)f
+(iden)m(ti\014ed)g(b)m(y)g(HDU)h(p)s(osition)f(within)g(their)g(FITS)g
+(\014le.)40 b(The)0 4514 y(last)f(t)m(w)m(o)g(columns)e(iden)m(tify)h
+(the)g(FITS)f(\014le)h(in)f(whic)m(h)h(the)g(mem)m(b)s(er)f(HDU)h
+(resides,)i(if)d(di\013eren)m(t)i(from)e(the)0 4627 y(grouping)30
+b(table)h(FITS)f(\014le.)0 4787 y(Additional)25 b(user)f(de\014ned)f
+("auxiliary")j(columns)e(ma)m(y)h(also)g(b)s(e)f(included)g(with)g(an)m
+(y)h(grouping)f(table.)39 b(When)25 b(a)0 4900 y(grouping)i(table)i(is)
+f(copied)g(or)f(mo)s(di\014ed)g(the)h(presence)g(of)f(auxiliary)i
+(columns)e(is)h(alw)m(a)m(ys)h(tak)m(en)g(in)m(to)f(accoun)m(t)0
+5013 y(b)m(y)j(the)g(grouping)g(supp)s(ort)f(functions;)h(ho)m(w)m(ev)m
+(er,)i(the)e(grouping)g(supp)s(ort)f(functions)g(cannot)i(directly)g
+(mak)m(e)0 5126 y(use)e(of)h(this)f(data.)0 5286 y(If)44
+b(a)h(grouping)f(table)h(column)f(is)h(de\014ned)e(but)h(the)g(corresp)
+s(onding)g(mem)m(b)s(er)f(HDU)j(information)e(is)h(un-)0
+5399 y(a)m(v)-5 b(ailable)41 b(then)c(a)i(n)m(ull)f(v)-5
+b(alue)39 b(of)f(the)g(appropriate)h(data)f(t)m(yp)s(e)h(is)f(inserted)
+g(in)g(the)g(column)g(\014eld.)64 b(In)m(teger)0 5512
+y(columns)26 b(\(MEMBER)p 811 5512 V 34 w(POSITION,)f(MEMBER)p
+1771 5512 V 34 w(VERSION\))h(are)h(de\014ned)f(with)g(a)h(TNULLn)f(v)-5
+b(alue)27 b(of)g(zero)0 5625 y(\(0\).)41 b(Character)27
+b(\014eld)f(columns)h(\(MEMBER)p 1607 5625 V 34 w(XTENSION,)f(MEMBER)p
+2600 5625 V 33 w(NAME,)i(MEMBER)p 3388 5625 V 34 w(URI)p
+3590 5625 V 32 w(TYPE,)1905 5942 y(85)p eop end
+%%Page: 86 94
+TeXDict begin 86 93 bop 0 299 a Fj(86)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(MEMBER)p 426 555 28 4 v 33 w(LOCA)-8 b(TION\))30
+b(utilize)i(an)e(ASCI)s(I)f(n)m(ull)h(c)m(haracter)i(to)f(denote)g(a)g
+(n)m(ull)f(\014eld)g(v)-5 b(alue.)0 715 y(The)23 b(grouping)g(supp)s
+(ort)f(functions)h(b)s(elong)h(to)g(t)m(w)m(o)h(basic)f(categories:)40
+b(those)24 b(that)h(w)m(ork)e(with)h(grouping)f(table)0
+828 y(HDUs)j(\(\013gt**\))j(and)c(those)h(that)h(w)m(ork)f(with)f(mem)m
+(b)s(er)h(HDUs)g(\(\013gm**\).)41 b(Tw)m(o)26 b(functions,)h(\014ts)p
+3360 828 V 32 w(cop)m(y)p 3573 828 V 34 w(group\(\))0
+941 y(and)40 b(\014ts)p 314 941 V 33 w(remo)m(v)m(e)p
+626 941 V 34 w(group\(\),)k(ha)m(v)m(e)e(the)f(option)g(to)h(recursiv)m
+(ely)f(cop)m(y/delete)j(en)m(tire)e(groups.)71 b(Care)41
+b(should)0 1054 y(b)s(e)33 b(tak)m(en)h(when)f(emplo)m(ying)h(these)g
+(functions)f(in)g(recursiv)m(e)h(mo)s(de)f(as)g(p)s(o)s(orly)g
+(de\014ned)f(groups)h(could)g(cause)0 1167 y(unpredictable)25
+b(results.)39 b(The)25 b(problem)g(of)h(a)g(grouping)f(table)i
+(directly)f(or)g(indirectly)g(referencing)g(itself)g(\(th)m(us)0
+1280 y(creating)41 b(an)f(in\014nite)f(lo)s(op\))i(is)e(protected)i
+(against;)46 b(in)39 b(fact,)44 b(neither)39 b(function)h(will)g
+(attempt)h(to)f(cop)m(y)h(or)0 1393 y(delete)32 b(an)e(HDU)h(t)m(wice.)
+0 1745 y Ff(8.1)135 b(Grouping)45 b(T)-11 b(able)45 b(Routines)0
+1997 y Fi(1)81 b Fj(Create)34 b(\(app)s(end\))f(a)h(grouping)f(table)i
+(at)f(the)g(end)f(of)h(the)g(curren)m(t)f(FITS)g(\014le)h(p)s(oin)m
+(ted)g(to)g(b)m(y)g(fptr.)49 b(The)227 2110 y(grpname)28
+b(parameter)h(pro)m(vides)g(the)g(grouping)f(table)h(name)g(\(GRPNAME)g
+(k)m(eyw)m(ord)g(v)-5 b(alue\))29 b(and)f(ma)m(y)227
+2223 y(b)s(e)42 b(set)h(to)g(NULL)f(if)g(no)g(group)g(name)g(is)h(to)g
+(b)s(e)e(sp)s(eci\014ed.)76 b(The)42 b(groupt)m(yp)s(e)g(parameter)g
+(sp)s(eci\014es)227 2336 y(the)c(desired)g(structure)f(of)h(the)g
+(grouping)f(table)i(and)e(ma)m(y)i(tak)m(e)g(on)f(the)g(v)-5
+b(alues:)56 b(GT)p 3355 2336 V 33 w(ID)p 3490 2336 V
+33 w(ALL)p 3705 2336 V 32 w(URI)227 2449 y(\(all)35 b(columns)e
+(created\),)j(GT)p 1274 2449 V 33 w(ID)p 1409 2449 V
+33 w(REF)d(\(ID)h(b)m(y)g(reference)g(columns\),)g(GT)p
+2904 2449 V 33 w(ID)p 3039 2449 V 33 w(POS)e(\(ID)i(b)m(y)g(p)s
+(osition)227 2562 y(columns\),)48 b(GT)p 801 2562 V 32
+w(ID)p 935 2562 V 33 w(ALL)c(\(ID)g(b)m(y)f(reference)i(and)e(p)s
+(osition)g(columns\),)48 b(GT)p 3028 2562 V 32 w(ID)p
+3162 2562 V 33 w(REF)p 3383 2562 V 33 w(URI)c(\(ID)g(b)m(y)227
+2674 y(reference)35 b(and)e(FITS)g(\014le)i(URI)e(columns\),)j(and)d
+(GT)p 2129 2674 V 33 w(ID)p 2264 2674 V 33 w(POS)p 2481
+2674 V 32 w(URI)h(\(ID)g(b)m(y)g(p)s(osition)g(and)g(FITS)f(\014le)227
+2787 y(URI)e(columns\).)95 3063 y Fe(int)47 b(fits_create_group)c(/)48
+b(ffgtcr)286 3176 y(\(fitsfile)e(*fptr,)g(char)g(*grpname,)g(int)h
+(grouptype,)e(>)i(int)g(*status\))0 3451 y Fi(2)81 b
+Fj(Create)26 b(\(insert\))g(a)f(grouping)g(table)h(just)f(after)h(the)f
+(CHDU)h(of)g(the)f(curren)m(t)g(FITS)g(\014le)g(p)s(oin)m(ted)g(to)h(b)
+m(y)g(fptr.)227 3564 y(All)k(HDUs)f(b)s(elo)m(w)g(the)g(the)g
+(insertion)g(p)s(oin)m(t)f(will)i(b)s(e)e(shifted)g(do)m(wn)m(w)m(ards)
+g(to)i(mak)m(e)g(ro)s(om)e(for)g(the)h(new)227 3677 y(HDU.)23
+b(The)e(grpname)h(parameter)g(pro)m(vides)f(the)h(grouping)g(table)g
+(name)g(\(GRPNAME)h(k)m(eyw)m(ord)f(v)-5 b(alue\))227
+3790 y(and)25 b(ma)m(y)i(b)s(e)e(set)h(to)h(NULL)e(if)h(no)g(group)f
+(name)h(is)g(to)g(b)s(e)f(sp)s(eci\014ed.)39 b(The)25
+b(groupt)m(yp)s(e)h(parameter)g(sp)s(eci-)227 3903 y(\014es)g(the)h
+(desired)f(structure)g(of)h(the)f(grouping)g(table)i(and)e(ma)m(y)h
+(tak)m(e)h(on)e(the)h(v)-5 b(alues:)39 b(GT)p 3355 3903
+V 33 w(ID)p 3490 3903 V 33 w(ALL)p 3705 3903 V 32 w(URI)227
+4016 y(\(all)c(columns)e(created\),)j(GT)p 1274 4016
+V 33 w(ID)p 1409 4016 V 33 w(REF)d(\(ID)h(b)m(y)g(reference)g
+(columns\),)g(GT)p 2904 4016 V 33 w(ID)p 3039 4016 V
+33 w(POS)e(\(ID)i(b)m(y)g(p)s(osition)227 4129 y(columns\),)29
+b(GT)p 782 4129 V 33 w(ID)p 917 4129 V 33 w(ALL)f(\(ID)g(b)m(y)g
+(reference)h(and)e(p)s(osition)h(columns\),)h(GT)p 2897
+4129 V 33 w(ID)p 3032 4129 V 33 w(REF)p 3253 4129 V 32
+w(URI)f(\(ID)h(b)m(y)f(ref-)227 4242 y(erence)g(and)e(FITS)h(\014le)g
+(URI)g(columns\),)h(and)e(GT)p 1976 4242 V 33 w(ID)p
+2111 4242 V 33 w(POS)p 2328 4242 V 32 w(URI)h(\(ID)g(b)m(y)g(p)s
+(osition)g(and)g(FITS)f(\014le)h(URI)227 4355 y(columns\))k(.)95
+4630 y Fe(int)47 b(fits_insert_group)c(/)48 b(ffgtis)286
+4743 y(\(fitsfile)e(*fptr,)g(char)g(*grpname,)g(int)h(grouptype,)e(>)i
+(int)g(*status\))0 5019 y Fi(3)81 b Fj(Change)20 b(the)h(structure)f
+(of)h(an)g(existing)g(grouping)g(table)g(p)s(oin)m(ted)g(to)g(b)m(y)g
+(gfptr.)37 b(The)20 b(groupt)m(yp)s(e)g(parameter)227
+5132 y(\(see)27 b(\014ts)p 532 5132 V 32 w(create)p 800
+5132 V 35 w(group\(\))e(for)h(v)-5 b(alid)26 b(parameter)g(v)-5
+b(alues\))26 b(sp)s(eci\014es)g(the)f(new)g(structure)h(of)f(the)h
+(grouping)227 5245 y(table.)44 b(This)30 b(function)h(only)g(adds)g(or)
+g(remo)m(v)m(es)h(grouping)f(table)h(columns,)f(it)h(do)s(es)f(not)g
+(add)g(or)g(delete)227 5357 y(group)26 b(mem)m(b)s(ers)f(\(i.e.,)k
+(table)e(ro)m(ws\).)40 b(If)26 b(the)g(grouping)g(table)h(already)g
+(has)f(the)h(desired)e(structure)h(then)227 5470 y(no)35
+b(op)s(erations)f(are)h(p)s(erformed)e(and)h(function)g(simply)h
+(returns)e(with)h(a)h(\(0\))g(success)g(status)g(co)s(de.)53
+b(If)227 5583 y(the)32 b(requested)g(structure)g(c)m(hange)h(creates)g
+(new)f(grouping)g(table)h(columns,)f(then)g(the)g(column)g(v)-5
+b(alues)227 5696 y(for)30 b(all)i(existing)f(mem)m(b)s(ers)f(will)g(b)s
+(e)g(\014lled)g(with)g(the)h(n)m(ull)f(v)-5 b(alues)31
+b(appropriate)f(to)h(the)g(column)f(t)m(yp)s(e.)p eop
+end
+%%Page: 87 95
+TeXDict begin 87 94 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(87)95 555 y
+Fe(int)47 b(fits_change_group)c(/)48 b(ffgtch)286 668
+y(\(fitsfile)e(*gfptr,)f(int)i(grouptype,)e(>)j(int)f(*status\))0
+905 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)f(table)h(p)s(oin)m(ted)f(to)h(b)m(y)g(gfptr,)h(and)e
+(optionally)i(all)f(the)227 1018 y(group)29 b(mem)m(b)s(er)f(HDUs.)41
+b(The)28 b(rmopt)h(parameter)g(sp)s(eci\014es)g(the)g(action)h(to)g(b)s
+(e)e(tak)m(en)i(for)f(all)h(mem)m(b)s(ers)227 1131 y(of)d(the)g(group)g
+(de\014ned)e(b)m(y)i(the)g(grouping)g(table.)40 b(V)-8
+b(alid)28 b(v)-5 b(alues)27 b(are:)40 b(OPT)p 2848 1131
+28 4 v 32 w(RM)p 3030 1131 V 33 w(GPT)26 b(\(delete)j(only)e(the)227
+1244 y(grouping)33 b(table\))i(and)e(OPT)p 1259 1244
+V 32 w(RM)p 1441 1244 V 33 w(ALL)g(\(recursiv)m(ely)h(delete)h(all)f
+(HDUs)g(that)g(b)s(elong)f(to)h(the)g(group\).)227 1357
+y(An)m(y)d(groups)g(con)m(taining)i(the)e(grouping)g(table)h(gfptr)e
+(as)i(a)f(mem)m(b)s(er)g(are)g(up)s(dated,)f(and)h(if)g(rmopt)g(==)227
+1470 y(OPT)p 431 1470 V 32 w(RM)p 613 1470 V 33 w(GPT)21
+b(all)h(mem)m(b)s(ers)f(ha)m(v)m(e)h(their)f(GRPIDn)g(and)g(GRPLCn)f(k)
+m(eyw)m(ords)h(up)s(dated)f(accordingly)-8 b(.)227 1582
+y(If)36 b(rmopt)g(==)g(OPT)p 985 1582 V 32 w(RM)p 1167
+1582 V 33 w(ALL,)g(then)g(other)h(groups)e(that)i(con)m(tain)h(the)e
+(deleted)h(mem)m(b)s(ers)f(of)g(gfptr)227 1695 y(are)31
+b(up)s(dated)e(to)i(re\015ect)g(the)g(deletion)g(accordingly)-8
+b(.)95 1932 y Fe(int)47 b(fits_remove_group)c(/)48 b(ffgtrm)286
+2045 y(\(fitsfile)e(*gfptr,)f(int)i(rmopt,)f(>)i(int)f(*status\))0
+2282 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)h(table)h(p)s(oin)m(ted)e(to)i(b)m
+(y)e(infptr,)h(and)f(optionally)i(all)227 2395 y(group)g(mem)m(b)s(er)h
+(HDUs,)g(to)h(the)f(FITS)f(\014le)g(p)s(oin)m(ted)h(to)h(b)m(y)e
+(outfptr.)41 b(The)31 b(cp)s(opt)f(parameter)h(sp)s(eci\014es)227
+2508 y(the)c(action)h(to)f(b)s(e)f(tak)m(en)h(for)g(all)g(mem)m(b)s
+(ers)f(of)g(the)h(group)f(infptr.)38 b(V)-8 b(alid)28
+b(v)-5 b(alues)26 b(are:)40 b(OPT)p 3443 2508 V 32 w(GCP)p
+3674 2508 V 32 w(GPT)227 2621 y(\(cop)m(y)d(only)g(the)f(grouping)g
+(table\))h(and)e(OPT)p 1887 2621 V 32 w(GCP)p 2118 2621
+V 33 w(ALL)h(\(recursiv)m(ely)h(cop)m(y)g(ALL)e(the)i(HDUs)f(that)227
+2734 y(b)s(elong)24 b(to)g(the)g(group)f(de\014ned)g(b)m(y)g(infptr\).)
+38 b(If)23 b(the)h(cp)s(opt)g(==)f(OPT)p 2618 2734 V
+32 w(GCP)p 2849 2734 V 32 w(GPT)h(then)f(the)h(mem)m(b)s(ers)f(of)227
+2847 y(infptr)i(ha)m(v)m(e)h(their)g(GRPIDn)f(and)g(GRPLCn)g(k)m(eyw)m
+(ords)h(up)s(dated)e(to)i(re\015ect)g(the)g(existence)h(of)f(the)f(new)
+227 2960 y(grouping)f(table)g(outfptr,)h(since)f(they)g(no)m(w)g(b)s
+(elong)g(to)g(the)g(new)g(group.)38 b(If)23 b(cp)s(opt)h(==)f(OPT)p
+3460 2960 V 32 w(GCP)p 3691 2960 V 32 w(ALL)227 3073
+y(then)29 b(the)g(new)g(grouping)g(table)h(outfptr)e(only)h(con)m
+(tains)i(p)s(oin)m(ters)e(to)h(the)f(copied)g(mem)m(b)s(er)g(HDUs)h
+(and)227 3185 y(not)38 b(the)g(original)g(mem)m(b)s(er)f(HDUs)h(of)g
+(infptr.)61 b(Note)39 b(that,)h(when)d(cp)s(opt)g(==)g(OPT)p
+3301 3185 V 32 w(GCP)p 3532 3185 V 33 w(ALL,)g(all)227
+3298 y(mem)m(b)s(ers)h(of)h(the)f(group)g(de\014ned)f(b)m(y)i(infptr)e
+(will)i(b)s(e)e(copied)i(to)g(a)g(single)g(FITS)f(\014le)h(p)s(oin)m
+(ted)f(to)h(b)m(y)227 3411 y(outfptr)30 b(regardless)h(of)f(their)h
+(\014le)f(distribution)g(in)g(the)h(original)g(group.)95
+3648 y Fe(int)47 b(fits_copy_group)d(/)j(ffgtcp)286 3761
+y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(int)i(cpopt,)f(>)h
+(int)g(*status\))0 3998 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)g(table)g(HDUs)h(infptr)e
+(and)g(outfptr)h(b)m(y)f(com)m(bining)227 4111 y(their)30
+b(mem)m(b)s(ers)f(in)m(to)i(a)f(single)g(grouping)f(table.)42
+b(All)30 b(mem)m(b)s(er)f(HDUs)h(\(ro)m(ws\))h(are)f(copied)g(from)f
+(infptr)227 4224 y(to)f(outfptr.)39 b(If)26 b(mgopt)i(==)e(OPT)p
+1419 4224 V 32 w(MR)m(G)p 1669 4224 V 34 w(COPY)g(then)g(infptr)g(con)m
+(tin)m(ues)i(to)g(exist)g(unaltered)e(after)i(the)227
+4337 y(merge.)57 b(If)36 b(the)f(mgopt)i(==)e(OPT)p 1474
+4337 V 31 w(MR)m(G)p 1723 4337 V 34 w(MO)m(V)i(then)e(infptr)f(is)i
+(deleted)h(after)f(the)g(merge.)57 b(In)35 b(b)s(oth)227
+4450 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 4687 y Fe(int)47 b(fits_merge_groups)c(/)48 b(ffgtmg)286
+4799 y(\(fitsfile)e(*infptr,)f(fitsfile)h(*outfptr,)f(int)i(mgopt,)f(>)
+h(int)g(*status\))0 5036 y Fi(7)81 b Fj("Compact")24
+b(the)f(group)g(de\014ned)f(b)m(y)h(grouping)f(table)i(p)s(oin)m(ted)f
+(to)h(b)m(y)f(gfptr.)38 b(The)22 b(compaction)j(is)e(ac)m(hiev)m(ed)227
+5149 y(b)m(y)37 b(merging)h(\(via)g(\014ts)p 1034 5149
+V 32 w(merge)p 1303 5149 V 34 w(groups\(\)\))f(all)h(direct)g(mem)m(b)s
+(er)f(HDUs)g(of)h(gfptr)e(that)i(are)g(themselv)m(es)227
+5262 y(grouping)i(tables.)70 b(The)40 b(cmopt)g(parameter)h(de\014nes)e
+(whether)g(the)i(merged)f(grouping)f(table)i(HDUs)227
+5375 y(remain)j(after)h(merging)f(\(cmopt)h(==)f(OPT)p
+1852 5375 V 32 w(CMT)p 2099 5375 V 32 w(MBR\))h(or)f(if)g(they)h(are)f
+(deleted)h(after)g(merging)227 5488 y(\(cmopt)31 b(==)f(OPT)p
+916 5488 V 32 w(CMT)p 1163 5488 V 32 w(MBR)p 1409 5488
+V 34 w(DEL\).)g(If)g(the)h(grouping)e(table)j(con)m(tains)f(no)f
+(direct)h(mem)m(b)s(er)e(HDUs)227 5601 y(that)i(are)f(themselv)m(es)h
+(grouping)e(tables)i(then)e(this)h(function)f(do)s(es)h(nothing.)40
+b(Note)31 b(that)g(this)e(function)227 5714 y(is)i(not)f(recursiv)m(e,)
+h(i.e.,)h(only)f(the)f(direct)h(mem)m(b)s(er)f(HDUs)h(of)f(gfptr)g(are)
+h(considered)f(for)g(merging.)p eop end
+%%Page: 88 96
+TeXDict begin 88 95 bop 0 299 a Fj(88)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_compact_group)c(/)48 b(ffgtcm)286
+668 y(\(fitsfile)e(*gfptr,)f(int)i(cmopt,)f(>)i(int)f(*status\))0
+945 y Fi(8)81 b Fj(V)-8 b(erify)21 b(the)h(in)m(tegrit)m(y)h(of)e(the)g
+(grouping)g(table)h(p)s(oin)m(ted)f(to)h(b)m(y)f(gfptr)g(to)h(mak)m(e)g
+(sure)e(that)i(all)g(group)f(mem)m(b)s(ers)227 1058 y(are)31
+b(accessible)i(and)d(that)h(all)g(links)g(to)g(other)g(grouping)f
+(tables)i(are)f(v)-5 b(alid.)42 b(The)30 b(\014rstfailed)g(parameter)
+227 1171 y(returns)c(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)g(v)m
+(eri\014cation)g(\(if)g(p)s(ositiv)m(e)227 1284 y(v)-5
+b(alue\))36 b(or)e(the)h(\014rst)e(group)h(link)g(to)i(fail)f(\(if)f
+(negativ)m(e)j(v)-5 b(alue\).)54 b(If)34 b(gfptr)g(is)g(successfully)h
+(v)m(eri\014ed)f(then)227 1397 y(\014rstfailed)d(con)m(tains)g(a)g
+(return)e(v)-5 b(alue)31 b(of)g(0.)95 1673 y Fe(int)47
+b(fits_verify_group)c(/)48 b(ffgtvf)286 1786 y(\(fitsfile)e(*gfptr,)f
+(>)j(long)f(*firstfailed,)d(int)j(*status\))0 2063 y
+Fi(9)81 b Fj(Op)s(en)23 b(a)j(grouping)f(table)h(that)g(con)m(tains)g
+(the)g(mem)m(b)s(er)e(HDU)i(p)s(oin)m(ted)f(to)h(b)m(y)f(mfptr.)38
+b(The)25 b(grouping)g(table)227 2176 y(to)39 b(op)s(en)e(is)h
+(de\014ned)f(b)m(y)h(the)g(grpid)f(parameter,)j(whic)m(h)e(con)m(tains)
+h(the)f(k)m(eyw)m(ord)h(index)e(v)-5 b(alue)39 b(of)f(the)227
+2289 y(GRPIDn/GRPLCn)d(k)m(eyw)m(ord\(s\))g(that)h(link)f(the)g(mem)m
+(b)s(er)f(HDU)h(mfptr)f(to)i(the)f(grouping)f(table.)55
+b(If)227 2402 y(the)30 b(grouping)f(table)h(resides)f(in)h(a)f(\014le)h
+(other)f(than)h(the)f(mem)m(b)s(er)g(HDUs)h(\014le)f(then)g(an)h
+(attempt)g(is)g(\014rst)227 2515 y(made)f(to)h(op)s(en)e(the)h(\014le)g
+(readwrite,)h(and)e(failing)i(that)g(readonly)-8 b(.)40
+b(A)29 b(p)s(oin)m(ter)g(to)h(the)f(op)s(ened)f(grouping)227
+2628 y(table)k(HDU)f(is)f(returned)f(in)h(gfptr.)227
+2786 y(Note)35 b(that)g(it)f(is)g(p)s(ossible,)g(although)h(unlik)m
+(ely)f(and)f(undesirable,)h(for)g(the)g(GRPIDn/GRPLCn)f(k)m(ey-)227
+2899 y(w)m(ords)k(in)g(a)g(mem)m(b)s(er)g(HDU)h(header)f(to)h(b)s(e)e
+(non-con)m(tin)m(uous,)k(e.g.,)g(GRPID1,)g(GRPID2,)g(GRPID5,)227
+3012 y(GRPID6.)i(In)29 b(suc)m(h)g(cases,)i(the)f(grpid)f(index)g(v)-5
+b(alue)31 b(sp)s(eci\014ed)e(in)g(the)h(function)f(call)j(shall)e(iden)
+m(tify)g(the)227 3125 y(\(grpid\)th)36 b(GRPID)f(v)-5
+b(alue.)57 b(In)34 b(the)i(ab)s(o)m(v)m(e)h(example,)g(if)f(grpid)e(==)
+h(3,)j(then)d(the)g(group)g(sp)s(eci\014ed)g(b)m(y)227
+3238 y(GRPID5)c(w)m(ould)g(b)s(e)e(op)s(ened.)95 3515
+y Fe(int)47 b(fits_open_group)d(/)j(ffgtop)286 3628 y(\(fitsfile)f
+(*mfptr,)f(int)i(group,)f(>)i(fitsfile)d(**gfptr,)h(int)h(*status\))0
+3905 y Fi(10)f Fj(Add)38 b(a)h(mem)m(b)s(er)f(HDU)i(to)f(an)g(existing)
+g(grouping)g(table)h(p)s(oin)m(ted)e(to)i(b)m(y)e(gfptr.)66
+b(The)38 b(mem)m(b)s(er)g(HDU)227 4017 y(ma)m(y)30 b(either)g(b)s(e)f
+(p)s(oin)m(ted)g(to)h(mfptr)f(\(whic)m(h)g(m)m(ust)h(b)s(e)e(p)s
+(ositioned)i(to)g(the)f(mem)m(b)s(er)g(HDU\))i(or,)f(if)f(mfptr)227
+4130 y(==)36 b(NULL,)g(iden)m(ti\014ed)g(b)m(y)g(the)g(hdup)s(os)e
+(parameter)i(\(the)h(HDU)g(p)s(osition)f(n)m(um)m(b)s(er,)g(Primary)f
+(arra)m(y)227 4243 y(==)f(1\))i(if)f(b)s(oth)f(the)h(grouping)g(table)g
+(and)g(the)g(mem)m(b)s(er)f(HDU)h(reside)g(in)g(the)g(same)g(FITS)f
+(\014le.)54 b(The)227 4356 y(new)27 b(mem)m(b)s(er)f(HDU)h(shall)g(ha)m
+(v)m(e)h(the)f(appropriate)g(GRPIDn)f(and)g(GRPLCn)g(k)m(eyw)m(ords)h
+(created)h(in)f(its)227 4469 y(header.)44 b(Note)33 b(that)f(if)g(the)g
+(mem)m(b)s(er)e(HDU)j(is)e(already)h(a)g(mem)m(b)s(er)f(of)h(the)g
+(group)f(then)g(it)h(will)g(not)g(b)s(e)227 4582 y(added)e(a)h(second)f
+(time.)95 4859 y Fe(int)47 b(fits_add_group_member)42
+b(/)48 b(ffgtam)286 4972 y(\(fitsfile)e(*gfptr,)f(fitsfile)h(*mfptr,)g
+(int)h(hdupos,)f(>)h(int)g(*status\))0 5325 y Ff(8.2)135
+b(Group)45 b(Mem)l(b)t(er)f(Routines)0 5578 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)
+f(a)h(grouping)e(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 5691 y(just)f(the)h(NAXIS2)f(v)-5
+b(alue)31 b(\(n)m(um)m(b)s(er)f(of)g(ro)m(ws\))h(of)f(the)h(grouping)f
+(table.)p eop end
+%%Page: 89 97
+TeXDict begin 89 96 bop 0 299 a Fh(8.2.)72 b(GR)m(OUP)31
+b(MEMBER)g(R)m(OUTINES)2295 b Fj(89)95 555 y Fe(int)47
+b(fits_get_num_members)c(/)k(ffgtnm)286 668 y(\(fitsfile)f(*gfptr,)f(>)
+j(long)f(*nmembers,)e(int)h(*status\))0 945 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)f
+(the)g(HDU)h(p)s(oin)m(ted)f(to)h(b)m(y)f(mfptr)f(is)i(link)m(ed,)h(as)
+e(de\014ned)f(b)m(y)227 1058 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)g(its)
+i(header.)39 b(Note)28 b(that)g(eac)m(h)227 1171 y(time)37
+b(this)g(function)f(is)g(called,)k(the)c(indices)h(of)g(the)f
+(GRPIDn/GRPLCn)g(k)m(eyw)m(ords)h(are)g(c)m(hec)m(k)m(ed)h(to)227
+1284 y(mak)m(e)29 b(sure)e(they)g(are)h(con)m(tin)m(uous)g(\(ie)h(no)e
+(gaps\))h(and)f(are)h(re-en)m(umerated)g(to)h(eliminate)g(gaps)f(if)f
+(found.)95 1674 y Fe(int)47 b(fits_get_num_groups)c(/)k(ffgmng)286
+1787 y(\(fitsfile)f(*mfptr,)f(>)j(long)f(*nmembers,)e(int)h(*status\))0
+2063 y Fi(3)81 b Fj(Op)s(en)26 b(a)i(mem)m(b)s(er)f(of)h(the)f
+(grouping)h(table)g(p)s(oin)m(ted)g(to)g(b)m(y)g(gfptr.)39
+b(The)27 b(mem)m(b)s(er)g(to)i(op)s(en)e(is)g(iden)m(ti\014ed)h(b)m(y)
+227 2176 y(its)i(ro)m(w)g(n)m(um)m(b)s(er)e(within)h(the)g(grouping)h
+(table)g(as)g(giv)m(en)g(b)m(y)g(the)f(parameter)h('mem)m(b)s(er')f
+(\(\014rst)h(mem)m(b)s(er)227 2289 y(==)g(1\))g(.)41
+b(A)30 b(\014ts\014le)f(p)s(oin)m(ter)h(to)h(the)f(op)s(ened)f(mem)m(b)
+s(er)g(HDU)i(is)f(returned)f(as)h(mfptr.)39 b(Note)31
+b(that)g(if)f(the)227 2402 y(mem)m(b)s(er)e(HDU)h(resides)g(in)f(a)h
+(FITS)f(\014le)g(di\013eren)m(t)h(from)f(the)h(grouping)f(table)h(HDU)h
+(then)e(the)h(mem)m(b)s(er)227 2515 y(\014le)i(is)f(\014rst)g(op)s
+(ened)f(readwrite)i(and,)f(failing)h(this,)g(op)s(ened)e(readonly)-8
+b(.)95 2792 y Fe(int)47 b(fits_open_member)d(/)j(ffgmop)286
+2905 y(\(fitsfile)f(*gfptr,)f(long)i(member,)f(>)h(fitsfile)f(**mfptr,)
+f(int)i(*status\))0 3182 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)e(table)j(p)s(oin)m(ted)e
+(to)h(b)m(y)f(gfptr.)39 b(The)27 b(mem)m(b)s(er)g(HDU)h(is)227
+3295 y(iden)m(ti\014ed)33 b(b)m(y)g(its)h(ro)m(w)f(n)m(um)m(b)s(er)e
+(within)i(the)g(grouping)g(table)g(as)h(giv)m(en)g(b)m(y)e(the)i
+(parameter)f('mem)m(b)s(er')227 3408 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)f(b)s(e)f(app)s(ended)f(to)j(the)f(FITS)227 3521
+y(\014le)29 b(p)s(oin)m(ted)g(to)g(b)m(y)f(mfptr,)h(and)f(up)s(on)f
+(return)g(mfptr)h(shall)h(p)s(oin)m(t)f(to)i(the)f(copied)g(mem)m(b)s
+(er)f(HDU.)h(The)227 3633 y(cp)s(opt)e(parameter)h(ma)m(y)g(tak)m(e)h
+(on)e(the)g(follo)m(wing)i(v)-5 b(alues:)40 b(OPT)p 2465
+3633 28 4 v 32 w(MCP)p 2708 3633 V 32 w(ADD)29 b(whic)m(h)e(adds)f(a)i
+(new)f(en)m(try)227 3746 y(in)d(gfptr)g(for)f(the)i(copied)f(mem)m(b)s
+(er)g(HDU,)h(OPT)p 1907 3746 V 31 w(MCP)p 2149 3746 V
+33 w(NADD)g(whic)m(h)f(do)s(es)g(not)g(add)f(an)h(en)m(try)h(in)e
+(gfptr)227 3859 y(for)i(the)h(copied)f(mem)m(b)s(er,)h(and)f(OPT)p
+1536 3859 V 32 w(MCP)p 1779 3859 V 32 w(REPL)g(whic)m(h)g(replaces)h
+(the)f(original)h(mem)m(b)s(er)f(en)m(try)g(with)227
+3972 y(the)31 b(copied)g(mem)m(b)s(er)e(en)m(try)-8 b(.)95
+4249 y Fe(int)47 b(fits_copy_member)d(/)j(ffgmcp)286
+4362 y(\(fitsfile)f(*gfptr,)f(fitsfile)h(*mfptr,)g(long)g(member,)g
+(int)h(cpopt,)f(>)i(int)f(*status\))0 4639 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)f(table)h(p)s(oin)m(ted)f(to)h(b)m(y)f(infptr)g(to)h(the)f
+(grouping)227 4752 y(table)i(p)s(oin)m(ted)f(to)h(b)m(y)f(outfptr.)58
+b(The)35 b(mem)m(b)s(er)h(HDU)h(to)f(transfer)g(is)g(iden)m(ti\014ed)g
+(b)m(y)g(its)h(ro)m(w)f(n)m(um)m(b)s(er)227 4865 y(within)42
+b(infptr)f(as)i(sp)s(eci\014ed)f(b)m(y)g(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 4978 y(OPT)p 431 4978 V 32 w(MCP)p 674
+4978 V 33 w(ADD)26 b(then)f(the)h(mem)m(b)s(er)e(HDU)i(is)g(made)f(a)h
+(mem)m(b)s(er)f(of)g(outfptr)g(and)g(remains)g(a)h(mem)m(b)s(er)227
+5091 y(of)34 b(infptr.)51 b(If)34 b(tfopt)g(==)g(OPT)p
+1339 5091 V 32 w(MCP)p 1582 5091 V 32 w(MO)m(V)h(then)f(the)g(mem)m(b)s
+(er)f(HDU)i(is)f(deleted)h(from)e(infptr)g(after)227
+5204 y(the)e(transfer)f(to)h(outfptr.)95 5480 y Fe(int)47
+b(fits_transfer_member)c(/)k(ffgmtf)286 5593 y(\(fitsfile)f(*infptr,)f
+(fitsfile)h(*outfptr,)f(long)i(member,)e(int)i(tfopt,)334
+5706 y(>)h(int)e(*status\))p eop end
+%%Page: 90 98
+TeXDict begin 90 97 bop 0 299 a Fj(90)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(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)f(table)h(p)s(oin)m(ted)f(to)h(b)m(y)g(gfptr.)40
+b(The)29 b(mem)m(b)s(er)f(HDU)i(to)h(b)s(e)227 668 y(deleted)37
+b(is)e(iden)m(ti\014ed)h(b)m(y)f(its)h(ro)m(w)g(n)m(um)m(b)s(er)f(in)g
+(the)h(grouping)f(table)h(as)g(sp)s(eci\014ed)f(b)m(y)h(the)f
+(parameter)227 781 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)g(v)-5 b(alues:)227 894 y(OPT)p 431 894
+28 4 v 32 w(RM)p 613 894 V 33 w(ENTR)d(Y)34 b(whic)m(h)e(remo)m(v)m(es)
+j(the)e(mem)m(b)s(er)g(HDU)h(en)m(try)f(from)g(the)g(grouping)g(table)h
+(and)f(up-)227 1007 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 1007 V 32 w(RM)p
+2869 1007 V 33 w(MBR)h(whic)m(h)g(remo)m(v)m(es)h(the)227
+1120 y(mem)m(b)s(er)30 b(HDU)h(en)m(try)g(from)f(the)g(grouping)g
+(table)i(and)d(deletes)j(the)e(mem)m(b)s(er)g(HDU)h(itself.)95
+1380 y Fe(int)47 b(fits_remove_member)c(/)48 b(ffgmrm)286
+1492 y(\(fitsfile)e(*fptr,)g(long)g(member,)g(int)h(rmopt,)f(>)i(int)f
+(*status\))p eop end
+%%Page: 91 99
+TeXDict begin 91 98 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)h(in)m(terface)i(routines)e
+(describ)s(ed)e(previously)i(are)g(recommended)f(for)h(most)g(uses,)g
+(but)f(the)h(routines)0 2542 y(describ)s(ed)h(in)g(this)h(c)m(hapter)g
+(are)h(also)f(a)m(v)-5 b(ailable)34 b(if)c(necessary)-8
+b(.)43 b(Some)31 b(of)g(these)g(routines)g(p)s(erform)e(more)i(sp)s(e-)
+0 2655 y(cialized)e(function)d(that)i(cannot)f(easily)h(b)s(e)e(done)h
+(with)f(the)h(basic)h(in)m(terface)g(routines)f(while)f(others)h
+(duplicate)0 2767 y(the)j(functionalit)m(y)i(of)e(the)g(basic)h
+(routines)f(but)f(ha)m(v)m(e)i(a)g(sligh)m(tly)g(di\013eren)m(t)g
+(calling)g(sequence.)41 b(See)31 b(App)s(endix)0 2880
+y(B)g(for)f(the)g(de\014nition)g(of)h(eac)m(h)h(function)e(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)i(FITS)d(\014le)h
+(residing)g(in)g(core)h(computer)f(memory)-8 b(.)68 b(This)38
+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.)55
+b(The)35 b('\014lename')g(is)g(curren)m(tly)h(ignored)f(b)m(y)g(this)g
+(routine)g(and)g(ma)m(y)g(b)s(e)g(an)m(y)g(arbitrary)227
+3672 y(string.)78 b(In)42 b(general,)47 b(the)c(application)h(m)m(ust)f
+(ha)m(v)m(e)h(preallo)s(cated)g(an)e(initial)i(blo)s(c)m(k)g(of)f
+(memory)f(to)227 3785 y(hold)i(the)h(FITS)f(\014le)h(prior)f(to)h
+(calling)h(this)e(routine:)70 b('memptr')44 b(p)s(oin)m(ts)g(to)i(the)e
+(starting)i(address)227 3898 y(and)39 b('memsize')i(giv)m(es)g(the)f
+(initial)h(size)f(of)g(the)g(blo)s(c)m(k)g(of)g(memory)-8
+b(.)69 b('mem)p 2958 3898 V 33 w(reallo)s(c')41 b(is)f(a)g(p)s(oin)m
+(ter)f(to)227 4011 y(an)c(optional)i(function)d(that)i(CFITSIO)e(can)h
+(call)h(to)g(allo)s(cate)i(additional)e(memory)-8 b(,)37
+b(if)e(needed)f(\(only)227 4124 y(if)41 b(mo)s(de)e(=)h(READ)m
+(WRITE\),)i(and)e(is)g(mo)s(deled)g(after)h(the)f(standard)g(C)g
+('reallo)s(c')i(function;)j(a)c(n)m(ull)227 4237 y(p)s(oin)m(ter)g(ma)m
+(y)g(b)s(e)f(giv)m(en)i(if)e(the)h(initial)h(allo)s(cation)h(of)e
+(memory)f(is)h(all)g(that)g(will)g(b)s(e)f(required)g(\(e.g.,)227
+4350 y(if)35 b(the)g(\014le)g(is)g(op)s(ened)f(with)h(mo)s(de)f(=)h
+(READONL)-8 b(Y\).)36 b(The)e('deltasize')j(parameter)e(ma)m(y)h(b)s(e)
+e(used)g(to)227 4463 y(suggest)g(a)f(minim)m(um)f(amoun)m(t)h(of)g
+(additional)h(memory)f(that)g(should)f(b)s(e)g(allo)s(cated)j(during)d
+(eac)m(h)i(call)227 4575 y(to)d(the)f(memory)f(reallo)s(cation)j
+(function.)40 b(By)30 b(default,)g(CFITSIO)e(will)i(reallo)s(cate)j
+(enough)c(additional)227 4688 y(space)44 b(to)g(hold)f(the)h(en)m(tire)
+g(curren)m(tly)f(de\014ned)g(FITS)f(\014le)i(\(as)f(giv)m(en)i(b)m(y)e
+(the)h(NAXISn)e(k)m(eyw)m(ords\))227 4801 y(or)g(1)f(FITS)g(blo)s(c)m
+(k)h(\(=)f(2880)i(b)m(ytes\),)i(whic)m(h)d(ev)m(er)g(is)f(larger.)74
+b(V)-8 b(alues)43 b(of)e(deltasize)i(less)f(than)f(2880)227
+4914 y(will)31 b(b)s(e)f(ignored.)42 b(Since)31 b(the)g(memory)g
+(reallo)s(cation)i(op)s(eration)e(can)g(b)s(e)f(computationally)i(exp)s
+(ensiv)m(e,)227 5027 y(allo)s(cating)27 b(a)e(larger)g(initial)h(blo)s
+(c)m(k)f(of)g(memory)-8 b(,)26 b(and/or)f(sp)s(ecifying)f(a)h(larger)h
+(deltasize)g(v)-5 b(alue)25 b(ma)m(y)g(help)227 5140
+y(to)i(reduce)f(the)g(n)m(um)m(b)s(er)e(of)i(reallo)s(cation)i(calls)f
+(and)f(mak)m(e)h(the)f(application)h(program)f(run)e(faster.)40
+b(Note)227 5253 y(that)29 b(v)-5 b(alues)29 b(of)f(the)h(memptr)f(and)f
+(memsize)j(p)s(oin)m(ters)e(will)h(b)s(e)e(up)s(dated)g(b)m(y)i
+(CFITSIO)d(if)j(the)f(lo)s(cation)227 5366 y(or)j(size)g(of)f(the)h
+(FITS)f(\014le)g(in)g(memory)g(should)g(c)m(hange)h(as)g(a)g(result)f
+(of)g(allo)s(cating)j(more)e(memory)-8 b(.)95 5601 y
+Fe(int)47 b(fits_open_memfile)c(/)48 b(ffomem)286 5714
+y(\(fitsfile)e(**fptr,)f(const)i(char)f(*filename,)f(int)i(mode,)g
+(void)f(**memptr,)1905 5942 y Fj(91)p eop end
+%%Page: 92 100
+TeXDict begin 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)334 555 y Fe(size_t)46 b(*memsize,)f(size_t)i(deltasize,)
+334 668 y(void)g(*\(*mem_realloc\)\(void)42 b(*p,)47
+b(size_t)f(newsize\),)f(int)i(*status\))0 927 y Fi(2)81
+b Fj(Create)49 b(a)g(new)f(FITS)g(\014le)h(residing)f(in)h(core)g
+(computer)g(memory)-8 b(.)96 b(This)48 b(routine)g(is)h(analogous)h(to)
+227 1040 y(\014ts)p 354 1040 28 4 v 33 w(create)p 623
+1040 V 34 w(\014le.)40 b(In)29 b(general,)i(the)e(application)h(m)m
+(ust)f(ha)m(v)m(e)i(preallo)s(cated)g(an)e(initial)h(blo)s(c)m(k)g(of)f
+(memory)227 1152 y(to)38 b(hold)e(the)h(FITS)f(\014le)h(prior)f(to)h
+(calling)i(this)d(routine:)54 b('memptr')36 b(p)s(oin)m(ts)h(to)g(the)g
+(starting)h(address)227 1265 y(and)h('memsize')i(giv)m(es)g(the)f
+(initial)h(size)f(of)g(the)g(blo)s(c)m(k)g(of)g(memory)-8
+b(.)69 b('mem)p 2958 1265 V 33 w(reallo)s(c')41 b(is)f(a)g(p)s(oin)m
+(ter)f(to)227 1378 y(an)f(optional)g(function)f(that)h(CFITSIO)e(can)i
+(call)h(to)f(allo)s(cate)i(additional)e(memory)-8 b(,)40
+b(if)d(needed,)j(and)227 1491 y(is)34 b(mo)s(deled)f(after)h(the)g
+(standard)f(C)g('reallo)s(c')i(function;)g(a)f(n)m(ull)f(p)s(oin)m(ter)
+h(ma)m(y)g(b)s(e)f(giv)m(en)h(if)g(the)g(initial)227
+1604 y(allo)s(cation)i(of)d(memory)g(is)h(all)g(that)g(will)f(b)s(e)g
+(required.)48 b(The)33 b('deltasize')j(parameter)d(ma)m(y)h(b)s(e)f
+(used)f(to)227 1717 y(suggest)i(a)f(minim)m(um)f(amoun)m(t)h(of)g
+(additional)h(memory)f(that)g(should)f(b)s(e)g(allo)s(cated)j(during)d
+(eac)m(h)i(call)227 1830 y(to)d(the)f(memory)f(reallo)s(cation)j
+(function.)40 b(By)30 b(default,)g(CFITSIO)e(will)i(reallo)s(cate)j
+(enough)c(additional)227 1943 y(space)41 b(to)g(hold)e(1)i(FITS)e(blo)s
+(c)m(k)h(\(=)g(2880)i(b)m(ytes\))f(and)e(v)-5 b(alues)41
+b(of)f(deltasize)h(less)g(than)f(2880)h(will)g(b)s(e)227
+2056 y(ignored.)f(Since)28 b(the)f(memory)h(reallo)s(cation)i(op)s
+(eration)e(can)g(b)s(e)f(computationally)i(exp)s(ensiv)m(e,)g(allo)s
+(cat-)227 2169 y(ing)36 b(a)f(larger)h(initial)h(blo)s(c)m(k)e(of)h
+(memory)-8 b(,)37 b(and/or)e(sp)s(ecifying)g(a)h(larger)g(deltasize)h
+(v)-5 b(alue)36 b(ma)m(y)f(help)g(to)227 2282 y(reduce)f(the)g(n)m(um)m
+(b)s(er)e(of)i(reallo)s(cation)i(calls)f(and)e(mak)m(e)i(the)f
+(application)h(program)f(run)e(faster.)52 b(Note)227
+2395 y(that)29 b(v)-5 b(alues)29 b(of)f(the)h(memptr)f(and)f(memsize)j
+(p)s(oin)m(ters)e(will)h(b)s(e)e(up)s(dated)g(b)m(y)i(CFITSIO)d(if)j
+(the)f(lo)s(cation)227 2507 y(or)j(size)g(of)f(the)h(FITS)f(\014le)g
+(in)g(memory)g(should)g(c)m(hange)h(as)g(a)g(result)f(of)g(allo)s
+(cating)j(more)e(memory)-8 b(.)95 2766 y Fe(int)47 b
+(fits_create_memfile)c(/)k(ffimem)286 2879 y(\(fitsfile)f(**fptr,)f
+(void)i(**memptr,)334 2992 y(size_t)f(*memsize,)f(size_t)i(deltasize,)
+334 3105 y(void)g(*\(*mem_realloc\)\(void)42 b(*p,)47
+b(size_t)f(newsize\),)f(int)i(*status\))0 3363 y Fi(3)81
+b Fj(Reop)s(en)34 b(a)i(FITS)e(\014le)h(that)h(w)m(as)f(previously)g
+(op)s(ened)g(with)f(\014ts)p 2414 3363 V 33 w(op)s(en)p
+2637 3363 V 32 w(\014le)h(or)g(\014ts)p 3058 3363 V 33
+w(create)p 3327 3363 V 34 w(\014le.)55 b(The)34 b(new)227
+3476 y(\014ts\014le)i(p)s(oin)m(ter)h(ma)m(y)g(then)f(b)s(e)f(treated)j
+(as)e(a)h(separate)g(\014le,)h(and)e(one)h(ma)m(y)g(sim)m(ultaneously)g
+(read)f(or)227 3589 y(write)e(to)h(2)f(\(or)g(more\))g(di\013eren)m(t)g
+(extensions)g(in)g(the)g(same)g(\014le.)51 b(The)33 b(\014ts)p
+2886 3589 V 32 w(op)s(en)p 3108 3589 V 32 w(\014le)h(routine)g(\(ab)s
+(o)m(v)m(e\))227 3702 y(automatically)k(detects)f(cases)f(where)e(a)i
+(previously)f(op)s(ened)f(\014le)i(is)f(b)s(eing)g(op)s(ened)f(again,)k
+(and)c(then)227 3815 y(in)m(ternally)e(call)f(\014ts)p
+930 3815 V 33 w(reop)s(en)p 1229 3815 V 32 w(\014le,)g(so)f(programs)g
+(should)g(rarely)g(need)g(to)h(explicitly)h(call)g(this)e(routine.)95
+4073 y Fe(int)47 b(fits_reopen_file)d(/)j(ffreopen)286
+4186 y(\(fitsfile)f(*openfptr,)f(fitsfile)g(**newfptr,)g(>)j(int)f
+(*status\))0 4445 y Fi(4)81 b Fj(Create)24 b(a)g(new)f(FITS)g(\014le,)i
+(using)e(a)h(template)h(\014le)e(to)i(de\014ne)d(its)i(initial)h(size)g
+(and)e(structure.)37 b(The)24 b(template)227 4558 y(ma)m(y)i(b)s(e)f
+(another)g(FITS)g(HDU)h(or)f(an)g(ASCI)s(I)f(template)j(\014le.)39
+b(If)25 b(the)g(input)g(template)h(\014le)g(name)f(p)s(oin)m(ter)227
+4671 y(is)j(n)m(ull,)h(then)e(this)h(routine)f(b)s(eha)m(v)m(es)i(the)f
+(same)g(as)g(\014ts)p 2160 4671 V 32 w(create)p 2428
+4671 V 35 w(\014le.)40 b(The)27 b(curren)m(tly)h(supp)s(orted)e(format)
+227 4784 y(of)33 b(the)g(ASCI)s(I)e(template)j(\014le)e(is)h(describ)s
+(ed)e(under)g(the)i(\014ts)p 2350 4784 V 33 w(parse)p
+2591 4784 V 32 w(template)h(routine)f(\(in)f(the)h(general)227
+4897 y(Utilities)g(section\))95 5155 y Fe(int)47 b
+(fits_create_template)c(/)k(fftplt)286 5268 y(\(fitsfile)f(**fptr,)f
+(char)i(*filename,)e(char)i(*tpltfile)e(>)i(int)g(*status\))0
+5527 y Fi(5)81 b Fj(P)m(arse)31 b(the)f(input)g(\014lename)g(or)g(URL)h
+(in)m(to)g(its)g(comp)s(onen)m(t)f(parts,)h(namely:)336
+5714 y Fc(\017)46 b Fj(the)31 b(\014le)f(t)m(yp)s(e)h(\(\014le://,)h
+(ftp://,)f(h)m(ttp://,)h(etc\),)p eop end
+%%Page: 93 101
+TeXDict begin 93 100 bop 0 299 a Fh(9.1.)72 b(FITS)30
+b(FILE)g(A)m(CCESS)f(R)m(OUTINES)2244 b Fj(93)336 555
+y Fc(\017)46 b Fj(the)31 b(base)f(input)g(\014le)g(name,)336
+702 y Fc(\017)46 b Fj(the)31 b(name)f(of)h(the)f(output)g(\014le)h
+(that)g(the)f(input)g(\014le)g(is)h(to)g(b)s(e)e(copied)i(to)g(prior)f
+(to)h(op)s(ening,)336 848 y Fc(\017)46 b Fj(the)31 b(HDU)g(or)f
+(extension)h(sp)s(eci\014cation,)336 995 y Fc(\017)46
+b Fj(the)31 b(\014ltering)f(sp)s(eci\014er,)336 1141
+y Fc(\017)46 b Fj(the)31 b(binning)e(sp)s(eci\014er,)336
+1288 y Fc(\017)46 b Fj(the)31 b(column)f(sp)s(eci\014er,)336
+1434 y Fc(\017)46 b Fj(and)30 b(the)h(image)g(pixel)g(\014ltering)g(sp)
+s(eci\014er.)227 1623 y(A)k(n)m(ull)g(p)s(oin)m(ter)f(\(0\))i(ma)m(y)g
+(b)s(e)e(b)s(e)g(sp)s(eci\014ed)g(for)g(an)m(y)h(of)g(the)g(output)g
+(string)f(argumen)m(ts)h(that)h(are)f(not)227 1736 y(needed.)52
+b(Null)34 b(strings)g(will)g(b)s(e)g(returned)f(for)h(an)m(y)g(comp)s
+(onen)m(ts)g(that)h(are)f(not)h(presen)m(t)f(in)g(the)g(input)227
+1849 y(\014le)28 b(name.)39 b(The)27 b(calling)i(routine)e(m)m(ust)g
+(allo)s(cate)j(su\016cien)m(t)d(memory)g(to)h(hold)f(the)g(returned)f
+(c)m(haracter)227 1962 y(strings.)52 b(Allo)s(cating)37
+b(the)d(string)g(lengths)h(equal)g(to)g(FLEN)p 2362 1962
+28 4 v 33 w(FILENAME)f(is)g(guaran)m(teed)i(to)f(b)s(e)e(safe.)227
+2075 y(These)d(routines)h(are)f(mainly)h(for)f(in)m(ternal)h(use)f(b)m
+(y)h(other)f(CFITSIO)f(routines.)95 2335 y Fe(int)47
+b(fits_parse_input_url)c(/)k(ffiurl)286 2448 y(\(char)g(*filename,)e(>)
+i(char)g(*filetype,)e(char)h(*infile,)g(char)h(*outfile,)e(char)334
+2561 y(*extspec,)g(char)i(*filter,)f(char)g(*binspec,)f(char)i
+(*colspec,)e(int)i(*status\))95 2787 y(int)g(fits_parse_input_filename)
+41 b(/)48 b(ffifile)286 2900 y(\(char)f(*filename,)e(>)i(char)g
+(*filetype,)e(char)h(*infile,)g(char)h(*outfile,)e(char)334
+3013 y(*extspec,)g(char)i(*filter,)f(char)g(*binspec,)f(char)i
+(*colspec,)e(char)i(*pixspec,)334 3125 y(int)g(*status\))0
+3386 y Fi(6)81 b Fj(P)m(arse)33 b(the)f(input)g(\014lename)h(and)e
+(return)h(the)h(HDU)g(n)m(um)m(b)s(er)e(that)i(w)m(ould)f(b)s(e)g(mo)m
+(v)m(ed)i(to)f(if)f(the)h(\014le)f(w)m(ere)227 3499 y(op)s(ened)h(with)
+g(\014ts)p 878 3499 V 32 w(op)s(en)p 1100 3499 V 32 w(\014le.)49
+b(The)33 b(returned)f(HDU)i(n)m(um)m(b)s(er)e(b)s(egins)h(with)g(1)g
+(for)g(the)g(primary)g(arra)m(y)-8 b(,)227 3612 y(so)40
+b(for)f(example,)k(if)c(the)h(input)e(\014lename)i(=)f(`m)m
+(y\014le.\014ts[2]')i(then)e(hdun)m(um)e(=)i(3)h(will)g(b)s(e)f
+(returned.)227 3725 y(CFITSIO)j(do)s(es)i(not)g(op)s(en)f(the)g(\014le)
+h(to)h(c)m(hec)m(k)g(if)e(the)h(extension)h(actually)g(exists)f(if)g
+(an)f(extension)227 3838 y(n)m(um)m(b)s(er)e(is)i(sp)s(eci\014ed.)75
+b(If)42 b(an)g(extension)h(name)f(is)h(included)e(in)h(the)h(\014le)f
+(name)g(sp)s(eci\014cation)h(\(e.g.)227 3951 y(`m)m
+(y\014le.\014ts[EVENTS]')i(then)e(this)h(routine)g(will)h(ha)m(v)m(e)g
+(to)f(op)s(en)g(the)g(FITS)f(\014le)h(and)f(lo)s(ok)i(for)f(the)227
+4064 y(p)s(osition)31 b(of)f(the)h(named)f(extension,)i(then)e(close)i
+(\014le)e(again.)42 b(This)30 b(is)g(not)h(p)s(ossible)f(if)h(the)f
+(\014le)h(is)f(b)s(eing)227 4176 y(read)k(from)f(the)h(stdin)f(stream,)
+i(and)f(an)f(error)g(will)i(b)s(e)e(returned)f(in)i(this)f(case.)52
+b(If)33 b(the)h(\014lename)g(do)s(es)227 4289 y(not)42
+b(sp)s(ecify)g(an)g(explicit)h(extension)g(\(e.g.)76
+b('m)m(y\014le.\014ts'\))43 b(then)f(hdun)m(um)e(=)h(-99)i(will)g(b)s
+(e)e(returned,)227 4402 y(whic)m(h)35 b(is)g(functionally)h(equiv)-5
+b(alen)m(t)36 b(to)g(hdun)m(um)d(=)h(1.)55 b(This)34
+b(routine)h(is)g(mainly)h(used)e(for)g(bac)m(kw)m(ard)227
+4515 y(compatibilit)m(y)39 b(in)e(the)f(fto)s(ols)i(soft)m(w)m(are)g
+(pac)m(k)-5 b(age)39 b(and)d(is)g(not)h(recommended)g(for)f(general)i
+(use.)59 b(It)37 b(is)227 4628 y(generally)k(b)s(etter)e(and)g(more)g
+(e\016cien)m(t)i(to)f(\014rst)e(op)s(en)h(the)g(FITS)g(\014le)g(with)g
+(\014ts)p 3125 4628 V 32 w(op)s(en)p 3347 4628 V 33 w(\014le,)i(then)e
+(use)227 4741 y(\014ts)p 354 4741 V 33 w(get)p 507 4741
+V 34 w(hdu)p 694 4741 V 31 w(n)m(um)c(to)i(determine)g(whic)m(h)f(HDU)h
+(in)f(the)h(\014le)f(has)g(b)s(een)g(op)s(ened,)h(rather)f(than)g
+(calling)227 4854 y(\014ts)p 354 4854 V 33 w(parse)p
+595 4854 V 32 w(input)p 840 4854 V 32 w(url)30 b(follo)m(w)m(ed)i(b)m
+(y)e(a)h(call)g(to)h(\014ts)p 1967 4854 V 32 w(op)s(en)p
+2189 4854 V 32 w(\014le.)143 5115 y Fe(int)47 b(fits_parse_extnum)c(/)
+48 b(ffextn)334 5227 y(\(char)e(*filename,)f(>)j(int)f(*hdunum,)e(int)i
+(*status\))0 5488 y Fi(7)81 b Fj(P)m(arse)45 b(the)g(input)e(\014le)i
+(name)g(and)f(return)f(the)i(ro)s(ot)g(\014le)g(name.)83
+b(The)44 b(ro)s(ot)h(name)g(includes)f(the)h(\014le)227
+5601 y(t)m(yp)s(e)35 b(if)g(sp)s(eci\014ed,)h(\(e.g.)56
+b('ftp://')37 b(or)e('h)m(ttp://'\))i(and)d(the)h(full)g(path)g(name,)h
+(to)g(the)f(exten)m(t)i(that)e(it)h(is)227 5714 y(sp)s(eci\014ed)26
+b(in)f(the)i(input)e(\014lename.)39 b(It)26 b(do)s(es)g(not)g(include)g
+(the)g(HDU)h(name)f(or)g(n)m(um)m(b)s(er,)g(or)g(an)m(y)h(\014ltering)p
+eop end
+%%Page: 94 102
+TeXDict begin 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)227 555 y Fj(sp)s(eci\014cations.)86 b(The)45
+b(calling)h(routine)g(m)m(ust)f(allo)s(cate)i(su\016cien)m(t)f(memory)f
+(to)h(hold)f(the)g(returned)227 668 y(ro)s(otname)33
+b(c)m(haracter)g(string.)46 b(Allo)s(cating)34 b(the)f(length)f(equal)h
+(to)f(FLEN)p 2817 668 28 4 v 33 w(FILENAME)h(is)f(guaran)m(teed)227
+781 y(to)f(b)s(e)f(safe.)143 1019 y Fe(int)47 b(fits_parse_rootname)c
+(/)k(ffrtnm)334 1132 y(\(char)f(*filename,)f(>)j(char)f(*rootname,)e
+(int)h(*status\);)0 1370 y Fi(8)81 b Fj(T)-8 b(est)37
+b(if)f(the)h(input)f(\014le)h(or)f(a)h(compressed)g(v)m(ersion)g(of)g
+(the)g(\014le)f(\(with)h(a)g(.gz,)j(.Z,)c(.z,)j(or)e(.zip)g
+(extension\))227 1483 y(exists)i(on)f(disk.)63 b(The)37
+b(returned)g(v)-5 b(alue)38 b(of)g(the)h('exists')g(parameter)f(will)g
+(ha)m(v)m(e)i(1)e(of)g(the)g(4)g(follo)m(wing)227 1596
+y(v)-5 b(alues:)370 1820 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
+1933 y(1:)95 b(the)47 b(disk)g(file)g(does)f(exist)370
+2046 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 2159 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 2272 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
+2587 y(int)h(fits_file_exists)c(/)48 b(ffexist)334 2700
+y(\(char)e(*filename,)f(>)j(int)f(*exists,)e(int)i(*status\);)0
+2938 y Fi(9)81 b Fj(Flush)36 b(an)m(y)i(in)m(ternal)g(bu\013ers)e(of)i
+(data)g(to)g(the)f(output)g(FITS)g(\014le.)62 b(These)37
+b(routines)g(rarely)g(need)g(to)i(b)s(e)227 3051 y(called,)i(but)36
+b(can)i(b)s(e)f(useful)f(in)h(cases)i(where)d(other)i(pro)s(cesses)f
+(need)g(to)h(access)h(the)f(same)f(FITS)g(\014le)227
+3164 y(in)j(real)i(time,)h(either)e(on)g(disk)f(or)g(in)g(memory)-8
+b(.)71 b(These)41 b(routines)f(also)h(help)f(to)i(ensure)d(that)i(if)g
+(the)227 3277 y(application)c(program)d(subsequen)m(tly)h(ab)s(orts)f
+(then)h(the)g(FITS)f(\014le)h(will)g(ha)m(v)m(e)i(b)s(een)d(closed)h
+(prop)s(erly)-8 b(.)227 3390 y(The)43 b(\014rst)g(routine,)k(\014ts)p
+1110 3390 V 33 w(\015ush)p 1332 3390 V 31 w(\014le)c(is)h(more)f
+(rigorous)h(and)f(completely)i(closes,)j(then)c(reop)s(ens,)i(the)227
+3503 y(curren)m(t)31 b(HDU,)h(b)s(efore)e(\015ushing)g(the)h(in)m
+(ternal)g(bu\013ers,)f(th)m(us)h(ensuring)f(that)h(the)g(output)g(FITS)
+f(\014le)h(is)227 3615 y(iden)m(tical)38 b(to)e(what)f(w)m(ould)h(b)s
+(e)f(pro)s(duced)f(if)h(the)h(FITS)f(w)m(as)h(closed)g(at)g(that)g(p)s
+(oin)m(t)g(\(i.e.,)i(with)e(a)g(call)227 3728 y(to)g(\014ts)p
+470 3728 V 33 w(close)p 689 3728 V 34 w(\014le\).)56
+b(The)35 b(second)g(routine,)i(\014ts)p 1912 3728 V 33
+w(\015ush)p 2134 3728 V 31 w(bu\013er)d(simply)h(\015ushes)f(the)h(in)m
+(ternal)h(CFITSIO)227 3841 y(bu\013ers)28 b(of)h(data)h(to)f(the)h
+(output)e(FITS)g(\014le,)i(without)f(up)s(dating)f(and)g(closing)i(the)
+f(curren)m(t)g(HDU.)h(This)227 3954 y(is)37 b(m)m(uc)m(h)g(faster,)i
+(but)e(there)g(ma)m(y)g(b)s(e)f(circumstances)i(where)e(the)h
+(\015ushed)f(\014le)h(do)s(es)f(not)h(completely)227
+4067 y(re\015ect)31 b(the)g(\014nal)f(state)i(of)e(the)h(\014le)f(as)h
+(it)g(will)f(exist)i(when)d(the)h(\014le)h(is)f(actually)i(closed.)227
+4214 y(A)f(t)m(ypical)h(use)e(of)h(these)g(routines)f(w)m(ould)g(b)s(e)
+g(to)h(\015ush)e(the)h(state)i(of)f(a)g(FITS)e(table)j(to)f(disk)f
+(after)h(eac)m(h)227 4327 y(ro)m(w)36 b(of)f(the)h(table)g(is)f
+(written.)55 b(It)36 b(is)f(recommend)g(that)h(\014ts)p
+2392 4327 V 32 w(\015ush)p 2613 4327 V 32 w(\014le)f(b)s(e)g(called)h
+(after)g(the)f(\014rst)g(ro)m(w)227 4440 y(is)k(written,)i(then)d
+(\014ts)p 1023 4440 V 32 w(\015ush)p 1244 4440 V 31 w(bu\013er)g(ma)m
+(y)h(b)s(e)f(called)h(after)g(eac)m(h)h(subsequen)m(t)e(ro)m(w)g(is)h
+(written.)65 b(Note)227 4552 y(that)40 b(this)f(latter)h(routine)f
+(will)g(not)g(automatically)j(up)s(date)c(the)h(NAXIS2)g(k)m(eyw)m(ord)
+h(whic)m(h)e(records)227 4665 y(the)c(n)m(um)m(b)s(er)d(of)i(ro)m(ws)h
+(of)f(data)g(in)g(the)g(table,)i(so)f(this)f(k)m(eyw)m(ord)g(m)m(ust)g
+(b)s(e)f(explicitly)j(up)s(dated)d(b)m(y)h(the)227 4778
+y(application)f(program)e(after)h(eac)m(h)h(ro)m(w)e(is)g(written.)95
+5016 y Fe(int)47 b(fits_flush_file)d(/)j(ffflus)286 5129
+y(\(fitsfile)f(*fptr,)g(>)h(int)g(*status\))95 5355 y(int)g
+(fits_flush_buffer)c(/)48 b(ffflsh)286 5468 y(\(fitsfile)e(*fptr,)g(0,)
+h(>)g(int)g(*status\))286 5694 y(\(Note:)94 b(The)47
+b(second)f(argument)g(must)g(be)i(0\).)p eop end
+%%Page: 95 103
+TeXDict begin 95 102 bop 0 299 a Fh(9.2.)72 b(HDU)31
+b(A)m(CCESS)e(R)m(OUTINES)2488 b Fj(95)0 555 y Ff(9.2)135
+b(HDU)46 b(Access)e(Routines)0 795 y Fi(1)81 b Fj(Get)28
+b(the)f(b)m(yte)h(o\013sets)g(in)f(the)g(FITS)f(\014le)i(to)f(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 908 y(in)34 b(the)g(CHDU.)g(The)f(di\013erence)h(b)s(et)m(w)m
+(een)h(headstart)f(and)f(dataend)h(equals)g(the)g(size)g(of)g(the)g
+(CHDU.)227 1021 y(If)e(the)h(CHDU)f(is)h(the)f(last)h(HDU)g(in)f(the)h
+(\014le,)g(then)f(dataend)g(is)g(also)i(equal)e(to)h(the)g(size)g(of)g
+(the)f(en)m(tire)227 1133 y(FITS)i(\014le.)55 b(Null)35
+b(p)s(oin)m(ters)g(ma)m(y)g(b)s(e)f(input)g(for)h(an)m(y)g(of)g(the)g
+(address)f(parameters)i(if)e(their)h(v)-5 b(alues)36
+b(are)227 1246 y(not)31 b(needed.)95 1502 y Fe(int)47
+b(fits_get_hduaddr)d(/)j(ffghad)94 b(\(only)46 b(supports)g(files)g(up)
+h(to)h(2.1)f(GB)g(in)g(size\))334 1615 y(\(fitsfile)e(*fptr,)h(>)i
+(long)f(*headstart,)d(long)j(*datastart,)e(long)h(*dataend,)382
+1728 y(int)h(*status\))95 1953 y(int)g(fits_get_hduaddrll)c(/)48
+b(ffghadll)93 b(\(supports)45 b(large)i(files\))334 2066
+y(\(fitsfile)e(*fptr,)h(>)i(LONGLONG)d(*headstart,)g(LONGLONG)h
+(*datastart,)382 2179 y(LONGLONG)f(*dataend,)h(int)h(*status\))0
+2434 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.)42
+b(This)31 b(is)g(no)m(w)g(the)g(CHDU)g(but)f(it)227 2547
+y(is)i(completely)g(empt)m(y)g(and)f(has)g(no)g(header)g(k)m(eyw)m
+(ords.)43 b(It)32 b(is)f(recommended)g(that)h(\014ts)p
+3344 2547 28 4 v 32 w(create)p 3612 2547 V 34 w(img)g(or)227
+2660 y(\014ts)p 354 2660 V 33 w(create)p 623 2660 V 34
+w(tbl)e(b)s(e)g(used)g(instead)g(of)h(this)f(routine.)95
+2916 y Fe(int)47 b(fits_create_hdu)d(/)j(ffcrhd)286 3028
+y(\(fitsfile)f(*fptr,)g(>)h(int)g(*status\))0 3284 y
+Fi(3)81 b Fj(Insert)22 b(a)h(new)g(IMA)m(GE)h(extension)f(immediately)i
+(follo)m(wing)f(the)f(CHDU,)h(or)f(insert)g(a)g(new)f(Primary)h(Arra)m
+(y)227 3397 y(at)30 b(the)e(b)s(eginning)g(of)h(the)g(\014le.)40
+b(An)m(y)29 b(follo)m(wing)h(extensions)f(in)g(the)f(\014le)h(will)g(b)
+s(e)f(shifted)g(do)m(wn)h(to)g(mak)m(e)227 3510 y(ro)s(om)36
+b(for)h(the)f(new)g(extension.)59 b(If)36 b(the)h(CHDU)g(is)f(the)h
+(last)g(HDU)g(in)f(the)h(\014le)f(then)g(the)h(new)f(image)227
+3623 y(extension)31 b(will)g(simply)e(b)s(e)h(app)s(ended)e(to)j(the)f
+(end)g(of)g(the)g(\014le.)41 b(One)30 b(can)g(force)h(a)g(new)e
+(primary)g(arra)m(y)227 3735 y(to)35 b(b)s(e)d(inserted)i(at)g(the)g(b)
+s(eginning)f(of)g(the)h(FITS)f(\014le)g(b)m(y)h(setting)h(status)e(=)h
+(PREPEND)p 3432 3735 V 32 w(PRIMAR)-8 b(Y)227 3848 y(prior)25
+b(to)g(calling)i(the)e(routine.)38 b(In)25 b(this)f(case)i(the)f(old)g
+(primary)f(arra)m(y)i(will)f(b)s(e)f(con)m(v)m(erted)j(to)e(an)g(IMA)m
+(GE)227 3961 y(extension.)49 b(The)32 b(new)g(extension)i(\(or)f
+(primary)f(arra)m(y\))h(will)h(b)s(ecome)f(the)g(CHDU.)g(Refer)g(to)h
+(Chapter)227 4074 y(9)d(for)f(a)h(list)g(of)f(pre-de\014ned)f(bitpix)i
+(v)-5 b(alues.)95 4329 y Fe(int)47 b(fits_insert_img)d(/)j(ffiimg)286
+4442 y(\(fitsfile)f(*fptr,)g(int)h(bitpix,)e(int)i(naxis,)f(long)h
+(*naxes,)f(>)h(int)g(*status\))95 4668 y(int)g(fits_insert_imgll)c(/)48
+b(ffiimgll)286 4781 y(\(fitsfile)e(*fptr,)g(int)h(bitpix,)e(int)i
+(naxis,)f(LONGLONG)g(*naxes,)g(>)h(int)g(*status\))0
+5036 y Fi(4)81 b Fj(Insert)30 b(a)g(new)g(ASCI)s(I)f(or)i(binary)f
+(table)h(extension)g(immediately)h(follo)m(wing)g(the)f(CHDU.)g(An)m(y)
+f(follo)m(wing)227 5149 y(extensions)36 b(will)g(b)s(e)f(shifted)g(do)m
+(wn)g(to)h(mak)m(e)g(ro)s(om)g(for)f(the)g(new)g(extension.)57
+b(If)35 b(there)h(are)f(no)h(other)227 5262 y(follo)m(wing)c
+(extensions)g(then)e(the)h(new)f(table)h(extension)h(will)f(simply)f(b)
+s(e)g(app)s(ended)f(to)i(the)g(end)f(of)h(the)227 5375
+y(\014le.)42 b(If)30 b(the)h(FITS)f(\014le)g(is)h(curren)m(tly)g(empt)m
+(y)g(then)f(this)g(routine)h(will)g(create)h(a)f(dumm)m(y)f(primary)f
+(arra)m(y)227 5488 y(b)s(efore)i(app)s(ending)f(the)i(table)h(to)f(it.)
+44 b(The)31 b(new)g(extension)i(will)e(b)s(ecome)h(the)g(CHDU.)g(The)f
+(tunit)h(and)227 5601 y(extname)39 b(parameters)g(are)f(optional)i(and)
+e(a)g(n)m(ull)g(p)s(oin)m(ter)h(ma)m(y)f(b)s(e)g(giv)m(en)h(if)f(they)h
+(are)f(not)h(de\014ned.)227 5714 y(When)32 b(inserting)g(an)g(ASCI)s(I)
+f(table)i(with)e(\014ts)p 1847 5714 V 33 w(insert)p 2103
+5714 V 33 w(atbl,)i(a)f(n)m(ull)g(p)s(oin)m(ter)g(ma)m(y)h(giv)m(en)g
+(for)f(the)g(*tb)s(col)p eop end
+%%Page: 96 104
+TeXDict begin 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)227 555 y Fj(parameter)23 b(in)f(whic)m(h)h(case)g(eac)m
+(h)h(column)e(of)h(the)g(table)g(will)g(b)s(e)f(separated)h(b)m(y)f(a)h
+(single)g(space)g(c)m(haracter.)227 668 y(Similarly)-8
+b(,)29 b(if)d(the)h(input)f(v)-5 b(alue)27 b(of)g(ro)m(wlen)g(is)f(0,)i
+(then)f(CFITSIO)e(will)i(calculate)i(the)e(default)f(ro)m(wlength)227
+781 y(based)39 b(on)g(the)g(tb)s(col)h(and)e(tt)m(yp)s(e)h(v)-5
+b(alues.)67 b(Under)39 b(normal)g(circumstances,)j(the)d(nro)m(ws)f
+(paramen)m(ter)227 894 y(should)31 b(ha)m(v)m(e)i(a)f(v)-5
+b(alue)32 b(of)f(0;)i(CFITSIO)d(will)i(automatically)j(up)s(date)30
+b(the)i(n)m(um)m(b)s(er)e(of)i(ro)m(ws)g(as)g(data)g(is)227
+1007 y(written)26 b(to)h(the)f(table.)40 b(When)25 b(inserting)h(a)h
+(binary)e(table)h(with)g(\014ts)p 2596 1007 28 4 v 32
+w(insert)p 2851 1007 V 33 w(btbl,)g(if)g(there)g(are)g(follo)m(wing)227
+1120 y(extensions)f(in)f(the)h(\014le)f(and)g(if)g(the)h(table)g(con)m
+(tains)g(v)-5 b(ariable)25 b(length)g(arra)m(y)g(columns)f(then)g(p)s
+(coun)m(t)g(m)m(ust)227 1233 y(sp)s(ecify)30 b(the)h(exp)s(ected)g
+(\014nal)f(size)h(of)f(the)h(data)g(heap,)f(otherwise)h(p)s(coun)m(t)f
+(m)m(ust)h(=)f(0.)95 1490 y Fe(int)47 b(fits_insert_atbl)d(/)j(ffitab)
+286 1603 y(\(fitsfile)f(*fptr,)g(LONGLONG)f(rowlen,)h(LONGLONG)g
+(nrows,)g(int)h(tfields,)e(char)i(*ttype[],)334 1716
+y(long)g(*tbcol,)f(char)g(*tform[],)f(char)i(*tunit[],)e(char)i
+(*extname,)e(>)j(int)f(*status\))95 1942 y(int)g(fits_insert_btbl)d(/)j
+(ffibin)286 2055 y(\(fitsfile)f(*fptr,)g(LONGLONG)f(nrows,)h(int)h
+(tfields,)f(char)g(**ttype,)286 2168 y(char)h(**tform,)f(char)g
+(**tunit,)g(char)g(*extname,)g(long)g(pcount,)g(>)i(int)e(*status\))0
+2425 y Fi(5)81 b Fj(Mo)s(dify)27 b(the)h(size,)h(dimensions,)f(and/or)f
+(data)i(t)m(yp)s(e)f(of)f(the)h(curren)m(t)g(primary)e(arra)m(y)i(or)g
+(image)h(extension.)227 2538 y(If)39 b(the)h(new)e(image,)44
+b(as)39 b(sp)s(eci\014ed)g(b)m(y)g(the)g(input)g(argumen)m(ts,)j(is)d
+(larger)h(than)f(the)h(curren)m(t)f(existing)227 2651
+y(image)30 b(in)e(the)g(FITS)g(\014le)g(then)g(zero)h(\014ll)f(data)h
+(will)g(b)s(e)f(inserted)g(at)h(the)f(end)g(of)g(the)h(curren)m(t)f
+(image)i(and)227 2764 y(an)m(y)35 b(follo)m(wing)h(extensions)f(will)g
+(b)s(e)f(mo)m(v)m(ed)i(further)d(bac)m(k)i(in)g(the)f(\014le.)54
+b(Similarly)-8 b(,)36 b(if)f(the)g(new)f(image)227 2877
+y(is)j(smaller)g(than)g(the)f(curren)m(t)h(image)h(then)e(an)m(y)h
+(follo)m(wing)h(extensions)f(will)g(b)s(e)f(shifted)h(up)e(to)m(w)m
+(ards)227 2990 y(the)h(b)s(eginning)f(of)h(the)g(FITS)f(\014le)h(and)f
+(the)h(image)h(data)f(will)h(b)s(e)e(truncated)g(to)i(the)f(new)f
+(size.)58 b(This)227 3103 y(routine)27 b(rewrites)g(the)h(BITPIX,)f
+(NAXIS,)g(and)f(NAXISn)g(k)m(eyw)m(ords)i(with)f(the)g(appropriate)g(v)
+-5 b(alues)27 b(for)227 3216 y(the)k(new)f(image.)95
+3473 y Fe(int)47 b(fits_resize_img)d(/)j(ffrsim)286 3586
+y(\(fitsfile)f(*fptr,)g(int)h(bitpix,)e(int)i(naxis,)f(long)h(*naxes,)f
+(>)h(int)g(*status\))95 3812 y(int)g(fits_resize_imgll)c(/)48
+b(ffrsimll)286 3925 y(\(fitsfile)e(*fptr,)g(int)h(bitpix,)e(int)i
+(naxis,)f(LONGLONG)g(*naxes,)g(>)h(int)g(*status\))0
+4183 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)h(with)f(infptr)e(to)j
+(the)f(CHDU)227 4295 y(asso)s(ciated)34 b(with)e(outfptr.)47
+b(This)32 b(will)g(o)m(v)m(erwrite)i(an)m(y)f(data)g(previously)g(in)f
+(the)h(output)f(CHDU.)h(This)227 4408 y(lo)m(w)39 b(lev)m(el)h(routine)
+e(is)g(used)f(b)m(y)h(\014ts)p 1510 4408 V 33 w(cop)m(y)p
+1724 4408 V 33 w(hdu,)h(but)e(it)i(ma)m(y)f(also)h(b)s(e)f(useful)f(in)
+h(certain)h(application)227 4521 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)i(to)g(another)
+f(but)f(also)j(w)m(an)m(t)f(to)g(mo)s(dify)227 4634 y(the)h(header)g(k)
+m(eyw)m(ords.)46 b(The)32 b(required)f(FITS)g(header)h(k)m(eyw)m(ords)g
+(whic)m(h)g(de\014ne)f(the)h(structure)g(of)g(the)227
+4747 y(HDU)f(m)m(ust)g(b)s(e)e(written)i(to)g(the)f(output)g(CHDU)h(b)s
+(efore)f(calling)i(this)e(routine.)95 5005 y Fe(int)47
+b(fits_copy_data)d(/)k(ffcpdt)286 5118 y(\(fitsfile)e(*infptr,)f
+(fitsfile)h(*outfptr,)f(>)i(int)g(*status\))0 5375 y
+Fi(7)81 b Fj(Read)30 b(or)g(write)g(a)h(sp)s(eci\014ed)e(n)m(um)m(b)s
+(er)g(of)i(b)m(ytes)f(starting)h(at)g(the)g(sp)s(eci\014ed)e(b)m(yte)i
+(o\013set)g(from)f(the)g(start)h(of)227 5488 y(the)c(extension)g(data)f
+(unit.)39 b(These)26 b(lo)m(w)h(lev)m(el)h(routine)e(are)h(in)m(tended)
+f(mainly)g(for)g(accessing)i(the)e(data)h(in)227 5601
+y(non-standard,)h(conforming)g(extensions,)h(and)e(should)g(not)h(b)s
+(e)g(used)f(for)g(standard)g(IMA)m(GE,)i(T)-8 b(ABLE,)227
+5714 y(or)31 b(BINT)-8 b(ABLE)31 b(extensions.)p eop
+end
+%%Page: 97 105
+TeXDict begin 97 104 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29
+b(HEADER)i(KEYW)m(ORD)g(R)m(OUTINES)1510 b Fj(97)95 555
+y Fe(int)47 b(fits_read_ext)e(/)i(ffgextn)286 668 y(\(fitsfile)f
+(*fptr,)g(LONGLONG)f(offset,)h(LONGLONG)g(nbytes,)f(void)i(*buffer\))95
+781 y(int)g(fits_write_ext)d(/)k(ffpextn)286 894 y(\(fitsfile)e(*fptr,)
+g(LONGLONG)f(offset,)h(LONGLONG)g(nbytes,)f(void)i(*buffer\))0
+1158 y Fi(8)81 b Fj(This)34 b(routine)g(forces)h(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 1271 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)g(reinitializes)i
+(the)d(in)m(ternal)227 1384 y(bu\013ers)26 b(that)h(describ)s(e)g(the)g
+(HDU)g(structure.)39 b(This)26 b(routine)h(is)g(useful)f(for)g
+(reinitializing)j(the)e(structure)227 1497 y(of)34 b(an)f(HDU)h(if)f
+(an)m(y)h(of)g(the)f(required)g(k)m(eyw)m(ords)g(\(e.g.,)j(NAXISn\))d
+(ha)m(v)m(e)i(b)s(een)e(mo)s(di\014ed.)48 b(In)33 b(practice)227
+1610 y(it)e(should)e(rarely)h(b)s(e)f(necessary)h(to)h(call)g(this)f
+(routine)g(b)s(ecause)f(CFITSIO)g(in)m(ternally)i(calls)g(it)f(in)g
+(most)227 1723 y(situations.)95 1987 y Fe(int)47 b(fits_set_hdustruc)c
+(/)48 b(ffrdef)286 2100 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*status\))141
+b(\(DEPRECATED\))0 2439 y Ff(9.3)135 b(Sp)t(ecialized)46
+b(Header)g(Keyw)l(ord)f(Routines)0 2693 y Fd(9.3.1)112
+b(Header)38 b(Information)h(Routines)0 2906 y Fi(1)81
+b Fj(Reserv)m(e)29 b(space)g(in)e(the)i(CHU)f(for)g(MOREKEYS)f(more)h
+(header)g(k)m(eyw)m(ords.)41 b(This)27 b(routine)h(ma)m(y)h(b)s(e)f
+(called)227 3018 y(to)34 b(allo)s(cate)h(space)e(for)f(additional)i(k)m
+(eyw)m(ords)f(at)g(the)g(time)g(the)g(header)f(is)h(created)g(\(prior)g
+(to)g(writing)227 3131 y(an)m(y)h(data\).)51 b(CFITSIO)32
+b(can)i(dynamically)g(add)f(more)g(space)h(to)g(the)g(header)f(when)f
+(needed,)j(ho)m(w)m(ev)m(er)227 3244 y(it)c(is)g(more)f(e\016cien)m(t)i
+(to)f(preallo)s(cate)h(the)f(required)f(space)h(if)f(the)g(size)i(is)e
+(kno)m(wn)g(in)g(adv)-5 b(ance.)95 3509 y Fe(int)47 b(fits_set_hdrsize)
+d(/)j(ffhdef)286 3621 y(\(fitsfile)f(*fptr,)g(int)h(morekeys,)e(>)i
+(int)g(*status\))0 3886 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)f(the)h(header)g(\(not)h(coun)m(ting)g
+(the)f(END)g(k)m(eyw)m(ord\))h(and)e(the)h(curren)m(t)227
+3999 y(p)s(osition)34 b(in)g(the)g(header.)50 b(The)34
+b(p)s(osition)f(is)h(the)g(n)m(um)m(b)s(er)f(of)h(the)g(k)m(eyw)m(ord)g
+(record)f(that)i(will)f(b)s(e)f(read)227 4112 y(next)k(\(or)g(one)f
+(greater)i(than)e(the)h(p)s(osition)f(of)h(the)g(last)g(k)m(eyw)m(ord)g
+(that)g(w)m(as)g(read\).)59 b(A)37 b(v)-5 b(alue)36 b(of)h(1)g(is)227
+4224 y(returned)29 b(if)i(the)f(p)s(oin)m(ter)h(is)f(p)s(ositioned)h
+(at)g(the)f(b)s(eginning)g(of)g(the)h(header.)95 4489
+y Fe(int)47 b(fits_get_hdrpos)d(/)j(ffghps)286 4602 y(\(fitsfile)f
+(*fptr,)g(>)h(int)g(*keysexist,)e(int)i(*keynum,)e(int)i(*status\))0
+4897 y Fd(9.3.2)112 b(Read)38 b(and)h(W)-9 b(rite)36
+b(the)h(Required)h(Keyw)m(ords)0 5110 y Fi(1)81 b Fj(W)-8
+b(rite)34 b(the)f(required)g(extension)h(header)e(k)m(eyw)m(ords)i(in)m
+(to)g(the)f(CHU.)h(These)f(routines)g(are)g(not)g(required,)227
+5223 y(and)g(instead)g(the)g(appropriate)g(header)g(ma)m(y)g(b)s(e)g
+(constructed)g(b)m(y)g(writing)g(eac)m(h)h(individual)e(k)m(eyw)m(ord)
+227 5336 y(in)e(the)h(prop)s(er)e(sequence.)227 5488
+y(The)21 b(simpler)g(\014ts)p 842 5488 28 4 v 33 w(write)p
+1077 5488 V 33 w(imghdr)f(routine)i(is)f(equiv)-5 b(alen)m(t)23
+b(to)f(calling)h(\014ts)p 2727 5488 V 32 w(write)p 2961
+5488 V 33 w(grphdr)d(with)h(the)h(default)227 5601 y(v)-5
+b(alues)37 b(of)f(simple)g(=)g(TR)m(UE,)g(p)s(coun)m(t)g(=)g(0,)i
+(gcoun)m(t)f(=)f(1,)i(and)e(extend)g(=)f(TR)m(UE.)i(The)e(PCOUNT,)227
+5714 y(GCOUNT)43 b(and)g(EXTEND)g(k)m(eyw)m(ords)g(are)h(not)f
+(required)f(in)h(the)h(primary)e(header)h(and)f(are)i(only)p
+eop end
+%%Page: 98 106
+TeXDict begin 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)227 555 y Fj(written)38 b(if)f(p)s(coun)m(t)g(is)g(not)h
+(equal)f(to)i(zero,)h(gcoun)m(t)e(is)f(not)h(equal)g(to)g(zero)g(or)f
+(one,)j(and)c(if)i(extend)f(is)227 668 y(TR)m(UE,)k(resp)s(ectiv)m(ely)
+-8 b(.)74 b(When)41 b(writing)g(to)h(an)e(IMA)m(GE)i(extension,)i(the)e
+(SIMPLE)e(and)g(EXTEND)227 781 y(parameters)c(are)f(ignored.)56
+b(It)35 b(is)g(recommended)g(that)h(\014ts)p 2342 781
+28 4 v 32 w(create)p 2610 781 V 35 w(image)g(or)f(\014ts)p
+3150 781 V 33 w(create)p 3419 781 V 34 w(tbl)g(b)s(e)g(used)227
+894 y(instead)26 b(of)f(these)h(routines)g(to)g(write)f(the)h(required)
+e(header)i(k)m(eyw)m(ords.)39 b(The)25 b(general)h(\014ts)p
+3377 894 V 33 w(write)p 3612 894 V 33 w(exthdr)227 1007
+y(routine)31 b(ma)m(y)g(b)s(e)e(used)h(to)h(write)g(the)f(header)g(of)h
+(an)m(y)g(conforming)f(FITS)g(extension.)95 1252 y Fe(int)47
+b(fits_write_imghdr)c(/)48 b(ffphps)286 1365 y(\(fitsfile)e(*fptr,)g
+(int)h(bitpix,)e(int)i(naxis,)f(long)h(*naxes,)f(>)h(int)g(*status\))95
+1591 y(int)g(fits_write_imghdrll)c(/)k(ffphpsll)286 1704
+y(\(fitsfile)f(*fptr,)g(int)h(bitpix,)e(int)i(naxis,)f(LONGLONG)g
+(*naxes,)g(>)h(int)g(*status\))95 1930 y(int)g(fits_write_grphdr)c(/)48
+b(ffphpr)286 2042 y(\(fitsfile)e(*fptr,)g(int)h(simple,)e(int)i
+(bitpix,)f(int)h(naxis,)f(long)h(*naxes,)334 2155 y(LONGLONG)f(pcount,)
+f(LONGLONG)h(gcount,)g(int)h(extend,)f(>)h(int)g(*status\))95
+2381 y(int)g(fits_write_grphdrll)c(/)k(ffphprll)286 2494
+y(\(fitsfile)f(*fptr,)g(int)h(simple,)e(int)i(bitpix,)f(int)h(naxis,)f
+(LONGLONG)g(*naxes,)334 2607 y(LONGLONG)g(pcount,)f(LONGLONG)h(gcount,)
+g(int)h(extend,)f(>)h(int)g(*status\))95 2833 y(int)g
+(fits_write_exthdr)c(/ffphext)286 2946 y(\(fitsfile)j(*fptr,)g(char)g
+(*xtension,)f(int)i(bitpix,)f(int)h(naxis,)f(long)h(*naxes,)334
+3059 y(LONGLONG)f(pcount,)f(LONGLONG)h(gcount,)g(>)h(int)g(*status\))0
+3417 y Fi(2)81 b Fj(W)-8 b(rite)30 b(the)g(ASCI)s(I)d(table)k(header)e
+(k)m(eyw)m(ords)g(in)m(to)i(the)e(CHU.)h(The)e(optional)j(TUNITn)d(and)
+h(EXTNAME)227 3530 y(k)m(eyw)m(ords)f(are)h(written)e(only)h(if)g(the)g
+(input)f(p)s(oin)m(ters)h(are)g(not)g(n)m(ull.)40 b(A)27
+b(n)m(ull)h(p)s(oin)m(ter)g(ma)m(y)g(giv)m(en)h(for)f(the)227
+3643 y(*tb)s(col)37 b(parameter)g(in)f(whic)m(h)g(case)i(a)e(single)h
+(space)g(will)g(b)s(e)f(inserted)g(b)s(et)m(w)m(een)h(eac)m(h)g(column)
+f(of)h(the)227 3756 y(table.)57 b(Similarly)-8 b(,)37
+b(if)f(ro)m(wlen)f(is)h(giv)m(en)g(=)f(0,)i(then)e(CFITSIO)f(will)i
+(calculate)h(the)f(default)f(ro)m(wlength)227 3868 y(based)30
+b(on)h(the)f(tb)s(col)h(and)f(tt)m(yp)s(e)h(v)-5 b(alues.)95
+4114 y Fe(int)47 b(fits_write_atblhdr)c(/)48 b(ffphtb)286
+4227 y(\(fitsfile)e(*fptr,)g(LONGLONG)f(rowlen,)h(LONGLONG)g(nrows,)g
+(int)h(tfields,)e(char)i(**ttype,)334 4340 y(long)g(*tbcol,)f(char)g
+(**tform,)g(char)g(**tunit,)g(char)h(*extname,)e(>)i(int)g(*status\))0
+4585 y Fi(3)81 b Fj(W)-8 b(rite)30 b(the)f(binary)g(table)h(header)e(k)
+m(eyw)m(ords)i(in)m(to)g(the)f(CHU.)g(The)g(optional)h(TUNITn)e(and)h
+(EXTNAME)227 4698 y(k)m(eyw)m(ords)35 b(are)g(written)g(only)g(if)f
+(the)h(input)f(p)s(oin)m(ters)g(are)h(not)g(n)m(ull.)53
+b(The)35 b(p)s(coun)m(t)f(parameter,)i(whic)m(h)227 4811
+y(sp)s(eci\014es)h(the)g(size)g(of)g(the)g(v)-5 b(ariable)38
+b(length)f(arra)m(y)g(heap,)h(should)e(initially)i(=)f(0;)j(CFITSIO)c
+(will)h(au-)227 4924 y(tomatically)d(up)s(date)d(the)g(PCOUNT)f(k)m
+(eyw)m(ord)i(v)-5 b(alue)32 b(if)f(an)m(y)g(v)-5 b(ariable)32
+b(length)g(arra)m(y)g(data)g(is)f(written)227 5036 y(to)g(the)e(heap.)
+41 b(The)29 b(TF)m(ORM)g(k)m(eyw)m(ord)h(v)-5 b(alue)30
+b(for)g(v)-5 b(ariable)30 b(length)g(v)m(ector)h(columns)e(should)g(ha)
+m(v)m(e)i(the)227 5149 y(form)c('Pt\(len\)')j(or)d('1Pt\(len\)')j
+(where)d(`t')h(is)g(the)g(data)g(t)m(yp)s(e)g(co)s(de)f(letter)i
+(\(A,I,J,E,D,)g(etc.\))42 b(and)27 b(`len')h(is)227 5262
+y(an)g(in)m(teger)i(sp)s(ecifying)e(the)g(maxim)m(um)g(length)g(of)h
+(the)f(v)m(ectors)h(in)f(that)h(column)f(\(len)g(m)m(ust)g(b)s(e)g
+(greater)227 5375 y(than)36 b(or)g(equal)h(to)g(the)f(longest)i(v)m
+(ector)f(in)f(the)h(column\).)58 b(If)36 b(`len')g(is)h(not)f(sp)s
+(eci\014ed)g(when)f(the)h(table)227 5488 y(is)c(created)g(\(e.g.,)h
+(the)f(input)e(TF)m(ORMn)h(v)-5 b(alue)32 b(is)f(just)g('1Pt'\))i(then)
+e(CFITSIO)f(will)h(scan)h(the)f(column)227 5601 y(when)f(the)h(table)h
+(is)f(\014rst)f(closed)h(and)g(will)g(app)s(end)e(the)i(maxim)m(um)g
+(length)g(to)g(the)g(TF)m(ORM)g(k)m(eyw)m(ord)227 5714
+y(v)-5 b(alue.)41 b(Note)30 b(that)f(if)f(the)h(table)g(is)g(subsequen)
+m(tly)f(mo)s(di\014ed)f(to)j(increase)f(the)g(maxim)m(um)f(length)h(of)
+g(the)p eop end
+%%Page: 99 107
+TeXDict begin 99 106 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29
+b(HEADER)i(KEYW)m(ORD)g(R)m(OUTINES)1510 b Fj(99)227
+555 y(v)m(ectors)39 b(then)e(the)g(mo)s(difying)g(program)g(is)g(resp)s
+(onsible)g(for)g(also)h(up)s(dating)e(the)i(TF)m(ORM)f(k)m(eyw)m(ord)
+227 668 y(v)-5 b(alue.)95 935 y Fe(int)47 b(fits_write_btblhdr)c(/)48
+b(ffphbn)286 1048 y(\(fitsfile)e(*fptr,)g(LONGLONG)f(nrows,)h(int)h
+(tfields,)f(char)g(**ttype,)334 1161 y(char)h(**tform,)e(char)i
+(**tunit,)e(char)i(*extname,)e(LONGLONG)h(pcount,)g(>)h(int)g
+(*status\))0 1427 y Fi(4)81 b Fj(Read)30 b(the)h(required)e(k)m(eyw)m
+(ords)i(from)f(the)h(CHDU)f(\(image)j(or)d(table\).)42
+b(When)30 b(reading)h(from)f(an)g(IMA)m(GE)227 1540 y(extension)24
+b(the)g(SIMPLE)e(and)h(EXTEND)g(parameters)h(are)f(ignored.)39
+b(A)23 b(n)m(ull)g(p)s(oin)m(ter)h(ma)m(y)g(b)s(e)e(supplied)227
+1653 y(for)30 b(an)m(y)h(of)g(the)f(returned)f(parameters)i(that)g(are)
+g(not)f(needed.)95 1920 y Fe(int)47 b(fits_read_imghdr)d(/)j(ffghpr)286
+2033 y(\(fitsfile)f(*fptr,)g(int)h(maxdim,)e(>)j(int)f(*simple,)e(int)i
+(*bitpix,)f(int)h(*naxis,)334 2146 y(long)g(*naxes,)f(long)g(*pcount,)g
+(long)g(*gcount,)g(int)h(*extend,)e(int)i(*status\))95
+2372 y(int)g(fits_read_imghdrll)c(/)48 b(ffghprll)286
+2485 y(\(fitsfile)e(*fptr,)g(int)h(maxdim,)e(>)j(int)f(*simple,)e(int)i
+(*bitpix,)f(int)h(*naxis,)334 2598 y(LONGLONG)f(*naxes,)f(long)i
+(*pcount,)f(long)g(*gcount,)g(int)h(*extend,)e(int)i(*status\))95
+2823 y(int)g(fits_read_atblhdr)c(/)48 b(ffghtb)286 2936
+y(\(fitsfile)e(*fptr,int)f(maxdim,)h(>)h(long)g(*rowlen,)e(long)i
+(*nrows,)334 3049 y(int)g(*tfields,)e(char)i(**ttype,)e(LONGLONG)h
+(*tbcol,)g(char)g(**tform,)g(char)h(**tunit,)334 3162
+y(char)g(*extname,)93 b(int)47 b(*status\))95 3388 y(int)g
+(fits_read_atblhdrll)c(/)k(ffghtbll)286 3501 y(\(fitsfile)f(*fptr,int)f
+(maxdim,)h(>)h(LONGLONG)f(*rowlen,)f(LONGLONG)h(*nrows,)334
+3614 y(int)h(*tfields,)e(char)i(**ttype,)e(long)i(*tbcol,)f(char)h
+(**tform,)e(char)i(**tunit,)334 3727 y(char)g(*extname,)93
+b(int)47 b(*status\))95 3952 y(int)g(fits_read_btblhdr)c(/)48
+b(ffghbn)286 4065 y(\(fitsfile)e(*fptr,)g(int)h(maxdim,)e(>)j(long)f
+(*nrows,)e(int)i(*tfields,)334 4178 y(char)g(**ttype,)e(char)i
+(**tform,)e(char)i(**tunit,)f(char)g(*extname,)334 4291
+y(long)h(*pcount,)e(int)i(*status\))95 4517 y(int)g
+(fits_read_btblhdrll)c(/)k(ffghbnll)286 4630 y(\(fitsfile)f(*fptr,)g
+(int)h(maxdim,)e(>)j(LONGLONG)d(*nrows,)h(int)h(*tfields,)334
+4743 y(char)g(**ttype,)e(char)i(**tform,)e(char)i(**tunit,)f(char)g
+(*extname,)334 4856 y(long)h(*pcount,)e(int)i(*status\))0
+5155 y Fd(9.3.3)112 b(W)-9 b(rite)37 b(Keyw)m(ord)g(Routines)0
+5375 y Fj(These)32 b(routines)h(simply)f(app)s(end)f(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)g(a)f(k)m(eyw)m(ord)0 5488 y(with)d(the)g(same)h(name)f(already)h
+(exists.)41 b(In)28 b(general)i(it)g(is)f(preferable)g(to)h(use)f(the)h
+(\014ts)p 3009 5488 28 4 v 32 w(up)s(date)p 3317 5488
+V 32 w(k)m(ey)g(routine)f(to)0 5601 y(ensure)34 b(that)h(the)g(same)g
+(k)m(eyw)m(ord)g(is)f(not)h(written)g(more)g(than)f(once)h(to)h(the)e
+(header.)54 b(See)34 b(App)s(endix)f(B)i(for)0 5714 y(the)c
+(de\014nition)f(of)g(the)h(parameters)f(used)g(in)g(these)h(routines.)p
+eop end
+%%Page: 100 108
+TeXDict begin 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(1)81 b Fj(W)-8 b(rite)30 b(\(app)s(end\))f(a)g
+(new)g(k)m(eyw)m(ord)h(of)g(the)f(appropriate)g(data)h(t)m(yp)s(e)g(in)
+m(to)g(the)g(CHU.)f(A)h(n)m(ull)f(p)s(oin)m(ter)g(ma)m(y)227
+668 y(b)s(e)35 b(en)m(tered)h(for)f(the)h(commen)m(t)h(parameter,)g
+(whic)m(h)e(will)h(cause)g(the)g(commen)m(t)g(\014eld)f(of)h(the)f(k)m
+(eyw)m(ord)227 781 y(to)43 b(b)s(e)e(left)i(blank.)76
+b(The)41 b(\015t,)k(dbl,)f(cmp,)h(and)d(dblcmp)f(v)m(ersions)h(of)g
+(this)g(routine)g(ha)m(v)m(e)h(the)g(added)227 894 y(feature)33
+b(that)g(if)g(the)f('decimals')i(parameter)f(is)g(negativ)m(e,)i(then)d
+(the)h('G')g(displa)m(y)g(format)g(rather)f(then)227
+1007 y(the)i('E')f(format)h(will)f(b)s(e)g(used)f(when)g(constructing)i
+(the)g(k)m(eyw)m(ord)f(v)-5 b(alue,)35 b(taking)f(the)g(absolute)f(v)-5
+b(alue)227 1120 y(of)34 b('decimals')h(for)e(the)h(precision.)51
+b(This)33 b(will)h(suppress)d(trailing)k(zeros,)g(and)e(will)h(use)g(a)
+g(\014xed)f(format)227 1233 y(rather)e(than)f(an)g(exp)s(onen)m(tial)h
+(format,)g(dep)s(ending)e(on)h(the)h(magnitude)f(of)h(the)g(v)-5
+b(alue.)95 1478 y Fe(int)47 b(fits_write_key_str)c(/)48
+b(ffpkys)286 1591 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(char)g
+(*value,)g(char)h(*comment,)334 1704 y(>)h(int)e(*status\))95
+1930 y(int)h(fits_write_key_[log,)c(lng])j(/)95 b(ffpky[lj])286
+2042 y(\(fitsfile)46 b(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g
+(char)g(*comment,)334 2155 y(>)i(int)e(*status\))95 2381
+y(int)h(fits_write_key_[flt,)c(dbl,)j(fixflg,)g(fixdbl])g(/)h
+(ffpky[edfg])286 2494 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)
+g(numval,)g(int)h(decimals,)286 2607 y(char)g(*comment,)e(>)j(int)f
+(*status\))95 2833 y(int)g(fits_write_key_[cmp,)c(dblcmp,)i(fixcmp,)h
+(fixdblcmp])f(/)j(ffpk[yc,ym,fc,fm])286 2946 y(\(fitsfile)e(*fptr,)g
+(char)g(*keyname,)g(DTYPE)g(*numval,)g(int)g(decimals,)286
+3059 y(char)h(*comment,)e(>)j(int)f(*status\))0 3304
+y Fi(2)81 b Fj(W)-8 b(rite)30 b(\(app)s(end\))e(a)i(string)f(v)-5
+b(alued)29 b(k)m(eyw)m(ord)h(in)m(to)g(the)f(CHU)h(whic)m(h)e(ma)m(y)i
+(b)s(e)f(longer)h(than)e(68)i(c)m(haracters)227 3417
+y(in)43 b(length.)80 b(This)42 b(uses)h(the)g(Long)h(String)e(Keyw)m
+(ord)h(con)m(v)m(en)m(tion)j(that)d(is)h(describ)s(ed)e(in)h(the`Lo)s
+(cal)227 3530 y(FITS)38 b(Con)m(v)m(en)m(tions')i(section)g(in)f
+(Chapter)f(4.)66 b(Since)38 b(this)h(uses)f(a)h(non-standard)f(FITS)g
+(con)m(v)m(en)m(tion)227 3643 y(to)45 b(enco)s(de)f(the)g(long)h(k)m
+(eyw)m(ord)f(string,)k(programs)43 b(whic)m(h)h(use)g(this)g(routine)g
+(should)f(also)h(call)i(the)227 3756 y(\014ts)p 354 3756
+28 4 v 33 w(write)p 589 3756 V 33 w(k)m(ey)p 755 3756
+V 33 w(longw)m(arn)26 b(routine)f(to)h(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 3868
+y(\014le)43 b(that)h(this)e(con)m(v)m(en)m(tion)j(is)e(b)s(eing)f
+(used.)78 b(The)42 b(\014ts)p 2220 3868 V 32 w(write)p
+2454 3868 V 33 w(k)m(ey)p 2620 3868 V 34 w(longw)m(arn)h(routine)g
+(also)h(writes)f(a)227 3981 y(k)m(eyw)m(ord)29 b(called)g(LONGSTRN)e
+(to)i(record)f(the)g(v)m(ersion)h(of)f(the)g(longstring)h(con)m(v)m(en)
+m(tion)h(that)f(has)f(b)s(een)227 4094 y(used,)35 b(in)f(case)i(a)f
+(new)e(con)m(v)m(en)m(tion)k(is)e(adopted)f(at)h(some)g(p)s(oin)m(t)f
+(in)h(the)f(future.)52 b(If)34 b(the)h(LONGSTRN)227 4207
+y(k)m(eyw)m(ord)43 b(is)g(already)g(presen)m(t)g(in)g(the)f(header,)k
+(then)d(\014ts)p 2332 4207 V 32 w(write)p 2566 4207 V
+33 w(k)m(ey)p 2732 4207 V 34 w(longw)m(arn)g(will)g(simply)f(return)227
+4320 y(without)31 b(doing)f(an)m(ything.)95 4565 y Fe(int)47
+b(fits_write_key_longstr)42 b(/)48 b(ffpkls)286 4678
+y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(char)g(*longstr,)g(char)g
+(*comment,)334 4791 y(>)i(int)e(*status\))95 5017 y(int)h
+(fits_write_key_longwarn)42 b(/)47 b(ffplsw)286 5130
+y(\(fitsfile)f(*fptr,)g(>)h(int)g(*status\))0 5375 y
+Fi(3)81 b Fj(W)-8 b(rite)38 b(\(app)s(end\))d(a)i(n)m(um)m(b)s(ered)e
+(sequence)i(of)g(k)m(eyw)m(ords)g(in)m(to)g(the)g(CHU.)g(The)f
+(starting)h(index)f(n)m(um)m(b)s(er)227 5488 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 5601 y(eliminate)35 b(the)f(need)f(to)h(ha)m(v)m(e)g(an)f(arra)m(y)
+h(of)f(iden)m(tical)j(commen)m(t)e(strings,)g(one)f(for)h(eac)m(h)g(k)m
+(eyw)m(ord\))g(b)m(y)227 5714 y(including)24 b(the)h(amp)s(ersand)e(c)m
+(haracter)j(as)e(the)h(last)g(non-blank)f(c)m(haracter)i(in)e(the)g
+(\(\014rst\))h(COMMENTS)p eop end
+%%Page: 101 109
+TeXDict begin 101 108 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29
+b(HEADER)i(KEYW)m(ORD)g(R)m(OUTINES)1465 b Fj(101)227
+555 y(string)23 b(parameter.)38 b(This)22 b(same)h(string)f(will)h
+(then)f(b)s(e)g(used)f(for)h(the)h(commen)m(t)g(\014eld)f(in)g(all)i
+(the)e(k)m(eyw)m(ords.)227 668 y(One)32 b(ma)m(y)h(also)g(en)m(ter)f(a)
+h(n)m(ull)f(p)s(oin)m(ter)g(for)g(the)g(commen)m(t)h(parameter)g(to)f
+(lea)m(v)m(e)j(the)d(commen)m(t)h(\014eld)f(of)227 781
+y(the)f(k)m(eyw)m(ord)g(blank.)95 995 y Fe(int)47 b
+(fits_write_keys_str)c(/)k(ffpkns)286 1107 y(\(fitsfile)f(*fptr,)g
+(char)g(*keyroot,)g(int)h(nstart,)e(int)i(nkeys,)334
+1220 y(char)g(**value,)e(char)i(**comment,)e(>)i(int)g(*status\))95
+1446 y(int)g(fits_write_keys_[log,)42 b(lng])47 b(/)g(ffpkn[lj])286
+1559 y(\(fitsfile)f(*fptr,)g(char)g(*keyroot,)g(int)h(nstart,)e(int)i
+(nkeys,)334 1672 y(DTYPE)f(*numval,)g(char)h(**comment,)e(int)i
+(*status\))95 1898 y(int)g(fits_write_keys_[flt,)42 b(dbl,)47
+b(fixflg,)f(fixdbl])g(/)h(ffpkne[edfg])286 2011 y(\(fitsfile)f(*fptr,)g
+(char)g(*keyroot,)g(int)h(nstart,)e(int)i(nkey,)334 2124
+y(DTYPE)f(*numval,)g(int)h(decimals,)e(char)i(**comment,)e(>)i(int)g
+(*status\))0 2337 y Fi(4)81 b Fj(Cop)m(y)21 b(an)h(indexed)f(k)m(eyw)m
+(ord)i(from)e(one)h(HDU)h(to)f(another,)i(mo)s(difying)e(the)g(index)f
+(n)m(um)m(b)s(er)f(of)i(the)g(k)m(eyw)m(ord)227 2450
+y(name)37 b(in)f(the)g(pro)s(cess.)58 b(F)-8 b(or)37
+b(example,)i(this)d(routine)h(could)f(read)g(the)h(TLMIN3)f(k)m(eyw)m
+(ord)h(from)f(the)227 2563 y(input)30 b(HDU)h(\(b)m(y)g(giving)h(k)m
+(eyro)s(ot)f(=)g(`TLMIN')g(and)f(inn)m(um)f(=)h(3\))i(and)e(write)h(it)
+g(to)g(the)g(output)f(HDU)227 2676 y(with)36 b(the)g(k)m(eyw)m(ord)h
+(name)f(TLMIN4)g(\(b)m(y)g(setting)i(outn)m(um)d(=)h(4\).)58
+b(If)36 b(the)g(input)f(k)m(eyw)m(ord)i(do)s(es)f(not)227
+2789 y(exist,)c(then)e(this)g(routine)g(simply)g(returns)f(without)i
+(indicating)g(an)f(error.)95 3002 y Fe(int)47 b(fits_copy_key)e(/)i
+(ffcpky)286 3115 y(\(fitsfile)f(*infptr,)f(fitsfile)h(*outfptr,)f(int)i
+(innum,)f(int)h(outnum,)334 3228 y(char)g(*keyroot,)e(>)i(int)g
+(*status\))0 3442 y Fi(5)81 b Fj(W)-8 b(rite)30 b(\(app)s(end\))f(a)h
+(`triple)f(precision')h(k)m(eyw)m(ord)g(in)m(to)g(the)g(CHU)f(in)g
+(F28.16)j(format.)41 b(The)29 b(\015oating)h(p)s(oin)m(t)227
+3555 y(k)m(eyw)m(ord)g(v)-5 b(alue)30 b(is)f(constructed)h(b)m(y)f
+(concatenating)j(the)d(input)g(in)m(teger)i(v)-5 b(alue)29
+b(with)g(the)h(input)e(double)227 3668 y(precision)35
+b(fraction)f(v)-5 b(alue)35 b(\(whic)m(h)f(m)m(ust)g(ha)m(v)m(e)i(a)e
+(v)-5 b(alue)35 b(b)s(et)m(w)m(een)f(0.0)i(and)d(1.0\).)53
+b(The)34 b(\013gkyt)h(routine)227 3781 y(should)d(b)s(e)h(used)f(to)i
+(read)f(this)g(k)m(eyw)m(ord)h(v)-5 b(alue,)35 b(b)s(ecause)e(the)g
+(other)h(k)m(eyw)m(ord)f(reading)h(routines)f(will)227
+3893 y(not)e(preserv)m(e)f(the)h(full)f(precision)h(of)f(the)h(v)-5
+b(alue.)95 4107 y Fe(int)47 b(fits_write_key_triple)42
+b(/)48 b(ffpkyt)286 4220 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g
+(long)g(intval,)g(double)g(frac,)334 4333 y(char)h(*comment,)e(>)i(int)
+g(*status\))0 4546 y Fi(6)81 b Fj(W)-8 b(rite)37 b(k)m(eyw)m(ords)f(to)
+h(the)f(CHDU)g(that)h(are)f(de\014ned)f(in)h(an)g(ASCI)s(I)e(template)j
+(\014le.)58 b(The)35 b(format)i(of)f(the)227 4659 y(template)c(\014le)f
+(is)f(describ)s(ed)f(under)g(the)i(\014ts)p 1788 4659
+28 4 v 32 w(parse)p 2028 4659 V 33 w(template)g(routine.)95
+4873 y Fe(int)47 b(fits_write_key_template)42 b(/)47
+b(ffpktp)286 4986 y(\(fitsfile)f(*fptr,)g(const)g(char)h(*filename,)e
+(>)i(int)g(*status\))0 5269 y Fd(9.3.4)112 b(Insert)38
+b(Keyw)m(ord)f(Routines)0 5488 y Fj(These)42 b(insert)h(routines)f(are)
+h(somewhat)g(less)f(e\016cien)m(t)i(than)f(the)f(`up)s(date')g(or)h
+(`write')g(k)m(eyw)m(ord)g(routines)0 5601 y(b)s(ecause)30
+b(the)g(follo)m(wing)i(k)m(eyw)m(ords)e(in)g(the)g(header)g(m)m(ust)g
+(b)s(e)f(shifted)h(do)m(wn)f(to)i(mak)m(e)g(ro)s(om)f(for)g(the)g
+(inserted)0 5714 y(k)m(eyw)m(ord.)41 b(See)31 b(App)s(endix)d(B)j(for)f
+(the)h(de\014nition)f(of)g(the)h(parameters)g(used)e(in)h(these)h
+(routines.)p eop end
+%%Page: 102 110
+TeXDict begin 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(1)81 b Fj(Insert)26 b(a)h(new)f(k)m(eyw)m(ord)
+h(record)g(in)m(to)g(the)g(CHU)g(at)g(the)g(sp)s(eci\014ed)f(p)s
+(osition)h(\(i.e.,)i(immediately)f(preceding)227 668
+y(the)j(\(k)m(eyn)m(um\)th)g(k)m(eyw)m(ord)g(in)f(the)g(header.\))95
+921 y Fe(int)47 b(fits_insert_record)c(/)48 b(ffirec)286
+1034 y(\(fitsfile)e(*fptr,)g(int)h(keynum,)e(char)i(*card,)f(>)i(int)f
+(*status\))0 1286 y Fi(2)81 b Fj(Insert)24 b(a)h(new)g(k)m(eyw)m(ord)g
+(in)m(to)h(the)f(CHU.)g(The)g(new)f(k)m(eyw)m(ord)i(is)f(inserted)f
+(immediately)j(follo)m(wing)f(the)f(last)227 1399 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')i(v)m(ersion)f(has)f(the)h(same)g(functionalit)m
+(y)227 1512 y(as)33 b(the)g(`str')f(v)m(ersion)h(except)h(that)f(it)g
+(also)g(supp)s(orts)e(the)h(lo)s(cal)i(long)f(string)g(k)m(eyw)m(ord)g
+(con)m(v)m(en)m(tion)h(for)227 1625 y(strings)29 b(longer)g(than)g(68)h
+(c)m(haracters.)41 b(A)29 b(n)m(ull)g(p)s(oin)m(ter)g(ma)m(y)g(b)s(e)g
+(en)m(tered)g(for)g(the)g(commen)m(t)g(parameter)227
+1738 y(whic)m(h)d(will)f(cause)h(the)g(commen)m(t)h(\014eld)e(to)h(b)s
+(e)f(left)h(blank.)39 b(The)25 b(\015t,)h(dbl,)g(cmp,)h(and)e(dblcmp)f
+(v)m(ersions)i(of)227 1851 y(this)k(routine)g(ha)m(v)m(e)h(the)e(added)
+g(feature)i(that)f(if)g(the)g('decimals')h(parameter)f(is)g(negativ)m
+(e,)i(then)d(the)h('G')227 1964 y(displa)m(y)g(format)g(rather)f(then)g
+(the)h('E')f(format)h(will)g(b)s(e)f(used)f(when)h(constructing)h(the)f
+(k)m(eyw)m(ord)h(v)-5 b(alue,)227 2077 y(taking)27 b(the)g(absolute)g
+(v)-5 b(alue)26 b(of)h('decimals')g(for)f(the)h(precision.)39
+b(This)26 b(will)g(suppress)e(trailing)k(zeros,)g(and)227
+2189 y(will)37 b(use)g(a)g(\014xed)f(format)h(rather)g(than)f(an)h(exp)
+s(onen)m(tial)g(format,)i(dep)s(ending)c(on)i(the)g(magnitude)g(of)227
+2302 y(the)31 b(v)-5 b(alue.)95 2555 y Fe(int)47 b(fits_insert_card)d
+(/)j(ffikey)286 2668 y(\(fitsfile)f(*fptr,)g(char)g(*card,)g(>)i(int)f
+(*status\))95 2894 y(int)g(fits_insert_key_[str,)42 b(longstr])k(/)h
+(ffi[kys,)f(kls])286 3007 y(\(fitsfile)g(*fptr,)g(char)g(*keyname,)g
+(char)g(*value,)g(char)h(*comment,)334 3120 y(>)h(int)e(*status\))95
+3345 y(int)h(fits_insert_key_[log,)42 b(lng])47 b(/)g(ffiky[lj])286
+3458 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g(char)
+g(*comment,)334 3571 y(>)i(int)e(*status\))95 3797 y(int)h
+(fits_insert_key_[flt,)42 b(fixflt,)k(dbl,)h(fixdbl])f(/)h(ffiky[edfg])
+286 3910 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g
+(int)h(decimals,)334 4023 y(char)g(*comment,)e(>)i(int)g(*status\))95
+4249 y(int)g(fits_insert_key_[cmp,)42 b(dblcmp,)k(fixcmp,)g(fixdblcmp])
+f(/)i(ffik[yc,ym,fc,fm])286 4362 y(\(fitsfile)f(*fptr,)g(char)g
+(*keyname,)g(DTYPE)g(*numval,)g(int)g(decimals,)334 4474
+y(char)h(*comment,)e(>)i(int)g(*status\))0 4727 y Fi(3)81
+b Fj(Insert)32 b(a)i(new)f(k)m(eyw)m(ord)h(with)f(an)h(unde\014ned,)e
+(or)h(n)m(ull,)h(v)-5 b(alue)34 b(in)m(to)h(the)e(CHU.)h(The)f(v)-5
+b(alue)34 b(string)f(of)h(the)227 4840 y(k)m(eyw)m(ord)d(is)g(left)g
+(blank)f(in)g(this)g(case.)95 5093 y Fe(int)47 b(fits_insert_key_null)c
+(/)k(ffikyu)286 5205 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g
+(*comment,)g(>)h(int)g(*status\))0 5495 y Fd(9.3.5)112
+b(Read)38 b(Keyw)m(ord)g(Routines)0 5714 y Fj(Wild)31
+b(card)f(c)m(haracters)i(ma)m(y)f(b)s(e)f(used)f(when)h(sp)s(ecifying)g
+(the)g(name)h(of)f(the)h(k)m(eyw)m(ord)g(to)g(b)s(e)f(read.)p
+eop end
+%%Page: 103 111
+TeXDict begin 103 110 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29
+b(HEADER)i(KEYW)m(ORD)g(R)m(OUTINES)1465 b Fj(103)0 555
+y Fi(1)81 b Fj(Read)43 b(a)h(k)m(eyw)m(ord)g(v)-5 b(alue)43
+b(\(with)h(the)f(appropriate)h(data)g(t)m(yp)s(e\))g(and)e(commen)m(t)j
+(from)e(the)g(CHU.)h(If)f(a)227 668 y(NULL)32 b(commen)m(t)h(p)s(oin)m
+(ter)f(is)h(giv)m(en)g(on)f(input,)f(then)h(the)g(commen)m(t)i(string)e
+(will)g(not)g(b)s(e)g(returned.)44 b(If)227 781 y(the)32
+b(v)-5 b(alue)33 b(of)f(the)g(k)m(eyw)m(ord)g(is)g(not)h(de\014ned)d
+(\(i.e.,)k(the)e(v)-5 b(alue)33 b(\014eld)e(is)h(blank\))g(then)g(an)g
+(error)f(status)h(=)227 894 y(V)-10 b(ALUE)p 545 894
+28 4 v 33 w(UNDEFINED)29 b(will)f(b)s(e)g(returned)e(and)h(the)h(input)
+f(v)-5 b(alue)28 b(will)h(not)f(b)s(e)f(c)m(hanged)h(\(except)h(that)
+227 1007 y(\013gkys)i(will)g(reset)g(the)f(v)-5 b(alue)31
+b(to)g(a)g(n)m(ull)f(string\).)95 1252 y Fe(int)47 b(fits_read_key_str)
+c(/)48 b(ffgkys)286 1365 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h
+(char)g(*value,)f(char)g(*comment,)334 1478 y(int)h(*status\);)95
+1704 y(NOTE:)g(after)f(calling)g(the)h(following)e(routine,)h(programs)
+f(must)i(explicitly)e(free)382 1817 y(the)i(memory)f(allocated)f(for)i
+('longstr')e(after)i(it)g(is)g(no)g(longer)f(needed)g(or)382
+1930 y(call)g(fits_free_memory.)95 2155 y(int)h(fits_read_key_longstr)
+42 b(/)48 b(ffgkls)286 2268 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g
+(>)h(char)g(**longstr,)e(char)h(*comment,)620 2381 y(int)h(*status\))95
+2607 y(int)g(fits_free_memory)d(/)j(fffree)286 2720 y(\(char)g
+(*longstr,)e(int)i(*status\);)95 2946 y(int)g(fits_read_key_[log,)c
+(lng,)k(flt,)f(dbl,)h(cmp,)f(dblcmp])g(/)i(ffgky[ljedcm])286
+3059 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(>)h(DTYPE)f(*numval,)g
+(char)h(*comment,)334 3172 y(int)g(*status\))95 3397
+y(int)g(fits_read_key_lnglng)c(/)k(ffgkyjj)286 3510 y(\(fitsfile)f
+(*fptr,)g(char)g(*keyname,)g(>)h(LONGLONG)f(*numval,)f(char)i
+(*comment,)334 3623 y(int)g(*status\))0 3868 y Fi(2)81
+b Fj(Read)36 b(a)h(sequence)f(of)h(indexed)e(k)m(eyw)m(ord)i(v)-5
+b(alues)37 b(\(e.g.,)i(NAXIS1,)g(NAXIS2,)f(...\).)59
+b(The)36 b(input)f(starting)227 3981 y(index)j(n)m(um)m(b)s(er)e
+(\(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)38 b(of)g(an)m(y)h(of)f(the)g(k)m(eyw)m
+(ords)g(is)g(not)227 4094 y(de\014ned)c(\(i.e.,)j(the)e(v)-5
+b(alue)35 b(\014eld)f(is)h(blank\))g(then)f(an)g(error)h(status)g(=)f
+(V)-10 b(ALUE)p 3009 4094 V 33 w(UNDEFINED)36 b(will)f(b)s(e)227
+4207 y(returned)21 b(and)h(the)h(input)e(v)-5 b(alue)23
+b(for)f(the)g(unde\014ned)e(k)m(eyw)m(ord\(s\))k(will)e(not)h(b)s(e)e
+(c)m(hanged.)39 b(These)22 b(routines)227 4320 y(do)j(not)h(supp)s(ort)
+d(wild)i(card)h(c)m(haracters)g(in)f(the)h(ro)s(ot)f(name.)39
+b(If)25 b(there)h(are)f(no)g(indexed)g(k)m(eyw)m(ords)h(in)f(the)227
+4433 y(header)35 b(with)f(the)h(input)e(ro)s(ot)i(name)g(then)f(these)h
+(routines)g(do)f(not)h(return)e(a)i(non-zero)h(status)e(v)-5
+b(alue)227 4546 y(and)30 b(instead)h(simply)f(return)f(nfound)f(=)i(0.)
+95 4791 y Fe(int)47 b(fits_read_keys_str)c(/)48 b(ffgkns)286
+4904 y(\(fitsfile)e(*fptr,)g(char)g(*keyname,)g(int)h(nstart,)e(int)i
+(nkeys,)334 5017 y(>)h(char)e(**value,)g(int)h(*nfound,)93
+b(int)47 b(*status\))95 5243 y(int)g(fits_read_keys_[log,)c(lng,)j
+(flt,)h(dbl])g(/)g(ffgkn[ljed])286 5356 y(\(fitsfile)f(*fptr,)g(char)g
+(*keyname,)g(int)h(nstart,)e(int)i(nkeys,)334 5469 y(>)h(DTYPE)e
+(*numval,)f(int)i(*nfound,)f(int)h(*status\))0 5714 y
+Fi(3)81 b Fj(Read)37 b(the)h(v)-5 b(alue)38 b(of)g(a)g(\015oating)g(p)s
+(oin)m(t)g(k)m(eyw)m(ord,)i(returning)d(the)h(in)m(teger)h(and)e
+(fractional)i(parts)e(of)h(the)p eop end
+%%Page: 104 112
+TeXDict begin 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)227 555 y Fj(v)-5 b(alue)35 b(in)e(separate)i(routine)f
+(argumen)m(ts.)52 b(This)33 b(routine)h(ma)m(y)g(b)s(e)f(used)h(to)g
+(read)g(an)m(y)g(k)m(eyw)m(ord)h(but)e(is)227 668 y(esp)s(ecially)f
+(useful)d(for)i(reading)f(the)h('triple)g(precision')f(k)m(eyw)m(ords)h
+(written)g(b)m(y)f(\013pkyt.)95 929 y Fe(int)47 b(fits_read_key_triple)
+c(/)k(ffgkyt)286 1042 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(>)h
+(long)g(*intval,)e(double)h(*frac,)334 1155 y(char)h(*comment,)e(int)i
+(*status\))0 1446 y Fd(9.3.6)112 b(Mo)s(dify)39 b(Keyw)m(ord)e
+(Routines)0 1666 y Fj(These)31 b(routines)h(mo)s(dify)f(the)h(v)-5
+b(alue)32 b(of)g(an)g(existing)g(k)m(eyw)m(ord.)46 b(An)31
+b(error)g(is)h(returned)e(if)i(the)g(k)m(eyw)m(ord)g(do)s(es)0
+1778 y(not)43 b(exist.)77 b(Wild)43 b(card)g(c)m(haracters)h(ma)m(y)f
+(b)s(e)f(used)f(when)h(sp)s(ecifying)g(the)h(name)f(of)h(the)f(k)m(eyw)
+m(ord)h(to)h(b)s(e)0 1891 y(mo)s(di\014ed.)c(See)30 b(App)s(endix)f(B)i
+(for)f(the)g(de\014nition)g(of)h(the)f(parameters)h(used)f(in)g(these)h
+(routines.)0 2152 y Fi(1)81 b Fj(Mo)s(dify)30 b(\(o)m(v)m(erwrite\))i
+(the)f(n)m(th)f(80-c)m(haracter)j(header)d(record)h(in)f(the)g(CHU.)95
+2413 y Fe(int)47 b(fits_modify_record)c(/)48 b(ffmrec)286
+2526 y(\(fitsfile)e(*fptr,)g(int)h(keynum,)e(char)i(*card,)f(>)i(int)f
+(*status\))0 2786 y Fi(2)81 b Fj(Mo)s(dify)37 b(\(o)m(v)m(erwrite\))j
+(the)e(80-c)m(haracter)j(header)c(record)h(for)f(the)h(named)f(k)m(eyw)
+m(ord)h(in)g(the)g(CHU.)g(This)227 2899 y(can)31 b(b)s(e)f(used)f(to)i
+(o)m(v)m(erwrite)h(the)f(name)f(of)h(the)f(k)m(eyw)m(ord)h(as)g(w)m
+(ell)g(as)g(its)g(v)-5 b(alue)30 b(and)g(commen)m(t)i(\014elds.)95
+3160 y Fe(int)47 b(fits_modify_card)d(/)j(ffmcrd)286
+3273 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*card,)g(>)i
+(int)f(*status\))0 3534 y Fi(5)81 b Fj(Mo)s(dify)30 b(the)g(v)-5
+b(alue)31 b(and)e(commen)m(t)i(\014elds)f(of)g(an)g(existing)h(k)m(eyw)
+m(ord)g(in)f(the)g(CHU.)h(The)e(`longstr')i(v)m(ersion)227
+3647 y(has)41 b(the)h(same)f(functionalit)m(y)i(as)e(the)h(`str')f(v)m
+(ersion)h(except)g(that)g(it)g(also)g(supp)s(orts)d(the)j(lo)s(cal)g
+(long)227 3760 y(string)29 b(k)m(eyw)m(ord)h(con)m(v)m(en)m(tion)h(for)
+e(strings)f(longer)i(than)f(68)h(c)m(haracters.)41 b(Optionally)-8
+b(,)31 b(one)e(ma)m(y)h(mo)s(dify)227 3872 y(only)e(the)g(v)-5
+b(alue)28 b(\014eld)g(and)f(lea)m(v)m(e)j(the)e(commen)m(t)h(\014eld)e
+(unc)m(hanged)h(b)m(y)g(setting)g(the)g(input)f(COMMENT)227
+3985 y(parameter)c(equal)h(to)f(the)g(amp)s(ersand)e(c)m(haracter)j
+(\(&\))f(or)g(b)m(y)g(en)m(tering)g(a)g(n)m(ull)g(p)s(oin)m(ter)g(for)f
+(the)h(commen)m(t)227 4098 y(parameter.)40 b(The)24 b(\015t,)i(dbl,)g
+(cmp,)f(and)g(dblcmp)e(v)m(ersions)j(of)f(this)g(routine)g(ha)m(v)m(e)h
+(the)f(added)f(feature)h(that)227 4211 y(if)h(the)h('decimals')g
+(parameter)g(is)f(negativ)m(e,)k(then)c(the)g('G')h(displa)m(y)f
+(format)h(rather)f(then)g(the)g('E')h(format)227 4324
+y(will)i(b)s(e)f(used)f(when)h(constructing)h(the)f(k)m(eyw)m(ord)h(v)
+-5 b(alue,)30 b(taking)f(the)g(absolute)g(v)-5 b(alue)29
+b(of)f('decimals')i(for)227 4437 y(the)37 b(precision.)60
+b(This)35 b(will)i(suppress)e(trailing)i(zeros,)i(and)d(will)h(use)g(a)
+g(\014xed)e(format)i(rather)g(than)f(an)227 4550 y(exp)s(onen)m(tial)c
+(format,)f(dep)s(ending)d(on)j(the)f(magnitude)h(of)f(the)h(v)-5
+b(alue.)95 4811 y Fe(int)47 b(fits_modify_key_[str,)42
+b(longstr])k(/)h(ffm[kys,)f(kls])286 4924 y(\(fitsfile)g(*fptr,)g(char)
+g(*keyname,)g(char)g(*value,)g(char)h(*comment,)334 5036
+y(>)h(int)e(*status\);)95 5262 y(int)h(fits_modify_key_[log,)42
+b(lng])47 b(/)g(ffmky[lj])286 5375 y(\(fitsfile)f(*fptr,)g(char)g
+(*keyname,)g(DTYPE)g(numval,)g(char)g(*comment,)334 5488
+y(>)i(int)e(*status\))95 5714 y(int)h(fits_modify_key_[flt,)42
+b(dbl,)47 b(fixflt,)f(fixdbl])g(/)h(ffmky[edfg])p eop
+end
+%%Page: 105 113
+TeXDict begin 105 112 bop 0 299 a Fh(9.3.)72 b(SPECIALIZED)29
+b(HEADER)i(KEYW)m(ORD)g(R)m(OUTINES)1465 b Fj(105)286
+555 y Fe(\(fitsfile)46 b(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g
+(int)h(decimals,)334 668 y(char)g(*comment,)e(>)i(int)g(*status\))95
+894 y(int)g(fits_modify_key_[cmp,)42 b(dblcmp,)k(fixcmp,)g(fixdblcmp])f
+(/)i(ffmk[yc,ym,fc,fm])286 1007 y(\(fitsfile)f(*fptr,)g(char)g
+(*keyname,)g(DTYPE)g(*numval,)g(int)g(decimals,)334 1120
+y(char)h(*comment,)e(>)i(int)g(*status\))0 1431 y Fi(6)81
+b Fj(Mo)s(dify)22 b(the)g(v)-5 b(alue)23 b(of)f(an)g(existing)i(k)m
+(eyw)m(ord)e(to)h(b)s(e)f(unde\014ned,)g(or)g(n)m(ull.)38
+b(The)22 b(v)-5 b(alue)22 b(string)h(of)f(the)g(k)m(eyw)m(ord)227
+1544 y(is)30 b(set)h(to)g(blank.)40 b(Optionally)-8 b(,)31
+b(one)f(ma)m(y)h(lea)m(v)m(e)h(the)f(commen)m(t)g(\014eld)e(unc)m
+(hanged)h(b)m(y)g(setting)h(the)f(input)227 1657 y(COMMENT)f(parameter)
+g(equal)g(to)g(the)g(amp)s(ersand)e(c)m(haracter)k(\(&\))e(or)f(b)m(y)h
+(en)m(tering)g(a)g(n)m(ull)g(p)s(oin)m(ter.)95 1968 y
+Fe(int)47 b(fits_modify_key_null)c(/)k(ffmkyu)286 2081
+y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(char)g(*comment,)g(>)h(int)g
+(*status\))0 2433 y Fd(9.3.7)112 b(Up)s(date)39 b(Keyw)m(ord)e
+(Routines)0 2680 y Fi(1)81 b Fj(These)29 b(up)s(date)g(routines)h(mo)s
+(dify)f(the)g(v)-5 b(alue,)31 b(and)e(optionally)i(the)f(commen)m(t)h
+(\014eld,)f(of)g(the)g(k)m(eyw)m(ord)g(if)f(it)227 2793
+y(already)34 b(exists,)g(otherwise)f(the)g(new)f(k)m(eyw)m(ord)h(is)f
+(app)s(ended)f(to)j(the)f(header.)47 b(A)33 b(separate)g(routine)g(is)
+227 2906 y(pro)m(vided)c(for)g(eac)m(h)h(k)m(eyw)m(ord)f(data)h(t)m(yp)
+s(e.)41 b(The)28 b(`longstr')i(v)m(ersion)g(has)e(the)i(same)f
+(functionalit)m(y)h(as)g(the)227 3019 y(`str')h(v)m(ersion)g(except)h
+(that)g(it)f(also)h(supp)s(orts)c(the)j(lo)s(cal)h(long)g(string)e(k)m
+(eyw)m(ord)i(con)m(v)m(en)m(tion)h(for)d(strings)227
+3132 y(longer)i(than)f(68)h(c)m(haracters.)45 b(A)31
+b(n)m(ull)g(p)s(oin)m(ter)h(ma)m(y)f(b)s(e)g(en)m(tered)h(for)f(the)g
+(commen)m(t)i(parameter)e(whic)m(h)227 3245 y(will)i(lea)m(v)m(e)h(the)
+f(commen)m(t)g(\014eld)f(unc)m(hanged)g(or)g(blank.)46
+b(The)31 b(\015t,)i(dbl,)f(cmp,)h(and)e(dblcmp)g(v)m(ersions)i(of)227
+3357 y(this)d(routine)g(ha)m(v)m(e)h(the)e(added)g(feature)i(that)f(if)
+g(the)g('decimals')h(parameter)f(is)g(negativ)m(e,)i(then)d(the)h('G')
+227 3470 y(displa)m(y)g(format)g(rather)f(then)g(the)h('E')f(format)h
+(will)g(b)s(e)f(used)f(when)h(constructing)h(the)f(k)m(eyw)m(ord)h(v)-5
+b(alue,)227 3583 y(taking)27 b(the)g(absolute)g(v)-5
+b(alue)26 b(of)h('decimals')g(for)f(the)h(precision.)39
+b(This)26 b(will)g(suppress)e(trailing)k(zeros,)g(and)227
+3696 y(will)37 b(use)g(a)g(\014xed)f(format)h(rather)g(than)f(an)h(exp)
+s(onen)m(tial)g(format,)i(dep)s(ending)c(on)i(the)g(magnitude)g(of)227
+3809 y(the)31 b(v)-5 b(alue.)95 4121 y Fe(int)47 b
+(fits_update_key_[str,)42 b(longstr])k(/)h(ffu[kys,)f(kls])286
+4233 y(\(fitsfile)g(*fptr,)g(char)g(*keyname,)g(char)g(*value,)g(char)h
+(*comment,)334 4346 y(>)h(int)e(*status\))95 4572 y(int)h
+(fits_update_key_[log,)42 b(lng])47 b(/)g(ffuky[lj])286
+4685 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(numval,)g(char)
+g(*comment,)334 4798 y(>)i(int)e(*status\))95 5024 y(int)h
+(fits_update_key_[flt,)42 b(dbl,)47 b(fixflt,)f(fixdbl])g(/)h
+(ffuky[edfg])286 5137 y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)
+g(numval,)g(int)h(decimals,)334 5250 y(char)g(*comment,)e(>)i(int)g
+(*status\))95 5475 y(int)g(fits_update_key_[cmp,)42 b(dblcmp,)k
+(fixcmp,)g(fixdblcmp])f(/)i(ffuk[yc,ym,fc,fm])286 5588
+y(\(fitsfile)f(*fptr,)g(char)g(*keyname,)g(DTYPE)g(*numval,)g(int)g
+(decimals,)334 5701 y(char)h(*comment,)e(>)i(int)g(*status\))p
+eop end
+%%Page: 106 114
+TeXDict begin 106 113 bop 0 299 a Fj(106)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 Ff(9.4)135 b(De\014ne)45 b(Data)h(Scaling)g(and)e
+(Unde\014ned)h(Pixel)h(P)l(arameters)0 805 y Fj(These)37
+b(routines)g(set)h(or)f(mo)s(dify)g(the)g(in)m(ternal)h(parameters)g
+(used)e(b)m(y)i(CFITSIO)d(to)j(either)g(scale)h(the)e(data)0
+918 y(or)f(to)h(represen)m(t)f(unde\014ned)d(pixels.)58
+b(Generally)37 b(CFITSIO)d(will)j(scale)g(the)f(data)h(according)g(to)f
+(the)h(v)-5 b(alues)0 1031 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)f(ma)m(y)0 1144 y(b)s(e)e(used)h(to)h(o)m(v)m
+(erride)g(the)f(k)m(eyw)m(ord)h(v)-5 b(alues.)49 b(This)32
+b(ma)m(y)i(b)s(e)f(useful)f(when)g(one)i(w)m(an)m(ts)f(to)h(read)f(or)g
+(write)h(the)0 1257 y(ra)m(w)e(unscaled)g(v)-5 b(alues)33
+b(in)f(the)g(FITS)f(\014le.)47 b(Similarly)-8 b(,)33
+b(CFITSIO)e(generally)i(uses)f(the)g(v)-5 b(alue)33 b(of)f(the)h(BLANK)
+0 1370 y(or)40 b(TNULLn)f(k)m(eyw)m(ord)h(to)h(signify)e(an)h
+(unde\014ned)e(pixel,)43 b(but)c(these)h(routines)g(ma)m(y)g(b)s(e)f
+(used)g(to)i(o)m(v)m(erride)0 1483 y(this)32 b(v)-5 b(alue.)48
+b(These)32 b(routines)g(do)h(not)f(create)i(or)f(mo)s(dify)e(the)i
+(corresp)s(onding)e(header)i(k)m(eyw)m(ord)f(v)-5 b(alues.)48
+b(See)0 1596 y(App)s(endix)29 b(B)h(for)h(the)f(de\014nition)g(of)h
+(the)f(parameters)h(used)e(in)i(these)f(routines.)0 1827
+y Fi(1)81 b Fj(Reset)26 b(the)g(scaling)g(factors)g(in)f(the)h(primary)
+f(arra)m(y)h(or)f(image)i(extension;)h(do)s(es)d(not)g(c)m(hange)i(the)
+f(BSCALE)227 1940 y(and)i(BZER)m(O)g(k)m(eyw)m(ord)h(v)-5
+b(alues)28 b(and)g(only)g(a\013ects)i(the)e(automatic)j(scaling)e(p)s
+(erformed)e(when)g(the)h(data)227 2053 y(elemen)m(ts)f(are)f
+(written/read)g(to/from)g(the)g(FITS)f(\014le.)39 b(When)25
+b(reading)h(from)f(a)h(FITS)f(\014le)g(the)h(returned)227
+2166 y(data)i(v)-5 b(alue)28 b(=)f(\(the)h(v)-5 b(alue)28
+b(giv)m(en)h(in)e(the)g(FITS)g(arra)m(y\))h(*)g(BSCALE)f(+)g(BZER)m(O.)
+g(The)g(in)m(v)m(erse)i(form)m(ula)227 2279 y(is)i(used)e(when)h
+(writing)g(data)h(v)-5 b(alues)31 b(to)g(the)f(FITS)g(\014le.)95
+2511 y Fe(int)47 b(fits_set_bscale)d(/)j(ffpscl)286 2624
+y(\(fitsfile)f(*fptr,)g(double)g(scale,)g(double)g(zero,)g(>)i(int)f
+(*status\))0 2856 y Fi(2)81 b Fj(Reset)39 b(the)f(scaling)i(parameters)
+e(for)h(a)f(table)h(column;)k(do)s(es)38 b(not)g(c)m(hange)i(the)e
+(TSCALn)f(or)h(TZER)m(On)227 2968 y(k)m(eyw)m(ord)29
+b(v)-5 b(alues)29 b(and)e(only)i(a\013ects)g(the)g(automatic)h(scaling)
+f(p)s(erformed)e(when)g(the)i(data)g(elemen)m(ts)h(are)227
+3081 y(written/read)i(to/from)g(the)g(FITS)f(\014le.)44
+b(When)31 b(reading)g(from)g(a)h(FITS)f(\014le)g(the)h(returned)e(data)
+i(v)-5 b(alue)227 3194 y(=)25 b(\(the)i(v)-5 b(alue)26
+b(giv)m(en)g(in)f(the)h(FITS)f(arra)m(y\))h(*)g(TSCAL)e(+)i(TZER)m(O.)e
+(The)h(in)m(v)m(erse)i(form)m(ula)f(is)f(used)g(when)227
+3307 y(writing)31 b(data)g(v)-5 b(alues)30 b(to)i(the)e(FITS)g(\014le.)
+95 3539 y Fe(int)47 b(fits_set_tscale)d(/)j(fftscl)286
+3652 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(double)i(scale,)f(double)g
+(zero,)334 3765 y(>)i(int)e(*status\))0 3997 y Fi(3)81
+b Fj(De\014ne)36 b(the)g(in)m(teger)i(v)-5 b(alue)36
+b(to)h(b)s(e)e(used)h(to)h(signify)f(unde\014ned)e(pixels)i(in)g(the)g
+(primary)f(arra)m(y)i(or)f(image)227 4109 y(extension.)54
+b(This)34 b(is)g(only)h(used)f(if)g(BITPIX)g(=)h(8,)h(16,)g(or)f(32.)54
+b(This)34 b(do)s(es)g(not)h(create)h(or)e(c)m(hange)i(the)227
+4222 y(v)-5 b(alue)31 b(of)g(the)f(BLANK)h(k)m(eyw)m(ord)g(in)f(the)g
+(header.)95 4454 y Fe(int)47 b(fits_set_imgnull)d(/)j(ffpnul)286
+4567 y(\(fitsfile)f(*fptr,)g(LONGLONG)f(nulval,)h(>)i(int)e(*status\))0
+4799 y Fi(4)81 b Fj(De\014ne)36 b(the)g(string)g(to)g(b)s(e)f(used)g
+(to)i(signify)f(unde\014ned)e(pixels)i(in)f(a)h(column)g(in)g(an)f
+(ASCI)s(I)g(table.)58 b(This)227 4912 y(do)s(es)30 b(not)h(create)h(or)
+e(c)m(hange)i(the)e(v)-5 b(alue)31 b(of)g(the)f(TNULLn)g(k)m(eyw)m
+(ord.)95 5143 y Fe(int)47 b(fits_set_atblnull)c(/)48
+b(ffsnul)286 5256 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(char)i
+(*nulstr,)f(>)h(int)g(*status\))0 5488 y Fi(5)81 b Fj(De\014ne)34
+b(the)h(v)-5 b(alue)34 b(to)h(b)s(e)f(used)g(to)h(signify)f
+(unde\014ned)e(pixels)j(in)f(an)g(in)m(teger)i(column)e(in)g(a)g
+(binary)g(table)227 5601 y(\(where)29 b(TF)m(ORMn)f(=)g('B',)i('I',)f
+(or)f('J'\).)i(This)d(do)s(es)i(not)f(create)j(or)d(c)m(hange)i(the)e
+(v)-5 b(alue)29 b(of)g(the)g(TNULLn)227 5714 y(k)m(eyw)m(ord.)p
+eop end
+%%Page: 107 115
+TeXDict begin 107 114 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)80 b Fj(107)95 555 y Fe(int)47 b(fits_set_btblnull)
+c(/)48 b(fftnul)286 668 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e
+(LONGLONG)h(nulval,)g(>)h(int)g(*status\))0 995 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 1144 y(Routines)0 1394 y Fj(These)27
+b(routines)h(read)f(or)h(write)g(data)g(v)-5 b(alues)28
+b(in)g(the)f(primary)g(data)h(arra)m(y)h(\(i.e.,)g(the)f(\014rst)f(HDU)
+i(in)e(the)h(FITS)0 1507 y(\014le\))37 b(or)g(an)f(IMA)m(GE)h
+(extension.)60 b(Automatic)39 b(data)e(t)m(yp)s(e)g(con)m(v)m(ersion)g
+(is)g(p)s(erformed)e(for)h(if)h(the)g(data)g(t)m(yp)s(e)0
+1620 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)g(from)f(the)h(data)g(t)m(yp)s(e)
+g(of)g(the)g(arra)m(y)g(in)0 1733 y(the)c(calling)i(routine.)40
+b(The)28 b(data)i(v)-5 b(alues)29 b(are)h(automatically)i(scaled)d(b)m
+(y)g(the)h(BSCALE)e(and)g(BZER)m(O)h(header)0 1846 y(v)-5
+b(alues)25 b(as)h(they)f(are)g(b)s(eing)g(written)g(or)g(read)f(from)h
+(the)g(FITS)f(arra)m(y)-8 b(.)40 b(Unlik)m(e)26 b(the)f(basic)h
+(routines)e(describ)s(ed)g(in)0 1959 y(the)31 b(previous)g(c)m(hapter,)
+i(most)e(of)h(these)g(routines)f(sp)s(eci\014cally)h(supp)s(ort)d(the)j
+(FITS)e(random)h(groups)f(format.)0 2072 y(See)h(App)s(endix)d(B)j(for)
+f(the)h(de\014nition)f(of)g(the)h(parameters)g(used)e(in)h(these)h
+(routines.)0 2232 y(The)24 b(more)h(primitiv)m(e)h(reading)f(and)f
+(writing)h(routines)f(\(i.)40 b(e.,)26 b(\013ppr)p 2364
+2232 28 4 v 32 w(,)g(\013ppn)p 2653 2232 V 31 w(,)g(\013ppn,)f(\013gp)m
+(v)p 3185 2232 V 33 w(,)h(or)f(\013gpf)p 3552 2232 V
+32 w(\))g(simply)0 2345 y(treat)g(the)g(primary)e(arra)m(y)i(as)f(a)h
+(long)g(1-dimensional)g(arra)m(y)g(of)f(pixels,)i(ignoring)f(the)f(in)m
+(trinsic)h(dimensionalit)m(y)0 2458 y(of)30 b(the)g(arra)m(y)-8
+b(.)42 b(When)30 b(dealing)h(with)e(a)i(2D)g(image,)g(for)f(example,)h
+(the)f(application)i(program)e(m)m(ust)g(calculate)0
+2571 y(the)i(pixel)g(o\013set)g(in)f(the)h(1-D)h(arra)m(y)f(that)g
+(corresp)s(onds)e(to)i(an)m(y)g(particular)g(X,)g(Y)f(co)s(ordinate)i
+(in)e(the)g(image.)0 2684 y(C)25 b(programmers)h(should)f(note)h(that)g
+(the)h(ordering)e(of)h(arra)m(ys)g(in)g(FITS)f(\014les,)i(and)e(hence)h
+(in)g(all)g(the)g(CFITSIO)0 2797 y(calls,)40 b(is)d(more)g(similar)h
+(to)f(the)h(dimensionalit)m(y)g(of)f(arra)m(ys)g(in)g(F)-8
+b(ortran)38 b(rather)f(than)f(C.)h(F)-8 b(or)38 b(instance)g(if)f(a)0
+2910 y(FITS)28 b(image)i(has)e(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)i(enough)e(to)i(hold)e
+(the)0 3022 y(image)k(should)d(b)s(e)h(declared)h(as)f(arra)m
+(y[50][100])k(and)c(not)h(as)f(arra)m(y[100][50].)0 3183
+y(F)-8 b(or)30 b(con)m(v)m(enience,)i(higher-lev)m(el)g(routines)d(are)
+h(also)h(pro)m(vided)e(to)h(sp)s(eci\014cally)h(deal)f(with)f(2D)i
+(images)f(\(\013p2d)p 3872 3183 V 0 3296 a(and)c(\013g2d)p
+372 3296 V 33 w(\))h(and)f(3D)i(data)f(cub)s(es)f(\(\013p3d)p
+1467 3296 V 59 w(and)g(\013g3d)p 1893 3296 V 33 w(\).)40
+b(The)26 b(dimensionalit)m(y)i(of)f(the)g(FITS)f(image)i(is)e(passed)0
+3408 y(b)m(y)36 b(the)h(naxis1,)h(naxis2,)h(and)d(naxis3)h(parameters)f
+(and)g(the)h(declared)f(dimensions)g(of)h(the)f(program)g(arra)m(y)0
+3521 y(are)30 b(passed)g(in)f(the)h(dim1)g(and)f(dim2)h(parameters.)41
+b(Note)31 b(that)f(the)g(dimensions)f(of)h(the)g(program)g(arra)m(y)g
+(ma)m(y)0 3634 y(b)s(e)35 b(larger)h(than)f(the)h(dimensions)f(of)h
+(the)g(FITS)e(arra)m(y)-8 b(.)58 b(F)-8 b(or)36 b(example)g(if)g(a)g
+(FITS)e(image)j(with)e(NAXIS1)h(=)0 3747 y(NAXIS2)g(=)g(400)h(is)f
+(read)g(in)m(to)h(a)g(program)f(arra)m(y)g(whic)m(h)g(is)g(dimensioned)
+f(as)i(512)g(x)f(512)h(pixels,)h(then)e(the)0 3860 y(image)g(will)f
+(just)f(\014ll)g(the)h(lo)m(w)m(er)h(left)f(corner)f(of)h(the)g(arra)m
+(y)g(with)f(pixels)h(in)f(the)h(range)g(1)g(-)g(400)g(in)g(the)f(X)h
+(an)0 3973 y(Y)g(directions.)54 b(This)34 b(has)h(the)g(e\013ect)h(of)f
+(taking)g(a)h(con)m(tiguous)f(set)h(of)f(pixel)g(v)-5
+b(alue)35 b(in)f(the)h(FITS)f(arra)m(y)i(and)0 4086 y(writing)30
+b(them)g(to)h(a)f(non-con)m(tiguous)h(arra)m(y)g(in)e(program)h(memory)
+g(\(i.e.,)i(there)e(are)h(no)m(w)f(some)g(blank)g(pixels)0
+4199 y(around)f(the)i(edge)g(of)g(the)f(image)i(in)e(the)g(program)g
+(arra)m(y\).)0 4359 y(The)k(most)i(general)f(set)h(of)f(routines)f
+(\(\013pss)p 1560 4359 V 33 w(,)i(\013gsv)p 1836 4359
+V 33 w(,)g(and)e(\013gsf)p 2273 4359 V 33 w(\))h(ma)m(y)h(b)s(e)e(used)
+g(to)h(transfer)g(a)g(rectangular)0 4472 y(subset)27
+b(of)h(the)g(pixels)f(in)h(a)g(FITS)f(N-dimensional)h(image)h(to)f(or)g
+(from)f(an)g(arra)m(y)i(whic)m(h)e(has)g(b)s(een)g(declared)h(in)0
+4585 y(the)h(calling)h(program.)40 b(The)28 b(fpixel)h(and)f(lpixel)h
+(parameters)g(are)g(in)m(teger)h(arra)m(ys)f(whic)m(h)f(sp)s(ecify)g
+(the)h(starting)0 4698 y(and)k(ending)f(pixel)i(co)s(ordinate)g(in)f
+(eac)m(h)h(dimension)f(\(starting)h(with)f(1,)h(not)g(0\))g(of)f(the)g
+(FITS)g(image)h(that)g(is)0 4811 y(to)f(b)s(e)e(read)g(or)h(written.)45
+b(It)32 b(is)g(imp)s(ortan)m(t)g(to)h(note)f(that)h(these)f(are)g(the)g
+(starting)h(and)e(ending)g(pixels)h(in)g(the)0 4924 y(FITS)i(image,)k
+(not)d(in)f(the)h(declared)h(arra)m(y)f(in)f(the)h(program.)54
+b(The)35 b(arra)m(y)g(parameter)g(in)g(these)g(routines)g(is)0
+5036 y(treated)f(simply)e(as)h(a)f(large)i(one-dimensional)g(arra)m(y)f
+(of)f(the)h(appropriate)g(data)g(t)m(yp)s(e)g(con)m(taining)h(the)f
+(pixel)0 5149 y(v)-5 b(alues;)37 b(The)d(pixel)h(v)-5
+b(alues)35 b(in)g(the)f(FITS)g(arra)m(y)h(are)g(read/written)g(from/to)
+h(this)e(program)h(arra)m(y)g(in)f(strict)0 5262 y(sequence)d(without)f
+(an)m(y)h(gaps;)g(it)g(is)f(up)f(to)j(the)e(calling)i(routine)e(to)i
+(correctly)f(in)m(terpret)g(the)g(dimensionalit)m(y)0
+5375 y(of)d(this)f(arra)m(y)-8 b(.)41 b(The)27 b(t)m(w)m(o)i(FITS)e
+(reading)h(routines)f(\(\013gsv)p 2018 5375 V 61 w(and)g(\013gsf)p
+2415 5375 V 61 w(\))h(also)g(ha)m(v)m(e)h(an)f(`inc')g(parameter)g
+(whic)m(h)0 5488 y(de\014nes)33 b(the)h(data)h(sampling)f(in)m(terv)-5
+b(al)36 b(in)d(eac)m(h)j(dimension)d(of)h(the)h(FITS)e(arra)m(y)-8
+b(.)53 b(F)-8 b(or)35 b(example,)h(if)e(inc[0]=2)0 5601
+y(and)i(inc[1]=3)j(when)d(reading)h(a)g(2-dimensional)h(FITS)e(image,)
+41 b(then)36 b(only)h(ev)m(ery)h(other)f(pixel)h(in)e(the)i(\014rst)0
+5714 y(dimension)30 b(and)g(ev)m(ery)h(3rd)f(pixel)g(in)g(the)h(second)
+f(dimension)g(will)h(b)s(e)f(returned)f(to)i(the)f('arra)m(y')i
+(parameter.)p eop end
+%%Page: 108 116
+TeXDict begin 108 115 bop 0 299 a Fj(108)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 Fj(Tw)m(o)f(t)m(yp)s(es)h(of)f(routines)g(are)h
+(pro)m(vided)e(to)i(read)f(the)h(data)g(arra)m(y)f(whic)m(h)g(di\013er)
+g(in)g(the)h(w)m(a)m(y)g(unde\014ned)d(pixels)0 668 y(are)38
+b(handled.)60 b(The)37 b(\014rst)g(t)m(yp)s(e)g(of)g(routines)h
+(\(e.g.,)i(\013gp)m(v)p 2059 668 28 4 v 34 w(\))d(simply)g(return)f(an)
+h(arra)m(y)h(of)g(data)g(elemen)m(ts)g(in)0 781 y(whic)m(h)30
+b(unde\014ned)f(pixels)h(are)h(set)g(equal)g(to)h(a)f(v)-5
+b(alue)31 b(sp)s(eci\014ed)e(b)m(y)i(the)g(user)e(in)i(the)f(`n)m(ulv)
+-5 b(al')32 b(parameter.)41 b(An)0 894 y(additional)30
+b(feature)f(of)g(these)h(routines)e(is)h(that)h(if)f(the)g(user)f(sets)
+h(n)m(ulv)-5 b(al)29 b(=)g(0,)h(then)e(no)h(c)m(hec)m(ks)h(for)f
+(unde\014ned)0 1007 y(pixels)c(will)g(b)s(e)g(p)s(erformed,)f(th)m(us)h
+(reducing)f(the)h(amoun)m(t)h(of)f(CPU)f(pro)s(cessing.)39
+b(The)24 b(second)h(t)m(yp)s(e)g(of)g(routines)0 1120
+y(\(e.g.,)36 b(\013gpf)p 413 1120 V 32 w(\))e(returns)e(the)i(data)g
+(elemen)m(t)g(arra)m(y)g(and,)g(in)f(addition,)h(a)g(c)m(har)g(arra)m
+(y)f(that)h(indicates)h(whether)0 1233 y(the)f(v)-5 b(alue)34
+b(of)g(the)f(corresp)s(onding)g(data)h(pixel)g(is)g(unde\014ned)d(\(=)j
+(1\))g(or)g(de\014ned)e(\(=)i(0\).)51 b(The)33 b(latter)i(t)m(yp)s(e)f
+(of)0 1346 y(routines)d(ma)m(y)h(b)s(e)e(more)i(con)m(v)m(enien)m(t)h
+(to)f(use)f(in)g(some)g(circumstances,)i(ho)m(w)m(ev)m(er,)g(it)e
+(requires)g(an)g(additional)0 1458 y(arra)m(y)g(of)f(logical)j(v)-5
+b(alues)31 b(whic)m(h)f(can)h(b)s(e)e(un)m(wieldy)h(when)g(w)m(orking)g
+(with)g(large)i(data)f(arra)m(ys.)0 1732 y Fi(1)81 b
+Fj(W)-8 b(rite)31 b(elemen)m(ts)h(in)m(to)f(the)g(FITS)f(data)h(arra)m
+(y)-8 b(.)95 2005 y Fe(int)47 b(fits_write_img)d(/)k(ffppr)286
+2117 y(\(fitsfile)e(*fptr,)g(int)h(datatype,)e(LONGLONG)g(firstelem,)g
+(LONGLONG)h(nelements,)334 2230 y(DTYPE)g(*array,)g(int)h(*status\);)95
+2456 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 2569 y
+(ffppr[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286 2682 y(\(fitsfile)f(*fptr,)g
+(long)g(group,)g(LONGLONG)g(firstelem,)f(LONGLONG)h(nelements,)334
+2795 y(DTYPE)g(*array,)g(>)i(int)f(*status\);)95 3021
+y(int)g(fits_write_imgnull)c(/)48 b(ffppn)286 3134 y(\(fitsfile)e
+(*fptr,)g(int)h(datatype,)e(LONGLONG)g(firstelem,)g(LONGLONG)h
+(nelements,)334 3247 y(DTYPE)g(*array,)g(DTYPE)h(*nulval,)e(>)j(int)f
+(*status\);)95 3472 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 3585 y(ffppn[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286
+3698 y(\(fitsfile)f(*fptr,)g(long)g(group,)g(LONGLONG)g(firstelem,)525
+3811 y(LONGLONG)g(nelements,)f(DTYPE)h(*array,)g(DTYPE)g(nulval,)g(>)h
+(int)g(*status\);)0 4084 y Fi(2)81 b Fj(Set)30 b(data)h(arra)m(y)g
+(elemen)m(ts)h(as)e(unde\014ned.)95 4357 y Fe(int)47
+b(fits_write_img_null)c(/)k(ffppru)286 4470 y(\(fitsfile)f(*fptr,)g
+(long)g(group,)g(LONGLONG)g(firstelem,)f(LONGLONG)h(nelements,)334
+4583 y(>)i(int)e(*status\))0 4856 y Fi(3)81 b Fj(W)-8
+b(rite)32 b(v)-5 b(alues)30 b(in)m(to)i(group)e(parameters.)42
+b(This)30 b(routine)g(only)h(applies)g(to)g(the)g(`Random)f(Group)s
+(ed')g(FITS)227 4969 y(format)22 b(whic)m(h)f(has)g(b)s(een)f(used)h
+(for)g(applications)h(in)f(radio)h(in)m(terferometry)-8
+b(,)25 b(but)20 b(is)h(o\016cially)i(deprecated)227 5082
+y(for)30 b(future)g(use.)95 5355 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 5468 y(ffpgp[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286
+5581 y(\(fitsfile)f(*fptr,)g(long)g(group,)g(long)h(firstelem,)e(long)i
+(nelements,)334 5694 y(>)h(DTYPE)e(*array,)g(int)h(*status\))p
+eop end
+%%Page: 109 117
+TeXDict begin 109 116 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)80 b Fj(109)0 555 y Fi(4)h Fj(W)-8
+b(rite)31 b(a)g(2-D)h(or)e(3-D)h(image)h(in)m(to)f(the)g(data)g(arra)m
+(y)-8 b(.)95 776 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
+889 y(ffp2d[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286 1002 y(\(fitsfile)f
+(*fptr,)g(long)g(group,)g(LONGLONG)g(dim1,)g(LONGLONG)g(naxis1,)334
+1115 y(LONGLONG)g(naxis2,)f(DTYPE)i(*array,)f(>)h(int)g(*status\))95
+1341 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 1453 y
+(ffp3d[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286 1566 y(\(fitsfile)f(*fptr,)g
+(long)g(group,)g(LONGLONG)g(dim1,)g(LONGLONG)g(dim2,)g(LONGLONG)g
+(naxis1,)334 1679 y(LONGLONG)g(naxis2,)f(LONGLONG)h(naxis3,)g(DTYPE)g
+(*array,)g(>)h(int)g(*status\))0 1900 y Fi(5)81 b Fj(W)-8
+b(rite)31 b(an)g(arbitrary)f(data)h(subsection)f(in)m(to)i(the)e(data)h
+(arra)m(y)-8 b(.)95 2121 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 2234 y(ffpss[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286
+2347 y(\(fitsfile)f(*fptr,)g(long)g(group,)g(long)h(naxis,)f(long)h
+(*naxes,)334 2460 y(long)g(*fpixel,)e(long)i(*lpixel,)e(DTYPE)i
+(*array,)f(>)h(int)g(*status\))0 2680 y Fi(6)81 b Fj(Read)30
+b(elemen)m(ts)i(from)e(the)g(FITS)g(data)h(arra)m(y)-8
+b(.)95 2901 y Fe(int)47 b(fits_read_img)e(/)i(ffgpv)286
+3014 y(\(fitsfile)f(*fptr,)g(int)94 b(datatype,)46 b(long)g(firstelem,)
+f(long)i(nelements,)334 3127 y(DTYPE)f(*nulval,)g(>)h(DTYPE)g(*array,)f
+(int)h(*anynul,)e(int)i(*status\))95 3353 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
+(/)286 3466 y(ffgpv[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286
+3579 y(\(fitsfile)f(*fptr,)g(long)g(group,)g(long)h(firstelem,)e(long)i
+(nelements,)334 3692 y(DTYPE)f(nulval,)g(>)i(DTYPE)e(*array,)g(int)h
+(*anynul,)e(int)i(*status\))95 3917 y(int)g(fits_read_imgnull)c(/)48
+b(ffgpf)286 4030 y(\(fitsfile)e(*fptr,)g(int)94 b(datatype,)46
+b(long)g(firstelem,)f(long)i(nelements,)334 4143 y(>)h(DTYPE)e(*array,)
+g(char)g(*nullarray,)f(int)i(*anynul,)f(int)g(*status\))95
+4369 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 4482 y
+(ffgpf[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 4595 y(\(fitsfile)e(*fptr,)h
+(long)h(group,)f(long)h(firstelem,)e(long)h(nelements,)334
+4708 y(>)i(DTYPE)e(*array,)g(char)g(*nullarray,)f(int)i(*anynul,)f(int)
+g(*status\))0 4929 y Fi(7)81 b Fj(Read)29 b(v)-5 b(alues)31
+b(from)e(group)g(parameters.)41 b(This)29 b(routine)g(only)h(applies)g
+(to)h(the)e(`Random)h(Group)s(ed')f(FITS)227 5041 y(format)22
+b(whic)m(h)f(has)g(b)s(een)f(used)h(for)g(applications)h(in)f(radio)h
+(in)m(terferometry)-8 b(,)25 b(but)20 b(is)h(o\016cially)i(deprecated)
+227 5154 y(for)30 b(future)g(use.)95 5375 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 5488 y
+(ffggp[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 5601 y(\(fitsfile)e(*fptr,)h
+(long)h(group,)f(long)h(firstelem,)e(long)h(nelements,)334
+5714 y(>)i(DTYPE)e(*array,)g(int)h(*status\))p eop end
+%%Page: 110 118
+TeXDict begin 110 117 bop 0 299 a Fj(110)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(8)81 b Fj(Read)37 b(2-D)h(or)g(3-D)g(image)g
+(from)f(the)g(data)h(arra)m(y)-8 b(.)62 b(Unde\014ned)36
+b(pixels)i(in)e(the)i(arra)m(y)g(will)f(b)s(e)g(set)g(equal)227
+668 y(to)32 b(the)g(v)-5 b(alue)31 b(of)h('n)m(ulv)-5
+b(al',)32 b(unless)f(n)m(ulv)-5 b(al=0)31 b(in)g(whic)m(h)g(case)h(no)f
+(testing)i(for)e(unde\014ned)e(pixels)i(will)h(b)s(e)227
+781 y(p)s(erformed.)95 1049 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 1162 y(ffg2d[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334
+1275 y(\(fitsfile)e(*fptr,)h(long)h(group,)f(DTYPE)h(nulval,)e
+(LONGLONG)h(dim1,)g(LONGLONG)g(naxis1,)334 1387 y(LONGLONG)g(naxis2,)f
+(>)j(DTYPE)e(*array,)g(int)h(*anynul,)f(int)g(*status\))95
+1613 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 1726 y
+(ffg3d[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 1839 y(\(fitsfile)e(*fptr,)h
+(long)h(group,)f(DTYPE)h(nulval,)e(LONGLONG)h(dim1,)334
+1952 y(LONGLONG)g(dim2,)g(LONGLONG)g(naxis1,)f(LONGLONG)h(naxis2,)g
+(LONGLONG)f(naxis3,)334 2065 y(>)j(DTYPE)e(*array,)g(int)h(*anynul,)e
+(int)i(*status\))0 2333 y Fi(9)81 b Fj(Read)30 b(an)g(arbitrary)h(data)
+g(subsection)f(from)g(the)g(data)i(arra)m(y)-8 b(.)95
+2600 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
+2713 y(ffgsv[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334 2826
+y(\(fitsfile)e(*fptr,)h(int)h(group,)f(int)h(naxis,)f(long)h(*naxes,)
+334 2939 y(long)g(*fpixel,)e(long)i(*lpixel,)e(long)i(*inc,)f(DTYPE)h
+(nulval,)334 3052 y(>)h(DTYPE)e(*array,)g(int)h(*anynul,)e(int)i
+(*status\))95 3278 y(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 3391 y(ffgsf[b,i,ui,k,uk,j,uj,jj)o(,e,)o(d])334
+3504 y(\(fitsfile)e(*fptr,)h(int)h(group,)f(int)h(naxis,)f(long)h
+(*naxes,)334 3617 y(long)g(*fpixel,)e(long)i(*lpixel,)e(long)i(*inc,)f
+(>)i(DTYPE)e(*array,)334 3730 y(char)h(*nullarray,)d(int)j(*anynul,)f
+(int)h(*status\))0 4073 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
+4328 y Fd(9.6.1)112 b(General)39 b(Column)f(Routines)0
+4543 y Fi(1)81 b Fj(Get)31 b(information)f(ab)s(out)g(an)g(existing)h
+(ASCI)s(I)d(or)i(binary)f(table)i(column.)41 b(A)30 b(n)m(ull)g(p)s
+(oin)m(ter)g(ma)m(y)h(b)s(e)e(giv)m(en)227 4656 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)e(a)h(c)m(haracter)h(string)227
+4769 y(whic)m(h)d(returns)e(the)i(data)g(t)m(yp)s(e)g(of)g(the)f
+(column)h(as)g(de\014ned)e(b)m(y)i(the)f(TF)m(ORMn)h(k)m(eyw)m(ord)g
+(\(e.g.,)j('I',)227 4882 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,)g(t)
+m(yp)s(eco)s(de)f(will)g(ha)m(v)m(e)h(a)f(v)-5 b(alue)28
+b(of)f(the)227 4994 y(form)g('An')g(where)f('n')h(is)g(an)g(in)m(teger)
+i(expressing)d(the)h(width)g(of)g(the)g(\014eld)g(in)f(c)m(haracters.)
+41 b(F)-8 b(or)28 b(example,)227 5107 y(if)g(TF)m(ORM)h(=)e('160A8')k
+(then)d(\013gb)s(cl)g(will)g(return)f(t)m(yp)s(ec)m(har='A8')j(and)d
+(rep)s(eat=20.)41 b(All)29 b(the)f(returned)227 5220
+y(parameters)j(are)g(scalar)g(quan)m(tities.)95 5488
+y Fe(int)47 b(fits_get_acolparms)c(/)48 b(ffgacl)191
+5601 y(\(fitsfile)d(*fptr,)h(int)h(colnum,)f(>)h(char)g(*ttype,)f(long)
+h(*tbcol,)239 5714 y(char)f(*tunit,)g(char)h(*tform,)f(double)g
+(*scale,)f(double)i(*zero,)p eop end
+%%Page: 111 119
+TeXDict begin 111 118 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(111)239 555 y Fe(char)46 b(*nulstr,)g(char)g
+(*tdisp,)g(int)h(*status\))95 781 y(int)g(fits_get_bcolparms)c(/)48
+b(ffgbcl)286 894 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(>)j(char)f
+(*ttype,)e(char)i(*tunit,)334 1007 y(char)g(*typechar,)e(long)h
+(*repeat,)g(double)g(*scale,)g(double)g(*zero,)334 1120
+y(long)h(*nulval,)e(char)i(*tdisp,)f(int)94 b(*status\))95
+1346 y(int)47 b(fits_get_bcolparmsll)c(/)k(ffgbclll)286
+1458 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(>)j(char)f(*ttype,)e(char)
+i(*tunit,)334 1571 y(char)g(*typechar,)e(LONGLONG)g(*repeat,)h(double)g
+(*scale,)g(double)g(*zero,)334 1684 y(LONGLONG)g(*nulval,)f(char)i
+(*tdisp,)f(int)94 b(*status\))0 1937 y Fi(2)81 b Fj(Return)27
+b(optimal)i(n)m(um)m(b)s(er)e(of)h(ro)m(ws)g(to)h(read)f(or)g(write)g
+(at)h(one)f(time)h(for)f(maxim)m(um)g(I/O)f(e\016ciency)-8
+b(.)42 b(Refer)227 2050 y(to)25 b(the)g(\\Optimizing)g(Co)s(de")f
+(section)i(in)e(Chapter)g(5)g(for)g(more)h(discussion)f(on)g(ho)m(w)g
+(to)h(use)f(this)h(routine.)95 2416 y Fe(int)47 b(fits_get_rowsize)d(/)
+j(ffgrsz)286 2529 y(\(fitsfile)f(*fptr,)g(long)g(*nrows,)g(*status\))0
+2782 y Fi(3)81 b Fj(De\014ne)22 b(the)g(zero)i(indexed)d(b)m(yte)i
+(o\013set)g(of)g(the)f('heap')h(measured)e(from)h(the)h(start)g(of)f
+(the)g(binary)g(table)h(data.)227 2895 y(By)30 b(default)g(the)f(heap)h
+(is)f(assumed)g(to)h(start)g(immediately)h(follo)m(wing)g(the)f
+(regular)f(table)i(data,)f(i.e.,)h(at)227 3008 y(lo)s(cation)38
+b(NAXIS1)f(x)g(NAXIS2.)59 b(This)36 b(routine)g(is)h(only)f(relev)-5
+b(an)m(t)38 b(for)e(binary)g(tables)h(whic)m(h)g(con)m(tain)227
+3121 y(v)-5 b(ariable)25 b(length)g(arra)m(y)g(columns)f(\(with)g(TF)m
+(ORMn)g(=)g('Pt'\).)40 b(This)23 b(routine)i(also)g(automatically)i
+(writes)227 3234 y(the)35 b(v)-5 b(alue)35 b(of)g(theap)f(to)h(a)g(k)m
+(eyw)m(ord)g(in)g(the)f(extension)h(header.)53 b(This)34
+b(routine)g(m)m(ust)h(b)s(e)f(called)h(after)227 3347
+y(the)c(required)e(k)m(eyw)m(ords)h(ha)m(v)m(e)i(b)s(een)d(written)h
+(\(with)g(\013ph)m(bn\))f(but)h(b)s(efore)f(an)m(y)i(data)g(is)f
+(written)g(to)h(the)227 3460 y(table.)95 3713 y Fe(int)47
+b(fits_write_theap)d(/)j(ffpthp)286 3826 y(\(fitsfile)f(*fptr,)g(long)g
+(theap,)g(>)i(int)f(*status\))0 4079 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)e(table)j(v)-5
+b(ariable)37 b(arra)m(y)g(heap,)h(returning)e(the)g(size)h(of)g(the)g
+(heap,)h(the)227 4192 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)g(p)s(oin)m(ted)g(to)h(b)m(y)e(an)m
+(y)i(of)f(the)g(descriptors,)g(and)f(the)227 4304 y(n)m(um)m(b)s(er)d
+(of)h(b)m(ytes)h(whic)m(h)f(are)g(p)s(oin)m(ted)g(to)h(b)m(y)f(m)m
+(ultiple)h(descriptors.)40 b(It)28 b(also)h(returns)e(v)-5
+b(alid)29 b(=)e(F)-10 b(ALSE)227 4417 y(if)31 b(an)m(y)f(of)h(the)f
+(descriptors)h(p)s(oin)m(t)f(to)h(in)m(v)-5 b(alid)31
+b(addresses)f(out)g(of)h(range)g(of)f(the)h(heap.)95
+4670 y Fe(int)47 b(fits_test_heap)d(/)k(fftheap)286 4783
+y(\(fitsfile)e(*fptr,)g(>)h(LONGLONG)f(*heapsize,)f(LONGLONG)g
+(*unused,)h(LONGLONG)f(*overlap,)334 4896 y(int)i(*validheap,)e(int)i
+(*status\))0 5149 y Fi(5)81 b Fj(Re-pac)m(k)33 b(the)f(v)m(ectors)h(in)
+e(the)h(binary)f(table)i(v)-5 b(ariable)32 b(arra)m(y)g(heap)g(to)g
+(reco)m(v)m(er)i(an)m(y)e(un)m(used)e(space.)45 b(Nor-)227
+5262 y(mally)-8 b(,)40 b(when)d(a)g(v)m(ector)i(in)e(a)g(v)-5
+b(ariable)38 b(length)g(arra)m(y)f(column)g(is)g(rewritten)h(the)f
+(previously)g(written)227 5375 y(arra)m(y)d(remains)e(in)h(the)g(heap)f
+(as)h(w)m(asted)h(un)m(used)d(space.)49 b(This)32 b(routine)g(will)i
+(repac)m(k)f(the)g(arra)m(ys)g(that)227 5488 y(are)h(still)g(in)f(use,)
+h(th)m(us)f(eliminating)h(an)m(y)g(b)m(ytes)g(in)f(the)g(heap)g(that)h
+(are)g(no)f(longer)h(in)f(use.)49 b(Note)34 b(that)227
+5601 y(if)f(sev)m(eral)h(v)m(ectors)g(p)s(oin)m(t)e(to)i(the)e(same)h
+(b)m(ytes)g(in)g(the)f(heap,)i(then)e(this)g(routine)h(will)g(mak)m(e)g
+(duplicate)227 5714 y(copies)e(of)g(the)g(b)m(ytes)f(for)h(eac)m(h)g(v)
+m(ector,)h(whic)m(h)e(will)h(actually)h(expand)e(the)g(size)i(of)e(the)
+h(heap.)p eop end
+%%Page: 112 120
+TeXDict begin 112 119 bop 0 299 a Fj(112)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_compress_heap)c(/)48
+b(ffcmph)286 668 y(\(fitsfile)e(*fptr,)g(>)h(int)g(*status\))0
+976 y Fd(9.6.2)112 b(Lo)m(w-Lev)m(el)39 b(T)-9 b(able)38
+b(Access)f(Routines)0 1198 y Fj(The)g(follo)m(wing)j(2)e(routines)f
+(pro)m(vide)h(lo)m(w-lev)m(el)j(access)e(to)g(the)f(data)g(in)g(ASCI)s
+(I)e(or)i(binary)f(tables)h(and)g(are)0 1311 y(mainly)29
+b(useful)f(as)i(an)f(e\016cien)m(t)h(w)m(a)m(y)g(to)g(cop)m(y)g(all)g
+(or)f(part)g(of)g(a)g(table)h(from)f(one)g(lo)s(cation)i(to)f(another.)
+40 b(These)0 1424 y(routines)24 b(simply)g(read)g(or)h(write)f(the)h
+(sp)s(eci\014ed)e(n)m(um)m(b)s(er)g(of)i(consecutiv)m(e)h(b)m(ytes)f
+(in)f(an)g(ASCI)s(I)f(or)h(binary)g(table,)0 1537 y(without)g(regard)g
+(for)f(column)h(b)s(oundaries)e(or)i(the)g(ro)m(w)g(length)g(in)f(the)h
+(table.)40 b(These)23 b(routines)h(do)f(not)h(p)s(erform)0
+1650 y(an)m(y)36 b(mac)m(hine)h(dep)s(enden)m(t)e(data)i(con)m(v)m
+(ersion)g(or)g(b)m(yte)f(sw)m(apping.)58 b(See)36 b(App)s(endix)e(B)j
+(for)f(the)g(de\014nition)g(of)0 1763 y(the)31 b(parameters)f(used)g
+(in)g(these)h(routines.)0 2037 y Fi(1)81 b Fj(Read)30
+b(or)h(write)f(a)h(consecutiv)m(e)h(arra)m(y)f(of)g(b)m(ytes)f(from)g
+(an)h(ASCI)s(I)d(or)j(binary)e(table)95 2311 y Fe(int)47
+b(fits_read_tblbytes)c(/)48 b(ffgtbb)286 2424 y(\(fitsfile)e(*fptr,)g
+(LONGLONG)f(firstrow,)h(LONGLONG)f(firstchar,)g(LONGLONG)h(nchars,)334
+2537 y(>)i(unsigned)d(char)i(*values,)e(int)i(*status\))95
+2763 y(int)g(fits_write_tblbytes)c(/)k(ffptbb)286 2876
+y(\(fitsfile)f(*fptr,)g(LONGLONG)f(firstrow,)h(LONGLONG)f(firstchar,)g
+(LONGLONG)h(nchars,)334 2989 y(unsigned)g(char)g(*values,)g(>)h(int)g
+(*status\))0 3296 y Fd(9.6.3)112 b(W)-9 b(rite)37 b(Column)h(Data)g
+(Routines)0 3516 y Fi(1)81 b Fj(W)-8 b(rite)28 b(elemen)m(ts)h(in)m(to)
+f(an)g(ASCI)s(I)d(or)j(binary)e(table)j(column)e(\(in)g(the)h(CDU\).)g
+(The)f(data)h(t)m(yp)s(e)f(of)h(the)f(arra)m(y)227 3629
+y(is)k(implied)f(b)m(y)g(the)h(su\016x)e(of)i(the)f(routine)h(name.)95
+3903 y Fe(int)47 b(fits_write_col_str)c(/)48 b(ffpcls)286
+4016 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)f
+(LONGLONG)h(firstelem,)334 4129 y(LONGLONG)g(nelements,)f(char)h
+(**array,)g(>)h(int)g(*status\))95 4355 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 4468 y(ffpcl[l,b,i,ui,k,uk,j,uj,j)o(j,e)o(,d,c)o(,m])286
+4581 y(\(fitsfile)46 b(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)
+525 4694 y(LONGLONG)g(firstelem,)f(LONGLONG)g(nelements,)g(DTYPE)h
+(*array,)g(>)i(int)f(*status\))0 4968 y Fi(2)81 b Fj(W)-8
+b(rite)36 b(elemen)m(ts)h(in)m(to)g(an)e(ASCI)s(I)f(or)i(binary)e
+(table)j(column)e(substituting)g(the)h(appropriate)f(FITS)g(n)m(ull)227
+5081 y(v)-5 b(alue)31 b(for)f(an)m(y)h(elemen)m(ts)h(that)f(are)f
+(equal)h(to)g(the)g(n)m(ulv)-5 b(al)31 b(parameter.)95
+5355 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
+5468 y(ffpcn[l,b,i,ui,k,uk,j,uj,j)o(j,e)o(,d])286 5581
+y(\(fitsfile)g(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)f
+(LONGLONG)h(firstelem,)334 5694 y(LONGLONG)g(nelements,)f(DTYPE)h
+(*array,)g(DTYPE)g(nulval,)g(>)h(int)g(*status\))p eop
+end
+%%Page: 113 121
+TeXDict begin 113 120 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(113)0 555 y Fi(3)81 b Fj(W)-8
+b(rite)27 b(string)g(elemen)m(ts)h(in)m(to)f(a)g(binary)f(table)h
+(column)f(\(in)h(the)f(CDU\))i(substituting)e(the)g(FITS)g(n)m(ull)g(v)
+-5 b(alue)227 668 y(for)30 b(an)m(y)h(elemen)m(ts)h(that)f(are)g(equal)
+f(to)i(the)e(n)m(ulstr)g(string.)95 921 y Fe(int)47 b
+(fits_write_colnull_str)42 b(/)48 b(ffpcns)286 1034 y(\(fitsfile)e
+(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)f(LONGLONG)h(firstelem,)
+334 1147 y(LONGLONG)g(nelements,)f(char)h(**array,)g(char)g(*nulstr,)g
+(>)h(int)g(*status\))0 1399 y Fi(4)81 b Fj(W)-8 b(rite)34
+b(bit)f(v)-5 b(alues)33 b(in)m(to)h(a)g(binary)e(b)m(yte)h(\('B'\))i
+(or)e(bit)g(\('X'\))h(table)g(column)f(\(in)g(the)g(CDU\).)h(Larra)m(y)
+f(is)g(an)227 1512 y(arra)m(y)25 b(of)g(c)m(haracters)h(corresp)s
+(onding)e(to)h(the)g(sequence)g(of)f(bits)h(to)g(b)s(e)f(written.)39
+b(If)24 b(an)g(elemen)m(t)i(of)f(larra)m(y)227 1625 y(is)k(true)g
+(\(not)h(equal)f(to)h(zero\))g(then)f(the)g(corresp)s(onding)f(bit)h
+(in)g(the)g(FITS)f(table)i(is)f(set)h(to)g(1,)g(otherwise)227
+1738 y(the)37 b(bit)g(is)g(set)g(to)g(0.)60 b(The)37
+b('X')g(column)f(in)h(a)g(FITS)f(table)h(is)g(alw)m(a)m(ys)h(padded)e
+(out)h(to)g(a)g(m)m(ultiple)h(of)227 1851 y(8)f(bits)f(where)g(the)g
+(bit)h(arra)m(y)f(starts)h(with)f(the)h(most)f(signi\014can)m(t)h(bit)g
+(of)f(the)h(b)m(yte)g(and)e(w)m(orks)h(do)m(wn)227 1964
+y(to)m(w)m(ards)h(the)g(1's)f(bit.)59 b(F)-8 b(or)37
+b(example,)i(a)d('4X')h(arra)m(y)-8 b(,)39 b(with)d(the)h(\014rst)e
+(bit)i(=)e(1)i(and)f(the)g(remaining)h(3)227 2077 y(bits)31
+b(=)g(0)h(is)f(equiv)-5 b(alen)m(t)33 b(to)f(the)g(8-bit)g(unsigned)e
+(b)m(yte)i(decimal)g(v)-5 b(alue)32 b(of)g(128)g(\('1000)i(0000B'\).)g
+(In)d(the)227 2189 y(case)h(of)f('X')g(columns,)g(CFITSIO)f(can)h
+(write)g(to)g(all)h(8)f(bits)g(of)g(eac)m(h)h(b)m(yte)f(whether)f(they)
+h(are)g(formally)227 2302 y(v)-5 b(alid)34 b(or)f(not.)50
+b(Th)m(us)32 b(if)i(the)f(column)g(is)h(de\014ned)e(as)h('4X',)i(and)e
+(one)g(calls)i(\013p)s(clx)e(with)g(\014rstbit=1)g(and)227
+2415 y(n)m(bits=8,)i(then)f(all)g(8)h(bits)e(will)h(b)s(e)g(written)g
+(in)m(to)g(the)g(\014rst)f(b)m(yte)i(\(as)f(opp)s(osed)f(to)i(writing)e
+(the)h(\014rst)g(4)227 2528 y(bits)28 b(in)m(to)h(the)e(\014rst)g(ro)m
+(w)h(and)f(then)h(the)g(next)g(4)g(bits)f(in)m(to)i(the)f(next)g(ro)m
+(w\),)h(ev)m(en)f(though)f(the)h(last)h(4)f(bits)227
+2641 y(of)j(eac)m(h)g(b)m(yte)g(are)f(formally)h(not)f(de\014ned)f(and)
+h(should)f(all)i(b)s(e)e(set)i(=)f(0.)41 b(It)30 b(should)f(also)j(b)s
+(e)d(noted)h(that)227 2754 y(it)k(is)e(more)h(e\016cien)m(t)i(to)e
+(write)g('X')h(columns)e(an)h(en)m(tire)h(b)m(yte)f(at)h(a)f(time,)h
+(instead)f(of)g(bit)g(b)m(y)g(bit.)48 b(An)m(y)227 2867
+y(of)31 b(the)g(CFITSIO)e(routines)h(that)i(write)f(to)g(columns)f
+(\(e.g.)43 b(\014ts)p 2481 2867 28 4 v 33 w(write)p 2716
+2867 V 33 w(col)p 2859 2867 V 33 w(b)m(yt\))32 b(ma)m(y)f(b)s(e)f(used)
+g(for)g(this)227 2980 y(purp)s(ose.)60 b(These)36 b(routines)i(will)f
+(in)m(terpret)h('X')f(columns)g(as)g(though)g(they)h(w)m(ere)f('B')h
+(columns)f(\(e.g.,)227 3093 y('1X')32 b(through)d('8X')j(is)e(equiv)-5
+b(alen)m(t)32 b(to)f('1B',)h(and)e('9X')h(through)f('16X')i(is)e(equiv)
+-5 b(alen)m(t)32 b(to)f('2B'\).)95 3345 y Fe(int)47 b
+(fits_write_col_bit)c(/)48 b(ffpclx)286 3458 y(\(fitsfile)e(*fptr,)g
+(int)h(colnum,)e(LONGLONG)h(firstrow,)f(long)i(firstbit,)334
+3571 y(long)g(nbits,)f(char)g(*larray,)g(>)h(int)g(*status\))0
+3824 y Fi(5)81 b Fj(W)-8 b(rite)35 b(the)f(descriptor)g(for)f(a)h(v)-5
+b(ariable)35 b(length)f(column)g(in)f(a)i(binary)e(table.)52
+b(This)33 b(routine)g(can)i(b)s(e)e(used)227 3937 y(in)h(conjunction)g
+(with)f(\013gdes)h(to)h(enable)f(2)g(or)g(more)g(arra)m(ys)h(to)f(p)s
+(oin)m(t)g(to)h(the)f(same)g(storage)h(lo)s(cation)227
+4050 y(to)c(sa)m(v)m(e)h(storage)g(space)f(if)f(the)h(arra)m(ys)g(are)g
+(iden)m(tical.)191 4302 y Fe(int)47 b(fits_write_descript)42
+b(/)48 b(ffpdes)382 4415 y(\(fitsfile)d(*fptr,)h(int)h(colnum,)f
+(LONGLONG)f(rownum,)h(LONGLONG)g(repeat,)430 4528 y(LONGLONG)f(offset,)
+h(>)h(int)g(*status\))0 4818 y Fd(9.6.4)112 b(Read)38
+b(Column)h(Data)f(Routines)0 5036 y Fj(Tw)m(o)28 b(t)m(yp)s(es)f(of)h
+(routines)f(are)h(pro)m(vided)f(to)h(get)h(the)e(column)h(data)g(whic)m
+(h)f(di\013er)g(in)g(the)h(w)m(a)m(y)h(unde\014ned)c(pixels)0
+5149 y(are)40 b(handled.)66 b(The)39 b(\014rst)g(set)h(of)f(routines)g
+(\(\013gcv\))i(simply)e(return)f(an)h(arra)m(y)h(of)g(data)g(elemen)m
+(ts)g(in)f(whic)m(h)0 5262 y(unde\014ned)28 b(pixels)j(are)g(set)g
+(equal)g(to)g(a)g(v)-5 b(alue)31 b(sp)s(eci\014ed)f(b)m(y)h(the)f(user)
+g(in)g(the)h('n)m(ullv)-5 b(al')32 b(parameter.)41 b(If)30
+b(n)m(ullv)-5 b(al)0 5375 y(=)22 b(0,)j(then)d(no)g(c)m(hec)m(ks)i(for)
+e(unde\014ned)e(pixels)j(will)g(b)s(e)f(p)s(erformed,)g(th)m(us)g
+(increasing)i(the)e(sp)s(eed)g(of)g(the)h(program.)0
+5488 y(The)36 b(second)g(set)g(of)h(routines)e(\(\013gcf)7
+b(\))38 b(returns)d(the)h(data)h(elemen)m(t)g(arra)m(y)g(and)e(in)h
+(addition)g(a)h(logical)h(arra)m(y)0 5601 y(of)33 b(\015ags)f(whic)m(h)
+g(de\014nes)g(whether)g(the)g(corresp)s(onding)g(data)h(pixel)f(is)h
+(unde\014ned.)44 b(See)33 b(App)s(endix)e(B)i(for)f(the)0
+5714 y(de\014nition)e(of)h(the)f(parameters)h(used)e(in)h(these)h
+(routines.)p eop end
+%%Page: 114 122
+TeXDict begin 114 121 bop 0 299 a Fj(114)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 Fj(An)m(y)39 b(column,)h(regardless)f(of)g(it's)g
+(in)m(trinsic)g(data)h(t)m(yp)s(e,)h(ma)m(y)e(b)s(e)f(read)g(as)h(a)g
+(string.)66 b(It)38 b(should)g(b)s(e)g(noted)0 668 y(ho)m(w)m(ev)m(er)
+32 b(that)f(reading)f(a)h(n)m(umeric)f(column)g(as)h(a)f(string)h(is)f
+(10)h(-)g(100)g(times)g(slo)m(w)m(er)h(than)e(reading)g(the)h(same)0
+781 y(column)g(as)h(a)g(n)m(um)m(b)s(er)e(due)h(to)h(the)g(large)h(o)m
+(v)m(erhead)f(in)g(constructing)g(the)g(formatted)g(strings.)44
+b(The)31 b(displa)m(y)0 894 y(format)26 b(of)g(the)h(returned)d
+(strings)i(will)g(b)s(e)g(determined)f(b)m(y)h(the)g(TDISPn)f(k)m(eyw)m
+(ord,)j(if)d(it)i(exists,)h(otherwise)e(b)m(y)0 1007
+y(the)h(data)g(t)m(yp)s(e)f(of)h(the)f(column.)39 b(The)26
+b(length)h(of)g(the)f(returned)f(strings)h(\(not)h(including)f(the)h(n)
+m(ull)f(terminating)0 1120 y(c)m(haracter\))38 b(can)e(b)s(e)g
+(determined)f(with)h(the)g(\014ts)p 1722 1120 28 4 v
+33 w(get)p 1875 1120 V 34 w(col)p 2019 1120 V 33 w(displa)m(y)p
+2330 1120 V 33 w(width)g(routine.)57 b(The)36 b(follo)m(wing)h(TDISPn)0
+1233 y(displa)m(y)31 b(formats)f(are)h(curren)m(tly)f(supp)s(orted:)191
+1490 y Fe(Iw.m)142 b(Integer)191 1603 y(Ow.m)g(Octal)46
+b(integer)191 1716 y(Zw.m)142 b(Hexadecimal)45 b(integer)191
+1829 y(Fw.d)142 b(Fixed)46 b(floating)g(point)191 1942
+y(Ew.d)142 b(Exponential)45 b(floating)g(point)191 2055
+y(Dw.d)142 b(Exponential)45 b(floating)g(point)191 2168
+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 2425 y Fj(where)37 b(w)h(is)g(the)g(width)f(in)h
+(c)m(haracters)h(of)f(the)h(displa)m(y)m(ed)f(v)-5 b(alues,)41
+b(m)c(is)h(the)g(minim)m(um)g(n)m(um)m(b)s(er)e(of)i(digits)0
+2538 y(displa)m(y)m(ed,)31 b(and)f(d)g(is)g(the)h(n)m(um)m(b)s(er)e(of)
+h(digits)h(to)g(the)g(righ)m(t)g(of)g(the)f(decimal.)42
+b(The)30 b(.m)g(\014eld)g(is)g(optional.)0 2796 y Fi(1)81
+b Fj(Read)29 b(elemen)m(ts)i(from)e(an)g(ASCI)s(I)f(or)i(binary)f
+(table)h(column)f(\(in)h(the)f(CDU\).)i(These)e(routines)g(return)g
+(the)227 2909 y(v)-5 b(alues)30 b(of)g(the)g(table)h(column)f(arra)m(y)
+g(elemen)m(ts.)42 b(Unde\014ned)28 b(arra)m(y)j(elemen)m(ts)g(will)f(b)
+s(e)f(returned)g(with)h(a)227 3022 y(v)-5 b(alue)30 b(=)e(n)m(ulv)-5
+b(al,)30 b(unless)e(n)m(ulv)-5 b(al)29 b(=)f(0)i(\(or)f(=)f(')h(')g
+(for)g(\013gcvs\))g(in)g(whic)m(h)f(case)i(no)f(c)m(hec)m(king)i(for)d
+(unde\014ned)227 3135 y(v)-5 b(alues)28 b(will)g(b)s(e)f(p)s(erformed.)
+39 b(The)27 b(ANYF)h(parameter)g(is)g(set)g(to)g(true)g(if)g(an)m(y)f
+(of)h(the)g(returned)f(elemen)m(ts)227 3247 y(are)k(unde\014ned.)95
+3505 y Fe(int)47 b(fits_read_col_str)c(/)48 b(ffgcvs)286
+3618 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)f
+(LONGLONG)h(firstelem,)334 3731 y(LONGLONG)g(nelements,)f(char)h
+(*nulstr,)g(>)h(char)g(**array,)e(int)i(*anynul,)334
+3844 y(int)g(*status\))95 4070 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 4183 y
+(ffgcv[l,b,i,ui,k,uk,j,uj,j)o(j,e)o(,d,c)o(,m])286 4295
+y(\(fitsfile)g(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)f
+(LONGLONG)h(firstelem,)334 4408 y(LONGLONG)g(nelements,)f(DTYPE)h
+(nulval,)g(>)h(DTYPE)g(*array,)e(int)i(*anynul,)334 4521
+y(int)g(*status\))0 4779 y Fi(2)81 b Fj(Read)39 b(elemen)m(ts)i(and)e
+(n)m(ull)h(\015ags)g(from)f(an)g(ASCI)s(I)g(or)g(binary)g(table)i
+(column)e(\(in)h(the)g(CHDU\).)g(These)227 4892 y(routines)29
+b(return)e(the)i(v)-5 b(alues)29 b(of)g(the)g(table)h(column)e(arra)m
+(y)i(elemen)m(ts.)41 b(An)m(y)29 b(unde\014ned)d(arra)m(y)k(elemen)m
+(ts)227 5005 y(will)k(ha)m(v)m(e)h(the)f(corresp)s(onding)e(n)m
+(ullarra)m(y)i(elemen)m(t)h(set)f(equal)g(to)g(TR)m(UE.)g(The)f(an)m
+(yn)m(ul)h(parameter)g(is)227 5118 y(set)d(to)g(true)f(if)h(an)m(y)g
+(of)f(the)h(returned)e(elemen)m(ts)j(are)e(unde\014ned.)95
+5375 y Fe(int)47 b(fits_read_colnull_str)42 b(/)48 b(ffgcfs)286
+5488 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)f
+(LONGLONG)h(firstelem,)334 5601 y(LONGLONG)g(nelements,)f(>)i(char)g
+(**array,)e(char)i(*nullarray,)e(int)i(*anynul,)334 5714
+y(int)g(*status\))p eop end
+%%Page: 115 123
+TeXDict begin 115 122 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(115)95 668 y Fe(int)47 b
+(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 781 y(ffgcf[l,b,i,ui,k,uk,j,uj,j)o(j,e)o(,d,c)o(,m])286
+894 y(\(fitsfile)46 b(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)334
+1007 y(LONGLONG)g(firstelem,)f(LONGLONG)g(nelements,)g(>)j(DTYPE)e
+(*array,)334 1120 y(char)h(*nullarray,)d(int)j(*anynul,)f(int)h
+(*status\))0 1384 y Fi(3)81 b Fj(Read)24 b(an)g(arbitrary)g(data)h
+(subsection)f(from)g(an)g(N-dimensional)h(arra)m(y)g(in)f(a)g(binary)g
+(table)h(v)m(ector)h(column.)227 1497 y(Unde\014ned)21
+b(pixels)i(in)f(the)h(arra)m(y)g(will)g(b)s(e)f(set)h(equal)h(to)f(the)
+g(v)-5 b(alue)23 b(of)g('n)m(ulv)-5 b(al',)25 b(unless)d(n)m(ulv)-5
+b(al=0)23 b(in)f(whic)m(h)227 1610 y(case)37 b(no)e(testing)h(for)f
+(unde\014ned)e(pixels)i(will)h(b)s(e)f(p)s(erformed.)53
+b(The)35 b(\014rst)g(and)f(last)i(ro)m(ws)g(in)f(the)g(table)227
+1722 y(to)30 b(b)s(e)e(read)h(are)g(sp)s(eci\014ed)g(b)m(y)g
+(fpixel\(naxis+1\))g(and)g(lpixel\(naxis+1\),)i(and)d(hence)h(are)h
+(treated)g(as)f(the)227 1835 y(next)38 b(higher)f(dimension)g(of)h(the)
+f(FITS)g(N-dimensional)h(arra)m(y)-8 b(.)63 b(The)37
+b(INC)h(parameter)g(sp)s(eci\014es)f(the)227 1948 y(sampling)31
+b(in)m(terv)-5 b(al)31 b(in)f(eac)m(h)i(dimension)e(b)s(et)m(w)m(een)h
+(the)f(data)h(elemen)m(ts)h(that)f(will)g(b)s(e)e(returned.)95
+2212 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
+2325 y(ffgsv[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286 2438
+y(\(fitsfile)g(*fptr,)g(int)h(colnum,)e(int)i(naxis,)f(long)h(*naxes,)f
+(long)h(*fpixel,)334 2551 y(long)g(*lpixel,)e(long)i(*inc,)f(DTYPE)h
+(nulval,)e(>)j(DTYPE)e(*array,)g(int)h(*anynul,)334 2664
+y(int)g(*status\))0 2928 y Fi(4)81 b Fj(Read)24 b(an)g(arbitrary)g
+(data)h(subsection)f(from)g(an)g(N-dimensional)h(arra)m(y)g(in)f(a)g
+(binary)g(table)h(v)m(ector)h(column.)227 3041 y(An)m(y)34
+b(Unde\014ned)e(pixels)i(in)g(the)f(arra)m(y)i(will)f(ha)m(v)m(e)h(the)
+f(corresp)s(onding)e('n)m(ullarra)m(y')j(elemen)m(t)g(set)f(equal)227
+3154 y(to)40 b(TR)m(UE.)e(The)h(\014rst)e(and)h(last)i(ro)m(ws)e(in)h
+(the)f(table)i(to)f(b)s(e)f(read)h(are)g(sp)s(eci\014ed)e(b)m(y)i
+(fpixel\(naxis+1\))227 3267 y(and)i(lpixel\(naxis+1\),)47
+b(and)41 b(hence)h(are)g(treated)g(as)g(the)g(next)g(higher)g
+(dimension)f(of)h(the)g(FITS)f(N-)227 3379 y(dimensional)i(arra)m(y)-8
+b(.)78 b(The)41 b(INC)h(parameter)h(sp)s(eci\014es)f(the)h(sampling)f
+(in)m(terv)-5 b(al)44 b(in)e(eac)m(h)i(dimension)227
+3492 y(b)s(et)m(w)m(een)31 b(the)g(data)g(elemen)m(ts)h(that)f(will)f
+(b)s(e)g(returned.)95 3756 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 3869 y(ffgsf[b,i,ui,k,uk,j,uj,jj,)o(e,d)o(])286
+3982 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(int)i(naxis,)f(long)h
+(*naxes,)334 4095 y(long)g(*fpixel,)e(long)i(*lpixel,)e(long)i(*inc,)f
+(>)i(DTYPE)e(*array,)334 4208 y(char)h(*nullarray,)d(int)j(*anynul,)f
+(int)h(*status\))0 4472 y Fi(5)81 b Fj(Read)35 b(bit)g(v)-5
+b(alues)35 b(from)g(a)g(b)m(yte)h(\('B'\))g(or)f(bit)g(\(`X`\))h(table)
+g(column)f(\(in)g(the)g(CDU\).)h(Larra)m(y)g(is)f(an)f(arra)m(y)227
+4585 y(of)g(logical)i(v)-5 b(alues)34 b(corresp)s(onding)f(to)h(the)g
+(sequence)g(of)g(bits)g(to)g(b)s(e)f(read.)51 b(If)33
+b(larra)m(y)h(is)g(true)f(then)h(the)227 4698 y(corresp)s(onding)i(bit)
+h(w)m(as)g(set)h(to)f(1,)j(otherwise)d(the)g(bit)g(w)m(as)g(set)h(to)f
+(0.)61 b(The)37 b('X')g(column)g(in)f(a)i(FITS)227 4811
+y(table)e(is)e(alw)m(a)m(ys)i(padded)e(out)h(to)g(a)g(m)m(ultiple)g(of)
+g(8)g(bits)f(where)g(the)h(bit)g(arra)m(y)g(starts)g(with)f(the)h(most)
+227 4924 y(signi\014can)m(t)j(bit)e(of)h(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.)59
+b(F)-8 b(or)37 b(example,)i(a)e('4X')h(arra)m(y)-8 b(,)227
+5036 y(with)33 b(the)h(\014rst)e(bit)i(=)f(1)h(and)e(the)i(remaining)f
+(3)h(bits)f(=)g(0)h(is)f(equiv)-5 b(alen)m(t)35 b(to)f(the)g(8-bit)g
+(unsigned)e(b)m(yte)227 5149 y(v)-5 b(alue)31 b(of)f(128.)42
+b(Note)31 b(that)g(in)e(the)i(case)g(of)f('X')g(columns,)g(CFITSIO)f
+(can)h(read)g(all)h(8)f(bits)g(of)g(eac)m(h)h(b)m(yte)227
+5262 y(whether)h(they)h(are)g(formally)g(v)-5 b(alid)33
+b(or)f(not.)48 b(Th)m(us)31 b(if)i(the)f(column)h(is)f(de\014ned)f(as)i
+('4X',)h(and)e(one)h(calls)227 5375 y(\013gcx)d(with)f(\014rstbit=1)f
+(and)h(n)m(bits=8,)g(then)g(all)h(8)f(bits)g(will)g(b)s(e)g(read)g
+(from)f(the)h(\014rst)g(b)m(yte)g(\(as)h(opp)s(osed)227
+5488 y(to)39 b(reading)f(the)g(\014rst)g(4)g(bits)g(from)g(the)g
+(\014rst)f(ro)m(w)h(and)g(then)f(the)i(\014rst)e(4)h(bits)g(from)g(the)
+g(next)g(ro)m(w\),)227 5601 y(ev)m(en)g(though)f(the)g(last)i(4)e(bits)
+g(of)h(eac)m(h)g(b)m(yte)g(are)f(formally)h(not)g(de\014ned.)60
+b(It)37 b(should)f(also)i(b)s(e)f(noted)227 5714 y(that)f(it)f(is)h
+(more)f(e\016cien)m(t)h(to)g(read)f('X')h(columns)e(an)h(en)m(tire)h(b)
+m(yte)g(at)g(a)f(time,)i(instead)e(of)h(bit)f(b)m(y)g(bit.)p
+eop end
+%%Page: 116 124
+TeXDict begin 116 123 bop 0 299 a Fj(116)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)227 555 y Fj(An)m(y)f(of)g(the)h(CFITSIO)d(routines)i
+(that)g(read)g(columns)g(\(e.g.)42 b(\014ts)p 2520 555
+28 4 v 32 w(read)p 2724 555 V 33 w(col)p 2867 555 V 34
+w(b)m(yt\))29 b(ma)m(y)h(b)s(e)e(used)g(for)h(this)227
+668 y(purp)s(ose.)60 b(These)36 b(routines)i(will)f(in)m(terpret)h('X')
+f(columns)g(as)g(though)g(they)h(w)m(ere)f('B')h(columns)f(\(e.g.,)227
+781 y('8X')32 b(is)e(equiv)-5 b(alen)m(t)32 b(to)f('1B',)h(and)e('16X')
+i(is)e(equiv)-5 b(alen)m(t)32 b(to)f('2B'\).)95 1041
+y Fe(int)47 b(fits_read_col_bit)c(/)48 b(ffgcx)286 1154
+y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)f
+(LONGLONG)h(firstbit,)334 1267 y(LONGLONG)g(nbits,)g(>)h(char)g
+(*larray,)e(int)i(*status\))0 1526 y Fi(6)81 b Fj(Read)31
+b(an)m(y)h(consecutiv)m(e)i(set)e(of)g(bits)f(from)h(an)f('X')h(or)g
+('B')h(column)e(and)g(in)m(terpret)h(them)g(as)f(an)h(unsigned)227
+1639 y(n-bit)h(in)m(teger.)48 b(n)m(bits)33 b(m)m(ust)f(b)s(e)g(less)h
+(than)g(16)g(or)g(32)g(in)f(\013gcxui)i(and)d(\013gcxuk,)j(resp)s
+(ectiv)m(ely)-8 b(.)49 b(If)32 b(nro)m(ws)227 1752 y(is)c(greater)h
+(than)f(1,)h(then)e(the)h(same)h(set)f(of)g(bits)g(will)g(b)s(e)f(read)
+h(from)f(eac)m(h)i(ro)m(w,)g(starting)g(with)e(\014rstro)m(w.)227
+1865 y(The)j(bits)g(are)h(n)m(um)m(b)s(ered)e(with)h(1)h(=)f(the)h
+(most)f(signi\014can)m(t)i(bit)e(of)h(the)f(\014rst)g(elemen)m(t)i(of)e
+(the)h(column.)95 2125 y Fe(int)47 b(fits_read_col_bit_[usht,)42
+b(uint])k(/)h(ffgcx[ui,uk])286 2238 y(\(fitsfile)f(*fptr,)g(int)h
+(colnum,)e(LONGLONG)h(firstrow,)f(LONGLONG,)h(nrows,)334
+2351 y(long)h(firstbit,)e(long)i(nbits,)f(>)h(DTYPE)g(*array,)e(int)i
+(*status\))0 2611 y Fi(7)81 b Fj(Return)27 b(the)i(descriptor)f(for)h
+(a)g(v)-5 b(ariable)29 b(length)g(column)f(in)h(a)g(binary)e(table.)41
+b(The)28 b(descriptor)h(consists)g(of)227 2723 y(2)j(in)m(teger)g
+(parameters:)42 b(the)31 b(n)m(um)m(b)s(er)f(of)h(elemen)m(ts)i(in)d
+(the)h(arra)m(y)h(and)e(the)h(starting)h(o\013set)g(relativ)m(e)h(to)
+227 2836 y(the)c(start)h(of)e(the)h(heap.)40 b(The)29
+b(\014rst)f(pair)g(of)h(routine)g(returns)e(a)i(single)h(descriptor)e
+(whereas)h(the)g(second)227 2949 y(pair)34 b(of)h(routine)f(returns)g
+(the)g(descriptors)g(for)g(a)h(range)g(of)f(ro)m(ws)h(in)f(the)g
+(table.)54 b(The)34 b(only)g(di\013erence)227 3062 y(b)s(et)m(w)m(een)
+42 b(the)f(2)g(routines)f(in)h(eac)m(h)h(pair)e(is)h(that)g(one)g
+(returns)f(the)h(parameters)g(as)g('long')g(in)m(tegers,)227
+3175 y(whereas)30 b(the)h(other)g(returns)e(the)h(v)-5
+b(alues)31 b(as)g(64-bit)g('LONGLONG')g(in)m(tegers.)95
+3435 y Fe(int)47 b(fits_read_descript)c(/)48 b(ffgdes)286
+3548 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e(LONGLONG)h(rownum,)g(>)h
+(long)g(*repeat,)525 3661 y(long)g(*offset,)e(int)i(*status\))95
+3886 y(int)g(fits_read_descriptll)c(/)k(ffgdesll)286
+3999 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(LONGLONG)h(rownum,)g(>)h
+(LONGLONG)f(*repeat,)525 4112 y(LONGLONG)g(*offset,)f(int)i(*status\))
+95 4338 y(int)g(fits_read_descripts)c(/)k(ffgdess)286
+4451 y(\(fitsfile)f(*fptr,)g(int)h(colnum,)e(LONGLONG)h(firstrow,)f
+(LONGLONG)h(nrows)334 4564 y(>)i(long)e(*repeat,)g(long)g(*offset,)g
+(int)h(*status\))95 4790 y(int)g(fits_read_descriptsll)42
+b(/)48 b(ffgdessll)286 4903 y(\(fitsfile)e(*fptr,)g(int)h(colnum,)e
+(LONGLONG)h(firstrow,)f(LONGLONG)h(nrows)334 5016 y(>)i(LONGLONG)d
+(*repeat,)h(LONGLONG)f(*offset,)h(int)h(*status\))p eop
+end
+%%Page: 117 125
+TeXDict begin 117 124 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)g(the)
+h(name)f(of)h(the)g(data)g(\014le)f(to)h(b)s(e)f(op)s(ened)g(or)0
+2579 y(created)g(that)g(includes)f(the)h(follo)m(wing)h(features:)136
+2813 y Fc(\017)46 b Fj(CFITSIO)40 b(can)i(read)f(IRAF)h(format)g
+(images)g(whic)m(h)f(ha)m(v)m(e)i(header)e(\014le)h(names)f(that)h(end)
+f(with)g(the)227 2926 y('.imh')d(extension,)i(as)e(w)m(ell)g(as)g
+(reading)f(and)g(writing)g(FITS)g(\014les,)i(This)e(feature)h(is)f
+(implemen)m(ted)h(in)227 3039 y(CFITSIO)29 b(b)m(y)i(\014rst)e(con)m(v)
+m(erting)k(the)d(IRAF)h(image)h(in)m(to)f(a)g(temp)s(orary)f(FITS)g
+(format)h(\014le)f(in)g(memory)-8 b(,)227 3152 y(then)35
+b(op)s(ening)f(the)h(FITS)f(\014le.)54 b(An)m(y)35 b(of)g(the)g(usual)f
+(CFITSIO)g(routines)g(then)h(ma)m(y)g(b)s(e)f(used)g(to)i(read)227
+3265 y(the)31 b(image)g(header)f(or)h(data.)41 b(Similarly)-8
+b(,)31 b(ra)m(w)f(binary)g(data)h(arra)m(ys)f(can)h(b)s(e)f(read)g(b)m
+(y)g(con)m(v)m(erting)i(them)227 3378 y(on)f(the)f(\015y)g(in)m(to)h
+(virtual)g(FITS)f(images.)136 3557 y Fc(\017)46 b Fj(FITS)37
+b(\014les)g(on)g(the)g(In)m(ternet)h(can)f(b)s(e)g(read)g(\(and)g
+(sometimes)h(written\))f(using)g(the)g(FTP)-8 b(,)38
+b(HTTP)-8 b(,)37 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)g(can)h(b)s(e)f(pip)s(ed)f(b)s
+(et)m(w)m(een)i(tasks)f(on)h(the)f(stdin)g(and)g(stdout)g(streams.)136
+4028 y Fc(\017)46 b Fj(FITS)36 b(\014les)h(can)g(b)s(e)f(read)h(and)f
+(written)h(in)g(shared)f(memory)-8 b(.)60 b(This)36 b(can)h(p)s(oten)m
+(tially)i(ac)m(hiev)m(e)g(b)s(etter)227 4141 y(data)26
+b(I/O)e(p)s(erformance)g(compared)h(to)h(reading)f(and)f(writing)g(the)
+h(same)h(FITS)e(\014les)g(on)h(magnetic)h(disk.)136 4320
+y Fc(\017)46 b Fj(Compressed)30 b(FITS)f(\014les)i(in)f(gzip)h(or)f
+(Unix)g(COMPRESS)f(format)h(can)h(b)s(e)f(directly)h(read.)136
+4499 y Fc(\017)46 b Fj(Output)28 b(FITS)h(\014les)g(can)g(b)s(e)g
+(written)g(directly)h(in)e(compressed)h(gzip)h(format,)g(th)m(us)e(sa)m
+(ving)i(disk)f(space.)136 4678 y Fc(\017)46 b Fj(FITS)26
+b(table)h(columns)f(can)h(b)s(e)f(created,)i(mo)s(di\014ed,)f(or)f
+(deleted)h('on-the-\015y')g(as)g(the)g(table)g(is)f(op)s(ened)g(b)m(y)
+227 4791 y(CFITSIO.)32 b(This)h(creates)i(a)e(virtual)h(FITS)f(\014le)g
+(con)m(taining)i(the)f(mo)s(di\014cations)f(that)h(is)g(then)f(op)s
+(ened)227 4904 y(b)m(y)e(the)f(application)i(program.)136
+5083 y Fc(\017)46 b Fj(T)-8 b(able)29 b(ro)m(ws)e(ma)m(y)i(b)s(e)e
+(selected,)j(or)e(\014ltered)g(out,)g(on)g(the)g(\015y)f(when)g(the)h
+(table)h(is)f(op)s(ened)f(b)m(y)g(CFITSIO,)227 5196 y(based)22
+b(on)f(an)g(user-sp)s(eci\014ed)g(expression.)38 b(Only)21
+b(ro)m(ws)g(for)g(whic)m(h)h(the)g(expression)f(ev)-5
+b(aluates)23 b(to)f('TR)m(UE')227 5309 y(are)31 b(retained)g(in)f(the)g
+(cop)m(y)i(of)e(the)h(table)g(that)g(is)f(op)s(ened)g(b)m(y)g(the)h
+(application)g(program.)136 5488 y Fc(\017)46 b Fj(Histogram)28
+b(images)g(ma)m(y)f(b)s(e)f(created)h(on)f(the)h(\015y)f(b)m(y)g
+(binning)g(the)g(v)-5 b(alues)27 b(in)f(table)i(columns,)f(resulting)
+227 5601 y(in)36 b(a)g(virtual)h(N-dimensional)f(FITS)g(image.)59
+b(The)35 b(application)i(program)f(then)g(only)g(sees)g(the)h(FITS)227
+5714 y(image)32 b(\(in)e(the)h(primary)e(arra)m(y\))j(instead)e(of)h
+(the)f(original)i(FITS)d(table.)1882 5942 y(117)p eop
+end
+%%Page: 118 126
+TeXDict begin 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)0
+555 y Fj(The)39 b(latter)i(3)f(table)h(\014ltering)f(features)g(in)f
+(particular)h(add)f(v)m(ery)h(p)s(o)m(w)m(erful)f(data)i(pro)s(cessing)
+e(capabilities)0 668 y(directly)33 b(in)m(to)g(CFITSIO,)e(and)h(hence)h
+(in)m(to)g(ev)m(ery)g(task)g(that)g(uses)f(CFITSIO)f(to)i(read)f(or)h
+(write)f(FITS)g(\014les.)0 781 y(F)-8 b(or)29 b(example,)g(these)f
+(features)h(transform)e(a)h(v)m(ery)g(simple)g(program)g(that)g(just)g
+(copies)g(an)g(input)f(FITS)g(\014le)h(to)0 894 y(a)c(new)f(output)h
+(\014le)g(\(lik)m(e)h(the)f(`\014tscop)m(y')h(program)e(that)i(is)e
+(distributed)g(with)h(CFITSIO\))e(in)m(to)j(a)f(m)m(ultipurp)s(ose)0
+1007 y(FITS)33 b(\014le)g(pro)s(cessing)g(to)s(ol.)51
+b(By)33 b(app)s(ending)f(fairly)i(simple)f(quali\014ers)g(on)m(to)h
+(the)g(name)f(of)h(the)f(input)g(FITS)0 1120 y(\014le,)45
+b(the)d(user)f(can)h(p)s(erform)e(quite)i(complex)h(table)f(editing)h
+(op)s(erations)f(\(e.g.,)k(create)d(new)e(columns,)k(or)0
+1233 y(\014lter)32 b(out)h(ro)m(ws)f(in)g(a)g(table\))i(or)e(create)i
+(FITS)d(images)j(b)m(y)e(binning)f(or)h(histogramming)h(the)g(v)-5
+b(alues)32 b(in)g(table)0 1346 y(columns.)47 b(In)32
+b(addition,)h(these)g(functions)f(ha)m(v)m(e)i(b)s(een)e(co)s(ded)g
+(using)g(new)g(state-of-the)j(art)e(algorithms)g(that)0
+1458 y(are,)e(in)f(some)h(cases,)g(10)h(-)e(100)i(times)f(faster)g
+(than)f(previous)g(widely)g(used)f(implemen)m(tations.)0
+1619 y(Before)34 b(describing)f(the)h(complete)h(syn)m(tax)f(for)f(the)
+h(extended)f(FITS)g(\014le)g(names)g(in)g(the)h(next)g(section,)h(here)
+0 1732 y(are)c(a)g(few)f(examples)h(of)f(FITS)g(\014le)g(names)h(that)f
+(giv)m(e)i(a)f(quic)m(k)g(o)m(v)m(erview)h(of)f(the)f(allo)m(w)m(ed)i
+(syn)m(tax:)136 2005 y Fc(\017)46 b Fe(myfile.fits)p
+Fj(:)38 b(the)30 b(simplest)h(case)g(of)g(a)g(FITS)e(\014le)i(on)f
+(disk)g(in)g(the)h(curren)m(t)f(directory)-8 b(.)136
+2207 y Fc(\017)46 b Fe(myfile.imh)p Fj(:)i(op)s(ens)34
+b(an)h(IRAF)g(format)g(image)i(\014le)e(and)f(con)m(v)m(erts)j(it)e(on)
+g(the)g(\015y)g(in)m(to)h(a)f(temp)s(orary)227 2320 y(FITS)30
+b(format)h(image)g(in)f(memory)h(whic)m(h)f(can)g(then)g(b)s(e)g(read)g
+(with)g(an)m(y)h(other)g(CFITSIO)e(routine.)136 2521
+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)e(data)i(arra)m(y)g(\(a)g(512)g(x)f(512)i(short)e
+(in)m(teger)h(arra)m(y)g(in)227 2634 y(this)i(case\))i(and)d(con)m(v)m
+(erts)j(it)e(on)g(the)g(\015y)g(in)m(to)h(a)f(temp)s(orary)g(FITS)f
+(format)h(image)i(in)d(memory)h(whic)m(h)227 2747 y(can)e(then)f(b)s(e)
+g(read)g(with)g(an)m(y)h(other)f(CFITSIO)f(routine.)136
+2948 y Fc(\017)46 b Fe(myfile.fits.gz)p Fj(:)d(if)33
+b(this)g(is)g(the)g(name)g(of)h(a)f(new)g(output)g(\014le,)h(the)f
+('.gz')i(su\016x)d(will)h(cause)h(it)g(to)g(b)s(e)227
+3061 y(compressed)c(in)g(gzip)h(format)g(when)e(it)i(is)g(written)f(to)
+h(disk.)136 3263 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)f(\014le)
+g(m)m(y\014le.\014ts)h(then)f(mo)m(v)m(es)227 3376 y(to)31
+b(the)g(extension)g(with)f(the)h(k)m(eyw)m(ords)f(EXTNAME)h(=)f
+('EVENTS')g(and)g(EXTVER)g(=)g(2.)136 3577 y Fc(\017)46
+b Fe(-)p Fj(:)40 b(a)30 b(dash)f(\(min)m(us)g(sign\))h(signi\014es)g
+(that)g(the)g(input)f(\014le)g(is)h(to)g(b)s(e)f(read)h(from)f(the)h
+(stdin)f(\014le)h(stream,)g(or)227 3690 y(that)d(the)g(output)f(\014le)
+h(is)f(to)h(b)s(e)f(written)h(to)g(the)g(stdout)f(stream.)40
+b(See)27 b(also)g(the)g(stream://)h(driv)m(er)e(whic)m(h)227
+3803 y(pro)m(vides)37 b(a)f(more)h(e\016cien)m(t,)i(but)d(more)g
+(restricted)h(metho)s(d)f(of)h(reading)f(or)g(writing)h(to)g(the)f
+(stdin)g(or)227 3916 y(stdout)31 b(streams.)136 4117
+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)h(in)g(an)m(y)h(ftp)e(arc)m(hiv)m(e)j
+(site)f(on)f(the)227 4230 y(In)m(ternet)31 b(ma)m(y)g(b)s(e)f(directly)
+h(op)s(ened)e(with)h(read-only)h(access.)136 4432 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)28 b(URL)f(to)h(a)g(FITS)e(\014le)i
+(on)f(the)227 4545 y(W)-8 b(eb)31 b(ma)m(y)g(b)s(e)f(op)s(ened)g(with)g
+(read-only)g(access.)136 4746 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)36 b(to)g(ftp)f(access)i(except)f(that)g(it)g(pro-)227
+4859 y(vides)30 b(write)h(as)f(w)m(ell)h(as)g(read)f(access)h(to)g(the)
+f(\014les)h(across)f(the)h(net)m(w)m(ork.)41 b(This)29
+b(uses)h(the)h(ro)s(ot)f(proto)s(col)227 4972 y(dev)m(elop)s(ed)h(at)g
+(CERN.)136 5174 y Fc(\017)46 b Fe(shmem://h2[events])p
+Fj(:)j(op)s(ens)36 b(the)i(FITS)e(\014le)h(in)g(a)g(shared)f(memory)h
+(segmen)m(t)h(and)f(mo)m(v)m(es)h(to)g(the)227 5287 y(EVENTS)30
+b(extension.)136 5488 y Fc(\017)46 b Fe(mem://)p Fj(:)65
+b(creates)44 b(a)g(scratc)m(h)g(output)f(\014le)g(in)g(core)h(computer)
+f(memory)-8 b(.)79 b(The)43 b(resulting)g('\014le')h(will)227
+5601 y(disapp)s(ear)25 b(when)f(the)i(program)f(exits,)i(so)f(this)f
+(is)h(mainly)f(useful)g(for)g(testing)i(purp)s(oses)c(when)i(one)g(do)s
+(es)227 5714 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.)p eop end
+%%Page: 119 127
+TeXDict begin 119 126 bop 0 299 a Fh(10.1.)73 b(O)m(VER)-10
+b(VIEW)2995 b Fj(119)136 555 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)g
+(con)m(tained)h(in)e(the)h(10th)g(ro)m(w)f(of)h(the)227
+668 y('Images')38 b(column)f(in)g(the)g(binary)f(table)i(in)e(the)h
+(3th)g(extension)h(of)f(the)g(FITS)f(\014le.)60 b(The)37
+b(virtual)g(\014le)227 781 y(that)31 b(is)g(op)s(ened)e(b)m(y)i(the)f
+(application)i(just)e(con)m(tains)h(this)f(single)h(image)h(in)e(the)h
+(primary)e(arra)m(y)-8 b(.)136 973 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)h(of)g(the)f(input)f(image)i(ranging)f(from)f(the)h(1st)
+227 1086 y(to)k(the)f(512th)h(pixel)f(in)g(X)g(and)g(Y,)g(and)f
+(selects)j(ev)m(ery)e(second)g(pixel)h(in)e(b)s(oth)g(dimensions,)i
+(resulting)227 1198 y(in)30 b(a)h(256)h(x)e(256)i(pixel)e(input)g
+(image)h(in)g(this)f(case.)136 1390 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)h(\014le)f(on)227
+1503 y(the)h(\015y)f(that)i(is)f(iden)m(tical)h(to)g(m)m
+(y\014le.\014ts)f(except)g(that)h(it)f(will)g(con)m(tain)h(a)f(new)g
+(column)f(in)h(the)g(EVENTS)227 1616 y(extension)41 b(called)h('Rad')f
+(whose)f(v)-5 b(alue)41 b(is)g(computed)f(using)h(the)f(indicated)h
+(expression)g(whic)m(h)f(is)h(a)227 1729 y(function)30
+b(of)h(the)f(v)-5 b(alues)31 b(in)f(the)h(X)f(and)g(Y)h(columns.)136
+1920 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)f(FITS)f
+(\014les)h(that)g(is)g(iden)m(tical)i(to)227 2033 y('m)m
+(y\014le.\014ts')40 b(except)h(that)f(the)f(EVENTS)g(table)h(will)g
+(only)f(con)m(tain)i(the)e(ro)m(ws)h(that)g(ha)m(v)m(e)g(v)-5
+b(alues)40 b(of)227 2146 y(the)34 b(PHA)g(column)g(greater)h(than)e(5.)
+52 b(In)33 b(general,)j(an)m(y)e(arbitrary)g(b)s(o)s(olean)f
+(expression)h(using)f(a)i(C)e(or)227 2259 y(F)-8 b(ortran-lik)m(e)31
+b(syn)m(tax,)e(whic)m(h)f(ma)m(y)h(com)m(bine)g(AND)g(and)f(OR)f(op)s
+(erators,)i(ma)m(y)g(b)s(e)f(used)f(to)i(select)h(ro)m(ws)227
+2372 y(from)g(a)h(table.)136 2564 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)f(arra)m(y)i(im-)227
+2677 y(age)38 b(whic)m(h)e(is)h(computed)f(on)g(the)h(\015y)f(b)m(y)g
+(binning)f(\(i.e,)40 b(computing)c(the)h(2-dimensional)g(histogram\))
+227 2789 y(of)d(the)f(v)-5 b(alues)34 b(in)f(the)h(X)g(and)e(Y)i
+(columns)f(of)h(the)f(EVENTS)g(extension.)50 b(In)33
+b(this)g(case)i(the)e(X)h(and)f(Y)227 2902 y(co)s(ordinates)h(range)g
+(from)f(1)h(to)g(2048)h(and)e(the)h(image)g(pixel)g(size)g(is)g(4)f
+(units)g(in)g(b)s(oth)g(dimensions,)h(so)227 3015 y(the)d(resulting)f
+(image)i(is)e(512)i(x)e(512)i(pixels)f(in)f(size.)136
+3207 y Fc(\017)46 b Fj(The)31 b(\014nal)g(example)i(com)m(bines)f(man)m
+(y)f(of)h(these)g(feature)g(in)m(to)g(one)g(complex)g(expression)f
+(\(it)i(is)e(brok)m(en)227 3320 y(in)m(to)h(sev)m(eral)f(lines)g(for)f
+(clarit)m(y\):)370 3576 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 3689 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 3801 y([bin)g(\(X,Y\)=32])227
+4057 y Fj(In)37 b(this)h(case,)j(CFITSIO)36 b(\(1\))j(copies)g(and)e
+(uncompresses)g(the)h(FITS)f(\014le)h(from)f(the)h(ftp)f(site)i(on)f
+(the)227 4170 y(legacy)g(mac)m(hine,)h(\(2\))e(mo)m(v)m(es)g(to)g(the)g
+('EVENTS')f(extension,)i(\(3\))f(calculates)i(a)d(new)g(column)g
+(called)227 4283 y('phacorr',)30 b(\(4\))f(selects)h(the)f(ro)m(ws)g
+(in)f(the)h(table)h(that)f(ha)m(v)m(e)h(phacorr)e(in)g(the)h(range)g(5)
+g(to)h(14,)g(and)e(\014nally)227 4396 y(\(5\))35 b(bins)d(the)h
+(remaining)g(ro)m(ws)g(on)h(the)f(X)g(and)g(Y)g(column)g(co)s
+(ordinates,)i(using)d(a)i(pixel)f(size)h(=)f(32)h(to)227
+4509 y(create)d(a)f(2D)g(image.)42 b(All)30 b(this)f(pro)s(cessing)g
+(is)h(completely)h(transparen)m(t)e(to)i(the)e(application)i(program,)
+227 4622 y(whic)m(h)f(simply)g(sees)h(the)g(\014nal)f(2-D)h(image)h(in)
+e(the)g(primary)g(arra)m(y)h(of)f(the)h(op)s(ened)f(\014le.)0
+4886 y(The)c(full)h(extended)g(CFITSIO)e(FITS)h(\014le)h(name)g(can)g
+(con)m(tain)h(sev)m(eral)g(di\013eren)m(t)g(comp)s(onen)m(ts)f(dep)s
+(ending)e(on)0 4998 y(the)31 b(con)m(text.)42 b(These)30
+b(comp)s(onen)m(ts)h(are)g(describ)s(ed)e(in)h(the)g(follo)m(wing)i
+(sections:)0 5262 y Fe(When)47 b(creating)e(a)j(new)f(file:)143
+5375 y(filetype://BaseFilename\(t)o(empl)o(ate)o(Name)o(\)[co)o(mpr)o
+(ess])0 5601 y(When)g(opening)e(an)j(existing)d(primary)h(array)g(or)i
+(image)e(HDU:)143 5714 y(filetype://BaseFilename\(o)o(utNa)o(me\))o
+([HDU)o(loca)o(tio)o(n][I)o(mage)o(Sec)o(tion)o(][pi)o(xFi)o(lter)o(])p
+eop end
+%%Page: 120 128
+TeXDict begin 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)0
+668 y Fe(When)47 b(opening)e(an)j(existing)d(table)i(HDU:)143
+781 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])0
+1010 y Fj(The)35 b(\014let)m(yp)s(e,)j(BaseFilename,)h(outName,)g
+(HDUlo)s(cation,)g(ImageSection,)g(and)c(pixFilter)i(comp)s(onen)m(ts,)
+g(if)0 1123 y(presen)m(t,)27 b(m)m(ust)f(b)s(e)g(giv)m(en)h(in)f(that)g
+(order,)h(but)e(the)i(colFilter,)i(ro)m(wFilter,)g(and)c(binSp)s(ec)g
+(sp)s(eci\014ers)g(ma)m(y)i(follo)m(w)0 1236 y(in)j(an)m(y)h(order.)42
+b(Regardless)31 b(of)g(the)g(order,)f(ho)m(w)m(ev)m(er,)i(the)f
+(colFilter)i(sp)s(eci\014er,)e(if)f(presen)m(t,)h(will)g(b)s(e)f(pro)s
+(cessed)0 1349 y(\014rst)g(b)m(y)g(CFITSIO,)f(follo)m(w)m(ed)j(b)m(y)e
+(the)h(ro)m(wFilter)h(sp)s(eci\014er,)e(and)f(\014nally)i(b)m(y)f(the)g
+(binSp)s(ec)f(sp)s(eci\014er.)0 1678 y Ff(10.2)136 b(Filet)l(yp)t(e)0
+1928 y Fj(The)37 b(t)m(yp)s(e)g(of)g(\014le)g(determines)g(the)g
+(medium)f(on)h(whic)m(h)g(the)g(\014le)g(is)h(lo)s(cated)g(\(e.g.,)i
+(disk)d(or)g(net)m(w)m(ork\))h(and,)0 2041 y(hence,)f(whic)m(h)e(in)m
+(ternal)h(device)g(driv)m(er)f(is)g(used)f(b)m(y)h(CFITSIO)f(to)i(read)
+f(and/or)g(write)g(the)g(\014le.)56 b(Curren)m(tly)0
+2154 y(supp)s(orted)29 b(t)m(yp)s(es)h(are)382 2383 y
+Fe(file://)93 b(-)48 b(file)e(on)i(local)e(magnetic)g(disk)g
+(\(default\))430 2496 y(ftp://)93 b(-)48 b(a)f(readonly)f(file)g
+(accessed)g(with)h(the)g(anonymous)e(FTP)i(protocol.)907
+2609 y(It)g(also)g(supports)93 b(ftp://username:password@)o(host)o(nam)
+o(e/..)o(.)907 2722 y(for)47 b(accessing)e(password-protected)e(ftp)k
+(sites.)382 2835 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 2948 y(supports)45
+b(username:password)e(just)k(like)g(the)g(ftp)g(driver.)907
+3060 y(Proxy)f(HTTP)h(servers)f(are)h(supported)e(using)h(the)h
+(http_proxy)907 3173 y(environment)e(variable)g(\(see)i(following)e
+(note\).)286 3286 y(stream://)93 b(-)48 b(special)e(driver)g(to)h(read)
+g(an)g(input)f(FITS)h(file)f(from)h(the)g(stdin)907 3399
+y(stream,)f(and/or)g(write)g(an)h(output)f(FITS)h(file)g(to)g(the)g
+(stdout)143 3512 y(stream.)94 b(This)46 b(driver)g(is)i(fragile)d(and)i
+(has)g(limited)143 3625 y(functionality)d(\(see)j(the)g(following)e
+(note\).)286 3738 y(gsiftp://)93 b(-)48 b(access)e(files)g(on)h(a)h
+(computational)c(grid)j(using)f(the)h(gridftp)907 3851
+y(protocol)e(in)j(the)e(Globus)h(toolkit)e(\(see)i(following)e(note\).)
+382 3964 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 4077 y(reading)f(files)g(over)h
+(the)g(network)e(\(see)i(following)e(note\).)334 4190
+y(shmem://)93 b(-)48 b(opens)e(or)h(creates)f(a)i(file)e(which)h
+(persists)e(in)i(the)g(computer's)907 4302 y(shared)f(memory)g(\(see)h
+(following)e(note\).)430 4415 y(mem://)93 b(-)48 b(opens)e(a)i
+(temporary)d(file)i(in)g(core)f(memory.)94 b(The)47 b(file)907
+4528 y(disappears)e(when)h(the)h(program)f(exits)h(so)g(this)f(is)i
+(mainly)907 4641 y(useful)e(for)h(test)f(purposes)g(when)h(a)g
+(permanent)e(output)h(file)907 4754 y(is)h(not)g(desired.)0
+4983 y Fj(If)35 b(the)h(\014let)m(yp)s(e)g(is)f(not)h(sp)s(eci\014ed,)h
+(then)e(t)m(yp)s(e)h(\014le://)h(is)e(assumed.)56 b(The)35
+b(double)g(slashes)h('//')h(are)f(optional)0 5096 y(and)30
+b(ma)m(y)h(b)s(e)e(omitted)j(in)e(most)h(cases.)0 5382
+y Fd(10.2.1)113 b(Notes)36 b(ab)s(out)j(HTTP)d(pro)m(xy)i(serv)m(ers)0
+5601 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)f(the)h(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 5714 y(serv)m(er)f(with)f(the)g(h)m
+(ttp)p 801 5714 28 4 v 33 w(pro)m(xy)g(en)m(vironmen)m(t)h(v)-5
+b(ariable.)42 b(F)-8 b(or)31 b(example)p eop end
+%%Page: 121 129
+TeXDict begin 121 128 bop 0 299 a Fh(10.2.)73 b(FILETYPE)3037
+b Fj(121)191 555 y Fe(setenv)46 b(http_proxy)f
+(http://heasarc.gsfc.nasa)o(.gov)o(:312)o(8)0 793 y Fj(will)38
+b(cause)g(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)g(a)g(FITS)f(\014le)0
+906 y(with)30 b(HTTP)-8 b(.)0 1194 y Fd(10.2.2)113 b(Notes)36
+b(ab)s(out)j(the)e(stream)h(\014let)m(yp)s(e)g(driv)m(er)0
+1413 y Fj(The)e(stream)h(driv)m(er)f(can)h(b)s(e)f(used)g(to)h
+(e\016cien)m(tly)i(read)d(a)h(FITS)f(\014le)h(from)f(the)h(stdin)f
+(\014le)g(stream)h(or)g(write)0 1525 y(a)44 b(FITS)e(to)i(the)g(stdout)
+f(\014le)g(stream.)80 b(Ho)m(w)m(ev)m(er,)49 b(b)s(ecause)43
+b(these)h(input)e(and)h(output)g(streams)g(m)m(ust)h(b)s(e)0
+1638 y(accessed)30 b(sequen)m(tially)-8 b(,)31 b(the)e(FITS)f(\014le)g
+(reading)h(or)f(writing)h(application)h(m)m(ust)e(also)i(read)e(and)g
+(write)h(the)g(\014le)0 1751 y(sequen)m(tially)-8 b(,)33
+b(at)e(least)g(within)f(the)h(tolerances)h(describ)s(ed)d(b)s(elo)m(w.)
+0 1911 y(CFITSIO)34 b(supp)s(orts)f(2)j(di\013eren)m(t)f(metho)s(ds)g
+(for)g(accessing)i(FITS)d(\014les)h(on)h(the)f(stdin)g(and)f(stdout)h
+(streams.)0 2024 y(The)c(original)i(metho)s(d,)f(whic)m(h)f(is)h(in)m
+(v)m(ok)m(ed)h(b)m(y)f(sp)s(ecifying)f(a)h(dash)f(c)m(haracter,)j("-",)
+g(as)d(the)h(name)g(of)g(the)g(\014le)0 2137 y(when)g(op)s(ening)g(or)h
+(creating)h(it,)g(w)m(orks)e(b)m(y)h(storing)g(a)g(complete)h(cop)m(y)g
+(of)f(the)g(en)m(tire)g(FITS)f(\014le)h(in)f(memory)-8
+b(.)0 2250 y(In)35 b(this)g(case,)k(when)34 b(reading)i(from)f(stdin,)i
+(CFITSIO)d(will)i(cop)m(y)h(the)e(en)m(tire)i(stream)f(in)m(to)h
+(memory)e(b)s(efore)0 2363 y(doing)c(an)m(y)h(pro)s(cessing)f(of)h(the)
+f(\014le.)44 b(Similarly)-8 b(,)32 b(when)f(writing)g(to)h(stdout,)g
+(CFITSIO)d(will)j(create)h(a)f(cop)m(y)g(of)0 2476 y(the)h(en)m(tire)g
+(FITS)f(\014le)g(in)h(memory)-8 b(,)33 b(b)s(efore)f(\014nally)h
+(\015ushing)e(it)i(out)f(to)i(the)e(stdout)h(stream)g(when)e(the)i
+(FITS)0 2589 y(\014le)g(is)g(closed.)49 b(Bu\013ering)33
+b(the)g(en)m(tire)h(FITS)e(\014le)h(in)g(this)f(w)m(a)m(y)i(allo)m(ws)g
+(the)f(application)i(to)e(randomly)g(access)0 2702 y(an)m(y)h(part)f
+(of)h(the)f(FITS)g(\014le,)i(in)e(an)m(y)h(order,)f(but)g(it)h(also)h
+(requires)e(that)h(the)f(user)g(ha)m(v)m(e)i(su\016cien)m(t)f(a)m(v)-5
+b(ailable)0 2815 y(memory)30 b(\(or)g(virtual)g(memory\))g(to)h(store)f
+(the)g(en)m(tire)h(\014le,)f(whic)m(h)f(ma)m(y)i(not)f(b)s(e)f(p)s
+(ossible)g(in)h(the)g(case)h(of)f(v)m(ery)0 2928 y(large)h(\014les.)0
+3088 y(The)e(new)m(er)g(stream)h(\014let)m(yp)s(e)g(pro)m(vides)f(a)h
+(more)f(memory-e\016cien)m(t)i(metho)s(d)e(of)h(accessing)h(FITS)d
+(\014les)h(on)h(the)0 3201 y(stdin)37 b(or)h(stdout)g(streams.)64
+b(Instead)38 b(of)g(storing)g(a)g(cop)m(y)h(of)f(the)g(en)m(tire)h
+(FITS)e(\014le)h(in)g(memory)-8 b(,)40 b(CFITSIO)0 3314
+y(only)32 b(uses)g(a)g(set)h(of)f(in)m(ternal)h(bu\013er)e(whic)m(h)h
+(b)m(y)g(default)g(can)g(store)h(40)g(FITS)e(blo)s(c)m(ks,)i(or)g(ab)s
+(out)e(100K)i(b)m(ytes)0 3427 y(of)f(the)f(FITS)g(\014le.)43
+b(The)31 b(application)i(program)e(m)m(ust)g(pro)s(cess)g(the)h(FITS)e
+(\014le)i(sequen)m(tially)h(from)e(b)s(eginning)0 3539
+y(to)h(end,)e(within)g(this)h(100K)h(bu\013er.)41 b(Generally)32
+b(sp)s(eaking)f(the)g(application)h(program)f(m)m(ust)f(conform)h(to)h
+(the)0 3652 y(follo)m(wing)g(restrictions:)136 3891 y
+Fc(\017)46 b Fj(The)36 b(program)f(m)m(ust)h(\014nish)e(reading)i(or)g
+(writing)f(the)h(header)g(k)m(eyw)m(ords)g(b)s(efore)f(reading)h(or)g
+(writing)227 4004 y(an)m(y)31 b(data)g(in)f(the)h(HDU.)136
+4184 y Fc(\017)46 b Fj(The)24 b(HDU)h(can)f(con)m(tain)i(at)e(most)h
+(ab)s(out)f(1400)h(header)f(k)m(eyw)m(ords.)39 b(This)24
+b(is)g(the)g(maxim)m(um)g(that)h(can)f(\014t)227 4297
+y(in)g(the)g(nominal)h(40)g(FITS)e(blo)s(c)m(k)i(bu\013er.)37
+b(In)24 b(principle,)h(this)f(limit)h(could)f(b)s(e)g(increased)g(b)m
+(y)g(recompiling)227 4410 y(CFITSIO)29 b(with)h(a)h(larger)g(bu\013er)e
+(limit,)j(whic)m(h)e(is)g(set)h(b)m(y)f(the)h(NIOBUF)g(parameter)g(in)f
+(\014tsio2.h.)136 4590 y Fc(\017)46 b Fj(The)32 b(program)g(m)m(ust)f
+(read)h(or)g(write)h(the)f(data)g(in)g(a)g(sequen)m(tial)i(manner)d
+(from)h(the)g(b)s(eginning)f(to)i(the)227 4703 y(end)26
+b(of)g(the)h(HDU.)g(Note)h(that)f(CFITSIO's)e(in)m(ternal)i(100K)g
+(bu\013er)e(allo)m(ws)j(a)e(little)j(latitude)e(in)f(meeting)227
+4816 y(this)31 b(requiremen)m(t.)136 4997 y Fc(\017)46
+b Fj(The)30 b(program)g(cannot)h(mo)m(v)m(e)h(bac)m(k)f(to)g(a)g
+(previous)f(HDU)h(in)f(the)h(FITS)e(\014le.)136 5177
+y Fc(\017)46 b Fj(Reading)c(or)f(writing)f(of)h(v)-5
+b(ariable)42 b(length)f(arra)m(y)h(columns)e(in)h(binary)f(tables)i(is)
+f(not)g(supp)s(orted)e(on)227 5290 y(streams,)29 b(b)s(ecause)f(this)g
+(requires)g(mo)m(ving)g(bac)m(k)h(and)f(forth)f(b)s(et)m(w)m(een)i(the)
+f(\014xed-length)g(p)s(ortion)g(of)g(the)227 5403 y(binary)i(table)h
+(and)f(the)g(follo)m(wing)i(heap)e(area)i(where)e(the)g(arra)m(ys)h
+(are)g(actually)h(stored.)136 5583 y Fc(\017)46 b Fj(Reading)25
+b(or)g(writing)f(of)h(tile-compressed)h(images)g(is)e(not)h(supp)s
+(orted)e(on)h(streams,)i(b)s(ecause)f(the)g(images)227
+5696 y(are)31 b(in)m(ternally)g(stored)g(using)f(v)-5
+b(ariable)31 b(length)g(arra)m(ys.)p eop end
+%%Page: 122 130
+TeXDict begin 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)0
+555 y Fd(10.2.3)113 b(Notes)36 b(ab)s(out)j(the)e(gsiftp)h(\014let)m
+(yp)s(e)0 774 y Fj(DEPENDENCIES:)c(Globus)h(to)s(olkit)h(\(2.4.3)g(or)f
+(higher\))f(\(GT\))h(should)f(b)s(e)g(installed.)53 b(There)34
+b(are)h(t)m(w)m(o)h(dif-)0 887 y(feren)m(t)31 b(w)m(a)m(ys)g(to)g
+(install)g(GT:)0 1047 y(1\))43 b(goto)h(the)f(globus)f(to)s(olkit)i(w)m
+(eb)e(page)i(www.globus.org)e(and)g(follo)m(w)h(the)g(do)m(wnload)g
+(and)e(compilation)0 1160 y(instructions;)0 1320 y(2\))j(goto)i(the)d
+(Virtual)i(Data)g(T)-8 b(o)s(olkit)45 b(w)m(eb)e(page)i(h)m
+(ttp://vdt.cs.wisc.edu/)g(and)e(follo)m(w)i(the)f(instructions)0
+1433 y(\(STR)m(ONGL)-8 b(Y)31 b(SUGGESTED\);)0 1593 y(Once)23
+b(a)h(globus)f(clien)m(t)h(has)f(b)s(een)g(installed)h(in)e(y)m(our)i
+(system)f(with)g(a)g(sp)s(eci\014c)g(\015a)m(v)m(our)h(it)f(is)g(p)s
+(ossible)g(to)h(compile)0 1706 y(and)30 b(install)h(the)g(CFITSIO)d
+(libraries.)41 b(Sp)s(eci\014c)30 b(con\014guration)h(\015ags)f(m)m
+(ust)h(b)s(e)e(used:)0 1866 y(1\))21 b({with-gsiftp[[=P)-8
+b(A)g(TH]])22 b(Enable)f(Globus)f(T)-8 b(o)s(olkit)21
+b(gsiftp)g(proto)s(col)g(supp)s(ort)d(P)-8 b(A)g(TH=GLOBUS)p
+3532 1866 28 4 v 33 w(LOCA)g(TION)0 1979 y(i.e.)42 b(the)30
+b(lo)s(cation)i(of)f(y)m(our)f(globus)g(installation)0
+2139 y(2\))h({with-gsiftp-\015a)m(v)m(our[[=P)-8 b(A)g(TH])33
+b(de\014nes)d(the)g(sp)s(eci\014c)g(Globus)h(\015a)m(v)m(our)f(ex.)41
+b(gcc32)0 2300 y(Both)31 b(the)g(\015ags)f(m)m(ust)g(b)s(e)g(used)g
+(and)f(it)i(is)g(mandatory)f(to)h(set)g(b)s(oth)f(the)g(P)-8
+b(A)g(TH)31 b(and)f(the)h(\015a)m(v)m(our.)0 2460 y(USA)m(GE:)g(T)-8
+b(o)31 b(access)h(\014les)e(on)g(a)h(gridftp)f(serv)m(er)g(it)h(is)g
+(necessary)f(to)i(use)e(a)g(gsiftp)h(pre\014x:)0 2620
+y(example:)41 b(gsiftp://remote)p 1003 2620 V 35 w(serv)m(er)p
+1271 2620 V 34 w(fqhn/directory/\014lename)0 2780 y(The)f(gridftp)g
+(driv)m(er)g(uses)g(a)g(lo)s(cal)i(bu\013er)d(on)i(a)f(temp)s(orary)g
+(\014le)h(the)f(\014le)h(is)f(lo)s(cated)i(in)e(the)g(/tmp)h(direc-)0
+2893 y(tory)-8 b(.)73 b(If)40 b(y)m(ou)h(ha)m(v)m(e)h(sp)s(ecial)g(p)s
+(ermissions)d(on)i(/tmp)g(or)g(y)m(ou)g(do)f(not)i(ha)m(v)m(e)g(a)f
+(/tmp)g(directory)-8 b(,)44 b(it)e(is)e(p)s(os-)0 3006
+y(sible)d(to)h(force)g(another)g(lo)s(cation)g(setting)h(the)e(GSIFTP)p
+2068 3006 V 32 w(TMPFILE)g(en)m(vironmen)m(t)h(v)-5 b(ariable)38
+b(\(ex.)62 b(exp)s(ort)0 3119 y(GSIFTP)p 347 3119 V 32
+w(TMPFILE=/y)m(our/lo)s(cation/y)m(ourtmp\014le\).)0
+3279 y(Grid)34 b(FTP)g(supp)s(orts)f(m)m(ulti)h(c)m(hannel)h(transfer.)
+52 b(By)35 b(default)f(a)h(single)g(c)m(hannel)g(transmission)f(is)g(a)
+m(v)-5 b(ailable.)0 3392 y(Ho)m(w)m(ev)m(er,)34 b(it)d(is)h(p)s
+(ossible)e(to)i(mo)s(dify)e(this)i(b)s(eha)m(vior)f(setting)h(the)f
+(GSIFTP)p 2691 3392 V 33 w(STREAMS)f(en)m(vironmen)m(t)h(v)-5
+b(ari-)0 3505 y(able)31 b(\(ex.)41 b(exp)s(ort)30 b(GSIFTP)p
+1016 3505 V 33 w(STREAMS=8\).)0 3790 y Fd(10.2.4)113
+b(Notes)36 b(ab)s(out)j(the)e(ro)s(ot)g(\014let)m(yp)s(e)0
+4009 y Fj(The)20 b(original)j(ro)s(otd)d(serv)m(er)h(can)h(b)s(e)e
+(obtained)h(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 4122 y(it)33 b(to)h(w)m(ork)f(correctly)h
+(with)e(CFITSIO)g(one)h(has)f(to)i(use)e(a)i(mo)s(di\014ed)d(v)m
+(ersion)j(whic)m(h)e(supp)s(orts)f(a)i(command)0 4235
+y(to)41 b(return)d(the)j(length)f(of)g(the)g(\014le.)70
+b(This)39 b(mo)s(di\014ed)f(v)m(ersion)j(is)f(a)m(v)-5
+b(ailable)42 b(in)e(ro)s(otd)f(sub)s(directory)g(in)h(the)0
+4348 y(CFITSIO)29 b(ftp)h(area)h(at)286 4577 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 4805 y Fj(This)j(small)g(serv)m(er)h(is)
+g(started)f(either)h(b)m(y)g(inetd)f(when)f(a)i(clien)m(t)h(requests)e
+(a)h(connection)h(to)f(a)f(ro)s(otd)h(serv)m(er)0 4918
+y(or)30 b(b)m(y)g(hand)f(\(i.e.)42 b(from)30 b(the)g(command)g(line\).)
+42 b(The)29 b(ro)s(otd)h(serv)m(er)h(w)m(orks)f(with)g(the)g(R)m(OOT)g
+(TNetFile)i(class.)0 5031 y(It)e(allo)m(ws)g(remote)h(access)f(to)h(R)m
+(OOT)e(database)h(\014les)f(in)g(either)h(read)g(or)f(write)h(mo)s(de.)
+40 b(By)30 b(default)f(TNetFile)0 5144 y(assumes)38 b(p)s(ort)g(432)h
+(\(whic)m(h)f(requires)g(ro)s(otd)g(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)h(inetd)f(add)g(the)0
+5257 y(follo)m(wing)32 b(line)f(to)g(/etc/services:)95
+5485 y Fe(rootd)238 b(432/tcp)0 5714 y Fj(and)30 b(to)h
+(/etc/inetd.conf,)i(add)d(the)g(follo)m(wing)i(line:)p
+eop end
+%%Page: 123 131
+TeXDict begin 123 130 bop 0 299 a Fh(10.2.)73 b(FILETYPE)3037
+b Fj(123)95 555 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 829 y
+Fj(F)-8 b(orce)30 b(inetd)e(to)h(reread)f(its)h(conf)f(\014le)g(with)g
+Fe(kill)47 b(-HUP)g(<pid)f(inetd>)p Fj(.)39 b(Y)-8 b(ou)28
+b(can)h(also)g(start)g(ro)s(otd)f(b)m(y)g(hand)0 942
+y(running)35 b(directly)i(under)d(y)m(our)j(priv)-5 b(ate)37
+b(accoun)m(t)g(\(no)g(ro)s(ot)g(system)f(privileges)h(needed\).)59
+b(F)-8 b(or)37 b(example)g(to)0 1054 y(start)e(ro)s(otd)g(listening)g
+(on)g(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)k(that)f(no)e(&)h(is)f(needed.)54 b(Ro)s(otd)0
+1167 y(will)31 b(go)g(in)m(to)g(bac)m(kground)f(b)m(y)h(itself.)95
+1441 y Fe(Rootd)47 b(arguments:)191 1554 y(-i)763 b(says)47
+b(we)g(were)f(started)g(by)h(inetd)191 1667 y(-p)g(port#)476
+b(specifies)45 b(a)j(different)d(port)i(to)g(listen)f(on)191
+1780 y(-d)h(level)476 b(level)46 b(of)i(debug)e(info)h(written)e(to)j
+(syslog)1050 1893 y(0)f(=)h(no)f(debug)f(\(default\))1050
+2005 y(1)h(=)h(minimum)1050 2118 y(2)f(=)h(medium)1050
+2231 y(3)f(=)h(maximum)0 2505 y Fj(Ro)s(otd)29 b(can)f(also)h(b)s(e)f
+(con\014gured)g(for)g(anon)m(ymous)g(usage)h(\(lik)m(e)h(anon)m(ymous)e
+(ftp\).)40 b(T)-8 b(o)29 b(setup)f(ro)s(otd)g(to)h(accept)0
+2618 y(anon)m(ymous)h(logins)h(do)g(the)f(follo)m(wing)i(\(while)f(b)s
+(eing)f(logged)i(in)e(as)g(ro)s(ot\):)143 2891 y Fe(-)48
+b(Add)f(the)f(following)g(line)g(to)i(/etc/passwd:)239
+3117 y(rootd:*:71:72:Anonymous)41 b(rootd:/var/spool/rootd:/b)o(in/)o
+(fals)o(e)239 3343 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 3456
+y(to)h(suite)f(your)h(system.)143 3681 y(-)h(Add)f(the)f(following)g
+(line)g(to)i(/etc/group:)239 3907 y(rootd:*:72:rootd)239
+4133 y(where)e(the)h(gid)g(must)f(match)h(the)g(gid)g(in)g
+(/etc/passwd.)143 4359 y(-)h(Create)e(the)h(directories:)239
+4585 y(mkdir)f(/var/spool/rootd)239 4698 y(mkdir)g
+(/var/spool/rootd/tmp)239 4811 y(chmod)g(777)h(/var/spool/rootd/tmp)239
+5036 y(Where)f(/var/spool/rootd)d(must)k(match)f(the)h(rootd)g(home)f
+(directory)g(as)239 5149 y(specified)f(in)i(the)g(rootd)f(/etc/passwd)f
+(entry.)143 5375 y(-)j(To)f(make)f(writeable)g(directories)e(for)j
+(anonymous)f(do,)h(for)f(example:)239 5601 y(mkdir)g
+(/var/spool/rootd/pub)239 5714 y(chown)g(rootd:rootd)f
+(/var/spool/rootd/pub)p eop end
+%%Page: 124 132
+TeXDict begin 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(That's)42 b(all.)76 b(Sev)m(eral)43 b(additional)g(remarks:)64
+b(y)m(ou)42 b(can)g(login)h(to)g(an)f(anon)m(ymous)f(serv)m(er)i
+(either)f(with)g(the)0 668 y(names)31 b("anon)m(ymous")h(or)f("ro)s
+(otd".)43 b(The)31 b(passw)m(ord)f(should)g(b)s(e)h(of)g(t)m(yp)s(e)g
+(user@host.do.main.)43 b(Only)30 b(the)h(@)0 781 y(is)e(enforced)f(for)
+h(the)f(time)i(b)s(eing.)39 b(In)28 b(anon)m(ymous)h(mo)s(de)f(the)g
+(top)h(of)g(the)g(\014le)f(tree)i(is)e(set)h(to)h(the)e(ro)s(otd)h
+(home)0 894 y(directory)-8 b(,)39 b(therefore)e(only)f(\014les)h(b)s
+(elo)m(w)f(the)h(home)f(directory)h(can)f(b)s(e)g(accessed.)60
+b(Anon)m(ymous)36 b(mo)s(de)g(only)0 1007 y(w)m(orks)30
+b(when)g(the)g(serv)m(er)h(is)f(started)h(via)g(inetd.)0
+1296 y Fd(10.2.5)113 b(Notes)36 b(ab)s(out)j(the)e(shmem)i(\014let)m
+(yp)s(e:)0 1515 y Fj(Shared)34 b(memory)h(\014les)g(are)g(curren)m(tly)
+g(supp)s(orted)e(on)i(most)h(Unix)f(platforms,)h(where)f(the)g(shared)f
+(memory)0 1627 y(segmen)m(ts)d(are)g(managed)g(b)m(y)f(the)g(op)s
+(erating)h(system)g(k)m(ernel)f(and)g(`liv)m(e')i(indep)s(enden)m(tly)d
+(of)i(pro)s(cesses.)40 b(They)0 1740 y(are)34 b(not)g(deleted)h(\(b)m
+(y)f(default\))g(when)f(the)h(pro)s(cess)f(whic)m(h)h(created)h(them)f
+(terminates,)h(although)g(they)f(will)0 1853 y(disapp)s(ear)e(if)h(the)
+h(system)f(is)g(reb)s(o)s(oted.)49 b(Applications)34
+b(can)g(create)h(shared)d(memory)h(\014les)g(in)g(CFITSIO)f(b)m(y)0
+1966 y(calling:)143 2214 y Fe(fit_create_file\(&fitsfile)o(ptr,)41
+b("shmem://h2",)j(&status\);)0 2462 y Fj(where)25 b(the)g(ro)s(ot)h
+(`\014le')f(names)h(are)f(curren)m(tly)g(restricted)h(to)g(b)s(e)f
+('h0',)i('h1',)g('h2',)g('h3',)f(etc.,)i(up)d(to)g(a)h(maxim)m(um)0
+2575 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)22 b(of)f(SHARED)p 1746 2575 28 4 v 33 w(MAXSEG)g(\(equal)h(to)f
+(16)h(b)m(y)f(default\).)38 b(This)20 b(is)h(a)g(protot)m(yp)s(e)0
+2688 y(implemen)m(tation)30 b(of)f(the)g(shared)f(memory)g(in)m
+(terface)i(and)e(a)h(more)g(robust)f(in)m(terface,)j(whic)m(h)d(will)h
+(ha)m(v)m(e)h(few)m(er)0 2801 y(restrictions)h(on)f(the)h(n)m(um)m(b)s
+(er)e(of)i(\014les)f(and)g(on)g(their)g(names,)h(ma)m(y)g(b)s(e)f(dev)m
+(elop)s(ed)g(in)g(the)h(future.)0 2961 y(When)23 b(op)s(ening)h(an)f
+(already)h(existing)h(FITS)e(\014le)h(in)f(shared)g(memory)h(one)g
+(calls)g(the)g(usual)g(CFITSIO)e(routine:)143 3209 y
+Fe(fits_open_file\(&fitsfilep)o(tr,)41 b("shmem://h7",)j(mode,)j
+(&status\))0 3457 y Fj(The)26 b(\014le)h(mo)s(de)g(can)g(b)s(e)f(READ)m
+(WRITE)h(or)g(READONL)-8 b(Y)28 b(just)e(as)h(with)f(disk)h(\014les.)39
+b(More)28 b(than)e(one)h(pro)s(cess)0 3570 y(can)35 b(op)s(erate)g(on)f
+(READONL)-8 b(Y)35 b(mo)s(de)f(\014les)h(at)g(the)f(same)h(time.)54
+b(CFITSIO)33 b(supp)s(orts)f(prop)s(er)h(\014le)i(lo)s(c)m(king)0
+3682 y(\(b)s(oth)27 b(in)h(READONL)-8 b(Y)29 b(and)e(READ)m(WRITE)h(mo)
+s(des\),)h(so)f(calls)h(to)f(\014ts)p 2572 3682 V 33
+w(op)s(en)p 2795 3682 V 32 w(\014le)g(ma)m(y)g(b)s(e)f(lo)s(c)m(k)m(ed)
+j(out)e(un)m(til)0 3795 y(another)j(other)f(pro)s(cess)g(closes)i(the)e
+(\014le.)0 3956 y(When)g(an)g(application)i(is)e(\014nished)f
+(accessing)j(a)e(FITS)g(\014le)g(in)g(a)h(shared)e(memory)h(segmen)m
+(t,)i(it)f(ma)m(y)g(close)g(it)0 4068 y(\(and)j(the)g(\014le)g(will)g
+(remain)f(in)h(the)g(system\))g(with)g(\014ts)p 1955
+4068 V 32 w(close)p 2173 4068 V 34 w(\014le,)h(or)f(delete)h(it)g(with)
+e(\014ts)p 3191 4068 V 33 w(delete)p 3455 4068 V 34 w(\014le.)51
+b(Ph)m(ys-)0 4181 y(ical)36 b(deletion)g(is)f(p)s(ostp)s(oned)e(un)m
+(til)j(the)f(last)g(pro)s(cess)g(calls)h(\013clos/\013delt.)56
+b(\014ts)p 2801 4181 V 32 w(delete)p 3064 4181 V 34 w(\014le)35
+b(tries)h(to)f(obtain)h(a)0 4294 y(READ)m(WRITE)e(lo)s(c)m(k)g(on)f
+(the)g(\014le)h(to)g(b)s(e)e(deleted,)j(th)m(us)e(it)h(can)f(b)s(e)g
+(blo)s(c)m(k)m(ed)h(if)f(the)h(ob)5 b(ject)34 b(w)m(as)f(not)h(op)s
+(ened)0 4407 y(in)c(READ)m(WRITE)h(mo)s(de.)0 4567 y(A)i(shared)f
+(memory)h(managemen)m(t)h(utilit)m(y)g(program)f(called)h(`smem',)f(is)
+g(included)f(with)h(the)g(CFITSIO)e(dis-)0 4680 y(tribution.)39
+b(It)27 b(can)g(b)s(e)f(built)h(b)m(y)g(t)m(yping)g(`mak)m(e)h(smem';)g
+(then)f(t)m(yp)s(e)g(`smem)f(-h')h(to)h(get)g(a)f(list)g(of)g(v)-5
+b(alid)27 b(options.)0 4793 y(Executing)37 b(smem)f(without)g(an)m(y)h
+(options)g(causes)f(it)h(to)g(list)g(all)g(the)g(shared)e(memory)i
+(segmen)m(ts)g(curren)m(tly)0 4906 y(residing)c(in)g(the)g(system)h
+(and)e(managed)i(b)m(y)f(the)h(shared)e(memory)h(driv)m(er.)49
+b(T)-8 b(o)34 b(get)g(a)g(list)g(of)f(all)h(the)g(shared)0
+5019 y(memory)c(ob)5 b(jects,)32 b(run)d(the)h(system)h(utilit)m(y)g
+(program)f(`ip)s(cs)h([-a]'.)0 5351 y Ff(10.3)136 b(Base)45
+b(Filename)0 5601 y Fj(The)31 b(base)g(\014lename)h(is)f(the)h(name)f
+(of)h(the)f(\014le)h(optionally)g(including)f(the)h(director/sub)s
+(directory)f(path,)h(and)0 5714 y(in)e(the)h(case)g(of)g(`ftp',)f(`h)m
+(ttp',)i(and)d(`ro)s(ot')j(\014let)m(yp)s(es,)e(the)h(mac)m(hine)g
+(iden)m(ti\014er.)41 b(Examples:)p eop end
+%%Page: 125 133
+TeXDict begin 125 132 bop 0 299 a Fh(10.3.)73 b(BASE)30
+b(FILENAME)2739 b Fj(125)191 555 y Fe(myfile.fits)191
+668 y(!data.fits)191 781 y(/data/myfile.fits)191 894
+y(fits.gsfc.nasa.gov/ftp/s)o(ampl)o(eda)o(ta/m)o(yfil)o(e.f)o(its.)o
+(gz)0 1120 y Fj(When)29 b(creating)h(a)f(new)f(output)h(\014le)g(on)g
+(magnetic)h(disk)e(\(of)i(t)m(yp)s(e)f(\014le://\))h(if)f(the)g(base)g
+(\014lename)g(b)s(egins)f(with)0 1233 y(an)34 b(exclamation)j(p)s(oin)m
+(t)d(\(!\))54 b(then)34 b(an)m(y)g(existing)i(\014le)e(with)g(that)h
+(same)g(basename)g(will)g(b)s(e)e(deleted)i(prior)f(to)0
+1346 y(creating)h(the)f(new)g(FITS)f(\014le.)51 b(Otherwise)34
+b(if)g(the)g(\014le)g(to)g(b)s(e)g(created)h(already)f(exists,)i(then)d
+(CFITSIO)g(will)0 1459 y(return)g(an)h(error)f(and)g(will)i(not)f(o)m
+(v)m(erwrite)h(the)f(existing)h(\014le.)52 b(Note)35
+b(that)g(the)f(exclamation)i(p)s(oin)m(t,)f(')10 b(!',)36
+b(is)e(a)0 1572 y(sp)s(ecial)28 b(UNIX)g(c)m(haracter,)j(so)d(if)f(it)i
+(is)f(used)f(on)g(the)h(command)g(line)g(rather)g(than)f(en)m(tered)h
+(at)h(a)f(task)h(prompt,)0 1685 y(it)j(m)m(ust)f(b)s(e)g(preceded)g(b)m
+(y)h(a)g(bac)m(kslash)g(to)g(force)g(the)g(UNIX)g(shell)f(to)h(pass)f
+(it)i(v)m(erbatim)f(to)g(the)g(application)0 1798 y(program.)0
+1958 y(If)24 b(the)i(output)e(disk)h(\014le)g(name)g(ends)f(with)g(the)
+h(su\016x)f('.gz',)k(then)d(CFITSIO)e(will)i(compress)g(the)g(\014le)g
+(using)g(the)0 2071 y(gzip)g(compression)f(algorithm)h(b)s(efore)f
+(writing)g(it)h(to)g(disk.)38 b(This)23 b(can)i(reduce)f(the)g(amoun)m
+(t)h(of)f(disk)g(space)h(used)0 2184 y(b)m(y)34 b(the)h(\014le.)53
+b(Note)36 b(that)f(this)g(feature)g(requires)f(that)h(the)f
+(uncompressed)g(\014le)g(b)s(e)g(constructed)h(in)f(memory)0
+2297 y(b)s(efore)c(it)h(is)f(compressed)g(and)g(written)h(to)g(disk,)f
+(so)g(it)h(can)g(fail)g(if)f(there)h(is)f(insu\016cien)m(t)h(a)m(v)-5
+b(ailable)33 b(memory)-8 b(.)0 2457 y(An)45 b(input)g(FITS)f(\014le)i
+(ma)m(y)g(b)s(e)f(compressed)g(with)h(the)f(gzip)h(or)g(Unix)f
+(compress)h(algorithms,)k(in)45 b(whic)m(h)0 2570 y(case)38
+b(CFITSIO)e(will)i(uncompress)e(the)i(\014le)g(on)f(the)h(\015y)e(in)m
+(to)j(a)f(temp)s(orary)f(\014le)g(\(in)h(memory)f(or)g(on)h(disk\).)0
+2683 y(Compressed)32 b(\014les)i(ma)m(y)g(only)f(b)s(e)g(op)s(ened)f
+(with)h(read-only)h(p)s(ermission.)49 b(When)33 b(sp)s(ecifying)g(the)h
+(name)f(of)h(a)0 2796 y(compressed)h(FITS)g(\014le)h(it)g(is)g(not)g
+(necessary)g(to)g(app)s(end)e(the)i(\014le)g(su\016x)e(\(e.g.,)39
+b(`.gz')e(or)f(`.Z'\).)g(If)f(CFITSIO)0 2908 y(cannot)24
+b(\014nd)e(the)h(input)f(\014le)i(name)f(without)g(the)g(su\016x,)h
+(then)f(it)h(will)g(automatically)i(searc)m(h)e(for)f(a)g(compressed)0
+3021 y(\014le)36 b(with)f(the)h(same)g(ro)s(ot)g(name.)57
+b(In)35 b(the)h(case)h(of)f(reading)g(ftp)f(and)g(h)m(ttp)h(t)m(yp)s(e)
+g(\014les,)h(CFITSIO)e(generally)0 3134 y(lo)s(oks)j(for)g(a)g
+(compressed)g(v)m(ersion)g(of)g(the)g(\014le)g(\014rst,)h(b)s(efore)e
+(trying)h(to)h(op)s(en)e(the)h(uncompressed)e(\014le.)64
+b(By)0 3247 y(default,)37 b(CFITSIO)e(copies)h(\(and)g(uncompressed)e
+(if)i(necessary\))g(the)g(ftp)f(or)h(h)m(ttp)g(FITS)f(\014le)g(in)m(to)
+i(memory)0 3360 y(on)f(the)g(lo)s(cal)h(mac)m(hine)f(b)s(efore)g(op)s
+(ening)f(it.)58 b(This)35 b(will)h(fail)g(if)g(the)g(lo)s(cal)h(mac)m
+(hine)g(do)s(es)e(not)h(ha)m(v)m(e)h(enough)0 3473 y(memory)g(to)h
+(hold)f(the)g(whole)h(FITS)e(\014le,)k(so)d(in)g(this)g(case,)k(the)c
+(output)g(\014lename)g(sp)s(eci\014er)g(\(see)h(the)g(next)0
+3586 y(section\))32 b(can)f(b)s(e)e(used)h(to)h(further)e(con)m(trol)j
+(ho)m(w)e(CFITSIO)f(reads)h(ftp)g(and)g(h)m(ttp)g(\014les.)0
+3746 y(If)i(the)h(input)f(\014le)h(is)g(an)g(IRAF)g(image)h(\014le)f
+(\(*.imh)g(\014le\))h(then)e(CFITSIO)f(will)j(automatically)h(con)m(v)m
+(ert)g(it)e(on)0 3859 y(the)27 b(\015y)g(in)m(to)h(a)g(virtual)f(FITS)f
+(image)j(b)s(efore)e(it)g(is)g(op)s(ened)g(b)m(y)g(the)g(application)i
+(program.)39 b(IRAF)27 b(images)i(can)0 3972 y(only)h(b)s(e)g(op)s
+(ened)g(with)g(READONL)-8 b(Y)31 b(\014le)f(access.)0
+4132 y(Similarly)-8 b(,)32 b(if)f(the)g(input)f(\014le)i(is)f(a)g(ra)m
+(w)g(binary)f(data)i(arra)m(y)-8 b(,)33 b(then)d(CFITSIO)g(will)h(con)m
+(v)m(ert)i(it)e(on)g(the)h(\015y)e(in)m(to)0 4245 y(a)38
+b(virtual)g(FITS)g(image)h(with)e(the)h(basic)h(set)f(of)g(required)f
+(header)h(k)m(eyw)m(ords)g(b)s(efore)g(it)g(is)g(op)s(ened)f(b)m(y)h
+(the)0 4358 y(application)32 b(program)f(\(with)g(READONL)-8
+b(Y)31 b(access\).)44 b(In)30 b(this)h(case)h(the)f(data)g(t)m(yp)s(e)g
+(and)g(dimensions)f(of)h(the)0 4471 y(image)d(m)m(ust)f(b)s(e)f(sp)s
+(eci\014ed)g(in)h(square)g(brac)m(k)m(ets)h(follo)m(wing)g(the)f
+(\014lename)g(\(e.g.)41 b(ra)m(w\014le.dat[ib512,512]\).)j(The)0
+4584 y(\014rst)30 b(c)m(haracter)i(\(case)f(insensitiv)m(e\))h
+(de\014nes)e(the)g(data)h(t)m(yp)s(e)g(of)f(the)h(arra)m(y:)239
+4810 y Fe(b)429 b(8-bit)46 b(unsigned)g(byte)239 4923
+y(i)381 b(16-bit)46 b(signed)g(integer)239 5036 y(u)381
+b(16-bit)46 b(unsigned)g(integer)239 5149 y(j)381 b(32-bit)46
+b(signed)g(integer)239 5262 y(r)h(or)g(f)143 b(32-bit)46
+b(floating)g(point)239 5375 y(d)381 b(64-bit)46 b(floating)g(point)0
+5601 y Fj(An)40 b(optional)h(second)f(c)m(haracter)i(sp)s(eci\014es)e
+(the)h(b)m(yte)f(order)g(of)g(the)h(arra)m(y)g(v)-5 b(alues:)60
+b(b)40 b(or)g(B)h(indicates)g(big)0 5714 y(endian)30
+b(\(as)g(in)g(FITS)f(\014les)h(and)f(the)h(nativ)m(e)i(format)e(of)g
+(SUN)g(UNIX)g(w)m(orkstations)h(and)f(Mac)h(PCs\))e(and)h(l)g(or)p
+eop end
+%%Page: 126 134
+TeXDict begin 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(L)27 b(indicates)i(little)g(endian)e(\(nativ)m(e)j(format)d
+(of)h(DEC)g(OSF)f(w)m(orkstations)h(and)f(IBM)h(PCs\).)40
+b(If)27 b(this)g(c)m(haracter)0 668 y(is)f(omitted)g(then)f(the)h(arra)
+m(y)g(is)g(assumed)f(to)h(ha)m(v)m(e)h(the)f(nativ)m(e)g(b)m(yte)h
+(order)e(of)h(the)f(lo)s(cal)i(mac)m(hine.)40 b(These)25
+b(data)0 781 y(t)m(yp)s(e)35 b(c)m(haracters)h(are)g(then)e(follo)m(w)m
+(ed)j(b)m(y)d(a)i(series)f(of)g(one)g(or)g(more)g(in)m(teger)h(v)-5
+b(alues)35 b(separated)h(b)m(y)e(commas)0 894 y(whic)m(h)41
+b(de\014ne)f(the)h(size)h(of)f(eac)m(h)h(dimension)f(of)g(the)g(ra)m(w)
+g(arra)m(y)-8 b(.)74 b(Arra)m(ys)41 b(with)f(up)g(to)i(5)f(dimensions)g
+(are)0 1007 y(curren)m(tly)31 b(supp)s(orted.)41 b(Finally)-8
+b(,)33 b(a)e(b)m(yte)h(o\013set)g(to)g(the)f(p)s(osition)h(of)f(the)g
+(\014rst)f(pixel)i(in)f(the)g(data)h(\014le)f(ma)m(y)h(b)s(e)0
+1120 y(sp)s(eci\014ed)h(b)m(y)g(separating)i(it)f(with)f(a)h(':')48
+b(from)33 b(the)h(last)g(dimension)f(v)-5 b(alue.)51
+b(If)33 b(omitted,)j(it)e(is)f(assumed)g(that)0 1233
+y(the)i(o\013set)h(=)f(0.)54 b(This)35 b(parameter)g(ma)m(y)h(b)s(e)e
+(used)g(to)i(skip)e(o)m(v)m(er)i(an)m(y)g(header)e(information)i(in)e
+(the)h(\014le)g(that)0 1346 y(precedes)30 b(the)h(binary)f(data.)41
+b(F)-8 b(urther)30 b(examples:)95 1603 y Fe(raw.dat[b10000])521
+b(1-dimensional)45 b(10000)h(pixel)g(byte)h(array)95
+1715 y(raw.dat[rb400,400,12])233 b(3-dimensional)45 b(floating)g(point)
+h(big-endian)f(array)95 1828 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
+1941 y(a)i(FITS)e(file,)h(skipping)e(over)i(the)g(2880)g(byte)f(header)
+0 2198 y Fj(One)25 b(sp)s(ecial)g(case)h(of)f(input)f(\014le)h(is)g
+(where)g(the)g(\014lename)g(=)g(`-')h(\(a)f(dash)g(or)g(min)m(us)f
+(sign\))h(or)g('stdin')g(or)g('stdout',)0 2311 y(whic)m(h)d
+(signi\014es)h(that)h(the)f(input)e(\014le)i(is)g(to)h(b)s(e)e(read)g
+(from)h(the)g(stdin)f(stream,)j(or)e(written)f(to)i(the)f(stdout)g
+(stream)0 2424 y(if)34 b(a)g(new)g(output)f(\014le)h(is)g(b)s(eing)g
+(created.)52 b(In)33 b(the)h(case)h(of)f(reading)h(from)e(stdin,)h
+(CFITSIO)f(\014rst)g(copies)i(the)0 2537 y(whole)g(stream)h(in)m(to)g
+(a)f(temp)s(orary)g(FITS)f(\014le)i(\(in)f(memory)g(or)g(on)g(disk\),)h
+(and)f(subsequen)m(t)f(reading)h(of)h(the)0 2650 y(FITS)c(\014le)h(o)s
+(ccurs)g(in)f(this)h(cop)m(y)-8 b(.)49 b(When)33 b(writing)g(to)g
+(stdout,)h(CFITSIO)d(\014rst)h(constructs)h(the)g(whole)g(\014le)g(in)0
+2763 y(memory)h(\(since)i(random)d(access)j(is)e(required\),)i(then)e
+(\015ushes)f(it)i(out)g(to)g(the)f(stdout)h(stream)g(when)e(the)i
+(\014le)0 2876 y(is)30 b(closed.)42 b(In)29 b(addition,)i(if)f(the)g
+(output)g(\014lename)g(=)g('-.gz')i(or)e('stdout.gz')h(then)f(it)h
+(will)f(b)s(e)g(gzip)g(compressed)0 2989 y(b)s(efore)g(b)s(eing)g
+(written)g(to)h(stdout.)0 3149 y(This)25 b(abilit)m(y)j(to)e(read)g
+(and)f(write)h(on)g(the)g(stdin)g(and)f(stdout)h(steams)g(allo)m(ws)i
+(FITS)d(\014les)h(to)g(b)s(e)g(pip)s(ed)e(b)s(et)m(w)m(een)0
+3262 y(tasks)42 b(in)f(memory)g(rather)g(than)h(ha)m(ving)g(to)g
+(create)h(temp)s(orary)e(in)m(termediate)i(FITS)d(\014les)i(on)f(disk.)
+73 b(F)-8 b(or)0 3375 y(example)28 b(if)e(task1)i(creates)h(an)e
+(output)f(FITS)g(\014le,)i(and)f(task2)g(reads)g(an)g(input)f(FITS)g
+(\014le,)i(the)f(FITS)f(\014le)h(ma)m(y)0 3487 y(b)s(e)j(pip)s(ed)f(b)s
+(et)m(w)m(een)i(the)f(2)h(tasks)g(b)m(y)f(sp)s(ecifying)143
+3744 y Fe(task1)47 b(-)g(|)g(task2)g(-)0 4001 y Fj(where)30
+b(the)h(v)m(ertical)i(bar)e(is)f(the)h(Unix)g(piping)f(sym)m(b)s(ol.)42
+b(This)30 b(assumes)g(that)i(the)f(2)g(tasks)g(read)g(the)g(name)g(of)0
+4114 y(the)g(FITS)e(\014le)i(o\013)f(of)h(the)g(command)f(line.)0
+4448 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 4698 y Fj(An)36 b(optional)i(output)e(\014lename)h
+(ma)m(y)h(b)s(e)e(sp)s(eci\014ed)g(in)g(paren)m(theses)h(immediately)h
+(follo)m(wing)g(the)f(base)g(\014le)0 4811 y(name)28
+b(to)h(b)s(e)f(op)s(ened.)39 b(This)28 b(is)g(mainly)g(useful)g(in)g
+(those)g(cases)i(where)d(CFITSIO)g(creates)j(a)e(temp)s(orary)g(cop)m
+(y)0 4924 y(of)i(the)f(input)g(FITS)f(\014le)i(b)s(efore)f(it)h(is)f
+(op)s(ened)g(and)f(passed)h(to)h(the)g(application)h(program.)40
+b(This)28 b(happ)s(ens)g(b)m(y)0 5036 y(default)i(when)g(op)s(ening)g
+(a)g(net)m(w)m(ork)h(FTP)g(or)f(HTTP-t)m(yp)s(e)g(\014le,)h(when)e
+(reading)h(a)h(compressed)f(FITS)g(\014le)g(on)0 5149
+y(a)36 b(lo)s(cal)h(disk,)g(when)e(reading)h(from)g(the)g(stdin)f
+(stream,)j(or)d(when)g(a)i(column)e(\014lter,)j(ro)m(w)e(\014lter,)h
+(or)f(binning)0 5262 y(sp)s(eci\014er)29 b(is)g(included)g(as)h(part)f
+(of)g(the)h(input)f(\014le)g(sp)s(eci\014cation.)41 b(By)30
+b(default)g(this)f(temp)s(orary)g(\014le)g(is)h(created)0
+5375 y(in)g(memory)-8 b(.)41 b(If)29 b(there)h(is)g(not)g(enough)g
+(memory)g(to)h(create)g(the)g(\014le)f(cop)m(y)-8 b(,)31
+b(then)f(CFITSIO)e(will)i(exit)h(with)f(an)0 5488 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)g(to)h(b)s(e)e(created)i(on)f(disk,)g(instead)h(of)f(a)g(temp)s
+(orary)0 5601 y(\014le)38 b(in)f(memory)-8 b(,)40 b(b)m(y)d(supplying)f
+(the)i(name)g(in)f(paren)m(theses)h(immediately)h(follo)m(wing)g(the)e
+(base)h(\014le)g(name.)0 5714 y(The)30 b(output)g(\014lename)g(can)h
+(include)f(the)h(')10 b(!')41 b(clobb)s(er)30 b(\015ag.)p
+eop end
+%%Page: 127 135
+TeXDict begin 127 134 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(127)0 555 y(Th)m(us,)48 b(if)d(the)g(input)f(\014lename)h(to)g
+(CFITSIO)f(is:)70 b Fe(file1.fits.gz\(file2.fit)o(s\))39
+b Fj(then)44 b(CFITSIO)g(will)0 668 y(uncompress)39 b
+(`\014le1.\014ts.gz')j(in)m(to)f(the)f(lo)s(cal)h(disk)e(\014le)h
+(`\014le2.\014ts')h(b)s(efore)f(op)s(ening)f(it.)70 b(CFITSIO)38
+b(do)s(es)i(not)0 781 y(automatically)33 b(delete)f(the)e(output)g
+(\014le,)h(so)g(it)g(will)f(still)i(exist)f(after)g(the)f(application)i
+(program)e(exits.)0 941 y(The)i(output)h(\014lename)g("mem://")i(is)e
+(also)h(allo)m(w)m(ed,)i(whic)m(h)c(will)i(write)f(the)g(output)f
+(\014le)h(in)m(to)h(memory)-8 b(,)35 b(and)0 1054 y(also)28
+b(allo)m(w)g(write)f(access)h(to)g(the)f(\014le.)39 b(This)26
+b('\014le')i(will)f(disapp)s(ear)f(when)g(it)h(is)g(closed,)h(but)e
+(this)h(ma)m(y)h(b)s(e)e(useful)0 1167 y(for)k(some)h(applications)g
+(whic)m(h)g(only)f(need)g(to)h(mo)s(dify)f(a)h(temp)s(orary)f(cop)m(y)h
+(of)f(the)h(\014le.)0 1327 y(In)k(some)i(cases,)h(sev)m(eral)f
+(di\013eren)m(t)g(temp)s(orary)e(FITS)h(\014les)g(will)g(b)s(e)f
+(created)i(in)f(sequence,)i(for)e(instance,)i(if)0 1440
+y(one)f(op)s(ens)g(a)g(remote)h(\014le)f(using)g(FTP)-8
+b(,)37 b(then)g(\014lters)g(ro)m(ws)g(in)g(a)h(binary)e(table)i
+(extension,)i(then)c(create)j(an)0 1553 y(image)f(b)m(y)f(binning)f(a)h
+(pair)g(of)g(columns.)60 b(In)36 b(this)h(case,)j(the)d(remote)h
+(\014le)f(will)g(b)s(e)f(copied)h(to)h(a)f(temp)s(orary)0
+1666 y(lo)s(cal)j(\014le,)h(then)d(a)h(second)f(temp)s(orary)h(\014le)f
+(will)h(b)s(e)f(created)i(con)m(taining)g(the)e(\014ltered)h(ro)m(ws)f
+(of)h(the)g(table,)0 1779 y(and)c(\014nally)g(a)h(third)e(temp)s(orary)
+h(\014le)h(con)m(taining)g(the)g(binned)e(image)i(will)g(b)s(e)f
+(created.)57 b(In)34 b(cases)i(lik)m(e)h(this)0 1892
+y(where)28 b(m)m(ultiple)h(\014les)f(are)h(created,)h(the)e(out\014le)h
+(sp)s(eci\014er)f(will)g(b)s(e)g(in)m(terpreted)h(the)f(name)g(of)h
+(the)f(\014nal)g(\014le)h(as)0 2005 y(describ)s(ed)g(b)s(elo)m(w,)i(in)
+f(descending)g(priorit)m(y:)136 2266 y Fc(\017)46 b Fj(as)29
+b(the)g(name)g(of)g(the)g(\014nal)f(image)i(\014le)f(if)f(an)h(image)h
+(within)e(a)h(single)g(binary)f(table)i(cell)g(is)e(op)s(ened)g(or)h
+(if)227 2379 y(an)i(image)g(is)g(created)g(b)m(y)f(binning)g(a)g(table)
+i(column.)136 2568 y Fc(\017)46 b Fj(as)33 b(the)f(name)h(of)f(the)h
+(\014le)f(con)m(taining)i(the)e(\014ltered)g(table)i(if)e(a)h(column)f
+(\014lter)g(and/or)g(a)h(ro)m(w)f(\014lter)h(are)227
+2681 y(sp)s(eci\014ed.)136 2870 y Fc(\017)46 b Fj(as)31
+b(the)f(name)h(of)f(the)h(lo)s(cal)h(cop)m(y)f(of)f(the)h(remote)g(FTP)
+f(or)h(HTTP)e(\014le.)136 3059 y Fc(\017)46 b Fj(as)31
+b(the)g(name)g(of)g(the)f(uncompressed)g(v)m(ersion)h(of)g(the)f(FITS)g
+(\014le,)h(if)g(a)g(compressed)f(FITS)g(\014le)h(on)g(lo)s(cal)227
+3172 y(disk)f(has)g(b)s(een)g(op)s(ened.)136 3361 y Fc(\017)46
+b Fj(otherwise,)31 b(the)g(output)f(\014lename)g(is)h(ignored.)0
+3622 y(The)e(output)f(\014le)h(sp)s(eci\014er)g(is)g(useful)f(when)g
+(reading)h(FTP)g(or)g(HTTP-t)m(yp)s(e)g(FITS)f(\014les)h(since)g(it)h
+(can)f(b)s(e)g(used)0 3735 y(to)34 b(create)i(a)e(lo)s(cal)h(disk)e
+(cop)m(y)i(of)f(the)g(\014le)f(that)i(can)f(b)s(e)f(reused)g(in)g(the)h
+(future.)50 b(If)33 b(the)h(output)g(\014le)f(name)h(=)0
+3848 y(`*')i(then)e(a)i(lo)s(cal)g(\014le)f(with)g(the)g(same)g(name)g
+(as)g(the)h(net)m(w)m(ork)f(\014le)g(will)h(b)s(e)e(created.)56
+b(Note)36 b(that)f(CFITSIO)0 3961 y(will)30 b(b)s(eha)m(v)m(e)g
+(di\013eren)m(tly)h(dep)s(ending)d(on)i(whether)f(the)h(remote)g
+(\014le)g(is)g(compressed)f(or)h(not)g(as)g(sho)m(wn)f(b)m(y)h(the)0
+4074 y(follo)m(wing)i(examples:)136 4309 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)h(is)g(copied)g(to)227
+4422 y(the)d(lo)s(cal)h(compressed)f(\014le)g(`m)m(y\014le.\014ts.gz',)
+i(whic)m(h)d(is)h(then)g(uncompressed)e(in)i(lo)s(cal)h(memory)e(b)s
+(efore)227 4535 y(b)s(eing)f(op)s(ened)g(and)g(passed)f(to)j(the)e
+(application)i(program.)136 4724 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
+4837 y(is)d(copied)g(and)f(uncompressed)g(in)m(to)h(the)g(lo)s(cal)h
+(\014le)f(`m)m(y\014le.\014ts'.)57 b(This)35 b(example)h(requires)g
+(less)g(lo)s(cal)227 4950 y(memory)21 b(than)g(the)g(previous)f
+(example)i(since)f(the)g(\014le)g(is)g(uncompressed)e(on)i(disk)g
+(instead)g(of)g(in)f(memory)-8 b(.)136 5139 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)g(will)g(usually)g(pro)s(duce)f
+(an)227 5252 y(error)h(since)h(CFITSIO)e(itself)i(cannot)g(compress)f
+(\014les.)0 5488 y(The)36 b(exact)i(b)s(eha)m(vior)e(of)h(CFITSIO)e(in)
+h(the)h(latter)g(case)h(dep)s(ends)c(on)j(the)f(t)m(yp)s(e)h(of)g(ftp)f
+(serv)m(er)g(running)f(on)0 5601 y(the)c(remote)g(mac)m(hine)g(and)f
+(ho)m(w)g(it)h(is)f(con\014gured.)40 b(In)30 b(some)h(cases,)g(if)f
+(the)h(\014le)f(`m)m(y\014le.\014ts.gz')j(exists)e(on)f(the)0
+5714 y(remote)38 b(mac)m(hine,)h(then)e(the)g(serv)m(er)g(will)h(cop)m
+(y)f(it)h(to)f(the)h(lo)s(cal)g(mac)m(hine.)61 b(In)36
+b(other)h(cases)h(the)f(ftp)g(serv)m(er)p eop end
+%%Page: 128 136
+TeXDict begin 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(will)36 b(automatically)j(create)e(and)f(transmit)g(a)g
+(compressed)g(v)m(ersion)g(of)g(the)g(\014le)g(if)g(only)g(the)g
+(uncompressed)0 668 y(v)m(ersion)27 b(exists.)41 b(This)26
+b(can)h(get)h(rather)f(confusing,)h(so)f(users)f(should)g(use)h(a)g
+(certain)h(amoun)m(t)g(of)f(caution)h(when)0 781 y(using)34
+b(the)h(output)f(\014le)h(sp)s(eci\014er)f(with)h(FTP)f(or)h(HTTP)f
+(\014le)h(t)m(yp)s(es,)h(to)f(mak)m(e)h(sure)e(they)h(get)h(the)f(b)s
+(eha)m(vior)0 894 y(that)c(they)g(exp)s(ect.)0 1250 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 1504 y Fj(When)38 b(a)h(new)f(FITS)g(\014le)h(is)g
+(created)g(with)g(a)f(call)i(to)g(\014ts)p 2101 1504
+28 4 v 32 w(create)p 2369 1504 V 35 w(\014le,)g(the)f(name)g(of)g(a)g
+(template)h(\014le)e(ma)m(y)0 1617 y(b)s(e)h(supplied)g(in)h(paren)m
+(theses)g(immediately)h(follo)m(wing)g(the)g(name)f(of)g(the)g(new)f
+(\014le)h(to)h(b)s(e)e(created.)71 b(This)0 1730 y(template)27
+b(is)e(used)g(to)h(de\014ne)f(the)h(structure)f(of)h(one)f(or)h(more)g
+(HDUs)g(in)f(the)h(new)f(\014le.)39 b(The)25 b(template)i(\014le)e(ma)m
+(y)0 1843 y(b)s(e)32 b(another)h(FITS)f(\014le,)i(in)f(whic)m(h)f(case)
+i(the)f(newly)g(created)h(\014le)f(will)g(ha)m(v)m(e)h(exactly)h(the)e
+(same)g(k)m(eyw)m(ords)g(in)0 1956 y(eac)m(h)25 b(HDU)g(as)g(in)f(the)g
+(template)i(FITS)d(\014le,)j(but)d(all)j(the)e(data)h(units)e(will)i(b)
+s(e)f(\014lled)g(with)f(zeros.)40 b(The)24 b(template)0
+2069 y(\014le)i(ma)m(y)h(also)g(b)s(e)e(an)h(ASCI)s(I)e(text)j(\014le,)
+g(where)f(eac)m(h)h(line)f(\(in)g(general\))i(describ)s(es)d(one)h
+(FITS)f(k)m(eyw)m(ord)i(record.)0 2182 y(The)j(format)h(of)f(the)h
+(ASCI)s(I)e(template)i(\014le)g(is)f(describ)s(ed)f(in)i(the)f(follo)m
+(wing)i(T)-8 b(emplate)31 b(Files)h(c)m(hapter.)0 2538
+y Ff(10.6)136 b(Image)46 b(Tile-Compression)g(Sp)t(eci\014cation)0
+2792 y Fj(When)28 b(sp)s(ecifying)g(the)h(name)g(of)f(the)h(output)f
+(FITS)g(\014le)g(to)h(b)s(e)f(created,)i(the)f(user)f(can)g(indicate)i
+(that)f(images)0 2905 y(should)d(b)s(e)h(written)g(in)g
+(tile-compressed)h(format)g(\(see)g(section)g(5.5,)h(\\Primary)e(Arra)m
+(y)h(or)f(IMA)m(GE)h(Extension)0 3018 y(I/O)f(Routines"\))i(b)m(y)e
+(enclosing)h(the)g(compression)f(parameters)h(in)f(square)g(brac)m(k)m
+(ets)i(follo)m(wing)g(the)f(ro)s(ot)f(disk)0 3131 y(\014le)j(name.)41
+b(Here)31 b(are)g(some)g(examples)g(of)f(the)h(syn)m(tax)g(for)f(sp)s
+(ecifying)g(tile-compressed)i(output)e(images:)191 3410
+y Fe(myfile.fit[compress])185 b(-)48 b(use)f(Rice)f(algorithm)g(and)h
+(default)e(tile)i(size)191 3636 y(myfile.fit[compress)42
+b(GZIP])47 b(-)g(use)g(the)g(specified)e(compression)g(algorithm;)191
+3748 y(myfile.fit[compress)d(Rice])238 b(only)46 b(the)h(first)g
+(letter)f(of)h(the)g(algorithm)191 3861 y(myfile.fit[compress)42
+b(PLIO])238 b(name)46 b(is)i(required.)191 4087 y(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 4200 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
+4556 y Ff(10.7)136 b(HDU)45 b(Lo)t(cation)g(Sp)t(eci\014cation)0
+4811 y Fj(The)c(optional)h(HDU)h(lo)s(cation)g(sp)s(eci\014er)d
+(de\014nes)h(whic)m(h)g(HDU)h(\(Header-Data)i(Unit,)h(also)d(kno)m(wn)f
+(as)h(an)0 4924 y(`extension'\))36 b(within)d(the)i(FITS)e(\014le)h(to)
+h(initially)h(op)s(en.)51 b(It)34 b(m)m(ust)g(immediately)i(follo)m(w)f
+(the)f(base)h(\014le)f(name)0 5036 y(\(or)g(the)g(output)g(\014le)g
+(name)f(if)h(presen)m(t\).)52 b(If)33 b(it)h(is)g(not)g(sp)s(eci\014ed)
+g(then)f(the)h(\014rst)f(HDU)i(\(the)f(primary)f(arra)m(y\))0
+5149 y(is)g(op)s(ened.)46 b(The)32 b(HDU)h(lo)s(cation)h(sp)s
+(eci\014er)e(is)h(required)f(if)g(the)h(colFilter,)i(ro)m(wFilter,)g
+(or)e(binSp)s(ec)e(sp)s(eci\014ers)0 5262 y(are)f(presen)m(t,)f(b)s
+(ecause)h(the)f(primary)f(arra)m(y)i(is)f(not)h(a)f(v)-5
+b(alid)30 b(HDU)g(for)f(these)g(op)s(erations.)41 b(The)29
+b(HDU)h(ma)m(y)g(b)s(e)0 5375 y(sp)s(eci\014ed)e(either)i(b)m(y)e
+(absolute)i(p)s(osition)f(n)m(um)m(b)s(er,)f(starting)i(with)e(0)i(for)
+e(the)h(primary)f(arra)m(y)-8 b(,)31 b(or)e(b)m(y)f(reference)0
+5488 y(to)h(the)g(HDU)g(name,)g(and)f(optionally)-8 b(,)31
+b(the)e(v)m(ersion)g(n)m(um)m(b)s(er)e(and)h(the)h(HDU)g(t)m(yp)s(e)g
+(of)f(the)h(desired)f(extension.)0 5601 y(The)k(lo)s(cation)h(of)f(an)g
+(image)i(within)d(a)i(single)f(cell)i(of)e(a)g(binary)g(table)h(ma)m(y)
+f(also)h(b)s(e)f(sp)s(eci\014ed,)g(as)g(describ)s(ed)0
+5714 y(b)s(elo)m(w.)p eop end
+%%Page: 129 137
+TeXDict begin 129 136 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(129)0
+555 y(The)26 b(absolute)h(p)s(osition)f(of)g(the)h(extension)g(is)f(sp)
+s(eci\014ed)f(either)i(b)m(y)f(enclosed)h(the)g(n)m(um)m(b)s(er)e(in)h
+(square)f(brac)m(k)m(ets)0 668 y(\(e.g.,)k(`[1]')g(=)d(the)h(\014rst)f
+(extension)h(follo)m(wing)i(the)e(primary)e(arra)m(y\))j(or)f(b)m(y)f
+(preceded)h(the)g(n)m(um)m(b)s(er)e(with)i(a)g(plus)0
+781 y(sign)37 b(\(`+1'\).)63 b(T)-8 b(o)38 b(sp)s(ecify)f(the)g(HDU)h
+(b)m(y)g(name,)h(giv)m(e)g(the)e(name)h(of)f(the)h(desired)f(HDU)h
+(\(the)f(v)-5 b(alue)38 b(of)g(the)0 894 y(EXTNAME)e(or)g(HDUNAME)h(k)m
+(eyw)m(ord\))g(and)f(optionally)h(the)f(extension)h(v)m(ersion)f(n)m
+(um)m(b)s(er)f(\(v)-5 b(alue)37 b(of)f(the)0 1007 y(EXTVER)27
+b(k)m(eyw)m(ord\))i(and)e(the)h(extension)h(t)m(yp)s(e)e(\(v)-5
+b(alue)29 b(of)f(the)g(XTENSION)f(k)m(eyw)m(ord:)40 b(IMA)m(GE,)29
+b(ASCI)s(I)d(or)0 1120 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)i(enclosed)g(in)f
+(square)g(brac)m(k)m(ets.)56 b(If)34 b(the)h(v)-5 b(alue)0
+1233 y(of)34 b(EXTVER)f(and)f(XTENSION)h(are)h(not)f(sp)s(eci\014ed,)h
+(then)f(the)h(\014rst)e(extension)j(with)e(the)g(correct)i(v)-5
+b(alue)34 b(of)0 1346 y(EXTNAME)39 b(is)g(op)s(ened.)67
+b(The)38 b(extension)i(name)f(and)f(t)m(yp)s(e)i(are)f(not)h(case)g
+(sensitiv)m(e,)j(and)38 b(the)h(extension)0 1458 y(t)m(yp)s(e)29
+b(ma)m(y)g(b)s(e)f(abbreviated)h(to)g(a)g(single)g(letter)h(\(e.g.,)h
+(I)d(=)g(IMA)m(GE)i(extension)f(or)f(primary)g(arra)m(y)-8
+b(,)30 b(A)f(or)f(T)g(=)0 1571 y(ASCI)s(I)d(table)i(extension,)h(and)e
+(B)h(=)f(binary)g(table)h(BINT)-8 b(ABLE)27 b(extension\).)41
+b(If)26 b(the)g(HDU)h(lo)s(cation)i(sp)s(eci\014er)0
+1684 y(is)h(equal)h(to)g(`[PRIMAR)-8 b(Y]')32 b(or)f(`[P]',)g(then)f
+(the)h(primary)e(arra)m(y)i(\(the)g(\014rst)f(HDU\))h(will)g(b)s(e)f
+(op)s(ened.)0 1844 y(An)36 b(optional)j(p)s(ound)34 b(sign)j(c)m
+(haracter)i(\("#"\))f(ma)m(y)f(b)s(e)g(app)s(ended)e(to)i(the)g
+(extension)h(name)f(or)g(n)m(um)m(b)s(er)e(to)0 1957
+y(signify)e(that)h(an)m(y)g(other)f(extensions)h(in)f(the)g(\014le)g
+(should)g(b)s(e)f(ignored)h(during)f(an)m(y)i(subsequen)m(t)e(\014le)i
+(\014ltering)0 2070 y(op)s(erations.)83 b(F)-8 b(or)45
+b(example,)k(when)43 b(doing)i(ro)m(w)f(\014ltering)h(op)s(erations)f
+(on)h(a)f(table)i(extension,)i(CFITSIO)0 2183 y(normally)27
+b(creates)i(a)e(cop)m(y)h(of)f(the)g(\014ltered)g(table)h(in)f(memory)
+-8 b(,)28 b(along)h(with)d(a)i(v)m(erbatim)f(cop)m(y)h(of)f(all)h(the)g
+(other)0 2296 y(extensions)h(in)g(the)g(input)f(FITS)g(\014le.)41
+b(If)28 b(the)h(p)s(ound)e(sign)i(is)g(app)s(ended)e(to)j(the)f(table)h
+(extension)g(name,)f(then)0 2409 y(only)34 b(that)g(extension,)i(and)d
+(none)h(of)g(the)g(other)g(extensions)g(in)f(the)h(\014le,)h(will)g(b)m
+(y)e(copied)h(to)h(memory)-8 b(,)35 b(as)f(in)0 2522
+y(the)d(follo)m(wing)g(example:)143 2773 y Fe(myfile.fit[events#][TIME)
+41 b(>)48 b(10000])0 3024 y Fj(FITS)34 b(images)i(are)f(most)h
+(commonly)f(stored)g(in)g(the)g(primary)f(arra)m(y)h(or)g(an)g(image)h
+(extension,)h(but)d(images)0 3137 y(can)d(also)h(b)s(e)e(stored)h(as)h
+(a)f(v)m(ector)h(in)f(a)g(single)h(cell)g(of)f(a)h(binary)e(table)i
+(\(i.e.)43 b(eac)m(h)32 b(ro)m(w)f(of)g(the)h(v)m(ector)g(column)0
+3250 y(con)m(tains)d(a)g(di\013eren)m(t)f(image\).)42
+b(Suc)m(h)27 b(an)h(image)i(can)e(b)s(e)g(op)s(ened)f(with)h(CFITSIO)e
+(b)m(y)i(sp)s(ecifying)g(the)g(desired)0 3363 y(column)k(name)g(and)f
+(the)h(ro)m(w)g(n)m(um)m(b)s(er)f(after)h(the)g(binary)f(table)i(HDU)g
+(sp)s(eci\014er)e(as)h(sho)m(wn)g(in)f(the)h(follo)m(wing)0
+3476 y(examples.)71 b(The)40 b(column)g(name)h(is)f(separated)h(from)f
+(the)h(HDU)g(sp)s(eci\014er)f(b)m(y)g(a)h(semicolon)g(and)f(the)h(ro)m
+(w)0 3589 y(n)m(um)m(b)s(er)29 b(is)h(enclosed)h(in)e(paren)m(theses.)
+41 b(In)30 b(this)g(case)h(CFITSIO)d(copies)j(the)f(image)i(from)d(the)
+i(table)g(cell)g(in)m(to)0 3702 y(a)h(temp)s(orary)e(primary)h(arra)m
+(y)g(b)s(efore)g(it)h(is)f(op)s(ened.)43 b(The)30 b(application)j
+(program)e(then)g(just)g(sees)g(the)h(image)0 3815 y(in)i(the)h
+(primary)e(arra)m(y)-8 b(,)37 b(without)d(an)m(y)h(extensions.)53
+b(The)34 b(particular)g(ro)m(w)h(to)g(b)s(e)e(op)s(ened)h(ma)m(y)h(b)s
+(e)f(sp)s(eci\014ed)0 3927 y(either)28 b(b)m(y)f(giving)h(an)f
+(absolute)h(in)m(teger)h(ro)m(w)f(n)m(um)m(b)s(er)e(\(starting)i(with)f
+(1)h(for)f(the)g(\014rst)g(ro)m(w\),)i(or)e(b)m(y)g(sp)s(ecifying)0
+4040 y(a)33 b(b)s(o)s(olean)f(expression)g(that)h(ev)-5
+b(aluates)34 b(to)f(TR)m(UE)g(for)f(the)g(desired)g(ro)m(w.)47
+b(The)32 b(\014rst)f(ro)m(w)i(that)g(satis\014es)g(the)0
+4153 y(expression)28 b(will)g(b)s(e)g(used.)39 b(The)28
+b(ro)m(w)g(selection)i(expression)e(has)g(the)g(same)g(syn)m(tax)h(as)f
+(describ)s(ed)f(in)h(the)g(Ro)m(w)0 4266 y(Filter)k(Sp)s(eci\014er)d
+(section,)j(b)s(elo)m(w.)0 4426 y(Examples:)143 4677
+y Fe(myfile.fits[3])44 b(-)k(open)e(the)h(3rd)g(HDU)g(following)e(the)i
+(primary)f(array)143 4790 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
+4903 y(myfile.fits[EVENTS])f(-)k(open)g(the)g(extension)e(that)i(has)g
+(EXTNAME)e(=)j('EVENTS')143 5016 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 5129 y(myfile.fits[events,2,b])42 b(-)47 b(same,)f(but)h
+(also)g(requires)f(XTENSION)f(=)j('BINTABLE')143 5242
+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 5355 y(column)f(in)i(the)e(3rd)h
+(extension)f(of)h(the)g(file.)143 5468 y(myfile.fits[3;)d
+(images\(exposure)g(>)j(100\)])g(-)g(as)g(above,)f(but)h(opens)g(the)f
+(image)907 5581 y(in)h(the)g(first)f(row)h(that)g(has)g(an)g
+('exposure')e(column)h(value)907 5694 y(greater)g(than)g(100.)p
+eop end
+%%Page: 130 138
+TeXDict begin 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)0
+555 y Ff(10.8)136 b(Image)46 b(Section)0 811 y Fj(A)41
+b(virtual)g(\014le)f(con)m(taining)i(a)f(rectangular)h(subsection)e(of)
+h(an)g(image)g(can)g(b)s(e)f(extracted)i(and)e(op)s(ened)g(b)m(y)0
+924 y(sp)s(ecifying)32 b(the)h(range)g(of)g(pixels)g(\(start:end\))g
+(along)h(eac)m(h)g(axis)f(to)g(b)s(e)f(extracted)i(from)e(the)h
+(original)g(image.)0 1037 y(One)d(can)h(also)h(sp)s(ecify)e(an)h
+(optional)h(pixel)f(incremen)m(t)g(\(start:end:step\))h(for)f(eac)m(h)h
+(axis)f(of)g(the)g(input)e(image.)0 1149 y(A)f(pixel)f(step)h(=)f(1)h
+(will)g(b)s(e)f(assumed)f(if)i(it)g(is)f(not)h(sp)s(eci\014ed.)39
+b(If)27 b(the)h(start)g(pixel)g(is)f(larger)i(then)e(the)h(end)e
+(pixel,)0 1262 y(then)32 b(the)g(image)h(will)f(b)s(e)f(\015ipp)s(ed)f
+(\(pro)s(ducing)h(a)h(mirror)g(image\))h(along)g(that)f(dimension.)45
+b(An)32 b(asterisk,)h('*',)0 1375 y(ma)m(y)39 b(b)s(e)e(used)h(to)h(sp)
+s(ecify)f(the)g(en)m(tire)h(range)g(of)f(an)h(axis,)i(and)c('-*')j
+(will)e(\015ip)g(the)g(en)m(tire)h(axis.)65 b(The)38
+b(input)0 1488 y(image)31 b(can)f(b)s(e)f(in)g(the)h(primary)f(arra)m
+(y)-8 b(,)31 b(in)e(an)g(image)i(extension,)g(or)f(con)m(tained)g(in)g
+(a)g(v)m(ector)h(cell)g(of)f(a)g(binary)0 1601 y(table.)40
+b(In)25 b(the)h(later)h(2)f(cases)h(the)f(extension)h(name)f(or)f(n)m
+(um)m(b)s(er)g(m)m(ust)h(b)s(e)f(sp)s(eci\014ed)g(b)s(efore)h(the)g
+(image)h(section)0 1714 y(sp)s(eci\014er.)0 1874 y(Examples:)95
+2157 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 2270 y(consisting)e(of)i(the)g(odd)g
+(numbered)f(columns)g(\(1st)g(axis\))h(and)668 2383 y(the)g(even)g
+(numbered)e(rows)i(\(2nd)g(axis\))f(of)h(the)g(image)f(in)i(the)668
+2496 y(primary)e(array)g(of)i(the)e(file.)95 2721 y(myfile.fits[*,)e
+(512:256])i(-)h(open)g(an)g(image)g(consisting)e(of)i(all)g(the)g
+(columns)668 2834 y(in)g(the)g(input)g(image,)f(but)h(only)f(rows)h
+(256)g(through)f(512.)668 2947 y(The)h(image)f(will)h(be)g(flipped)f
+(along)g(the)h(2nd)g(axis)g(since)668 3060 y(the)g(starting)f(pixel)g
+(is)h(greater)f(than)h(the)g(ending)f(pixel.)95 3286
+y(myfile.fits[*:2,)e(512:256:2])h(-)i(same)g(as)g(above)f(but)h
+(keeping)f(only)668 3399 y(every)h(other)f(row)h(and)g(column)f(in)h
+(the)g(input)f(image.)95 3625 y(myfile.fits[-*,)e(*])j(-)h(copy)e(the)h
+(entire)f(image,)g(flipping)g(it)h(along)668 3738 y(the)g(first)f
+(axis.)95 3963 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
+4076 y(is)g(in)h(the)e(3rd)h(extension)f(of)h(the)g(file.)95
+4302 y(myfile.fits[4;)d(images\(12\)][1:10,1:10])e(-)48
+b(open)e(an)h(image)g(consisting)286 4415 y(of)h(the)e(first)h(10)g
+(pixels)f(in)h(both)g(dimensions.)e(The)i(original)286
+4528 y(image)g(resides)f(in)h(the)g(12th)f(row)h(of)g(the)g('images')f
+(vector)286 4641 y(column)g(in)i(the)f(table)f(in)h(the)g(4th)g
+(extension)e(of)i(the)g(file.)0 4924 y Fj(When)23 b(CFITSIO)f(op)s(ens)
+h(an)g(image)h(section)h(it)f(\014rst)f(creates)h(a)g(temp)s(orary)f
+(\014le)h(con)m(taining)h(the)e(image)i(section)0 5036
+y(plus)30 b(a)h(cop)m(y)h(of)f(an)m(y)g(other)g(HDUs)g(in)g(the)g
+(\014le.)42 b(\(If)31 b(a)g(`#')g(c)m(haracter)h(is)f(app)s(ended)e(to)
+j(the)f(name)f(or)h(n)m(um)m(b)s(er)0 5149 y(of)i(the)g(image)i(HDU,)e
+(as)h(in)e("m)m(y\014le.\014ts[1#][1:200,1:200)q(]",)40
+b(then)33 b(the)g(other)g(HDUs)h(in)e(the)h(input)g(\014le)g(will)0
+5262 y(not)j(b)s(e)f(copied)i(in)m(to)f(memory\).)58
+b(This)35 b(temp)s(orary)g(\014le)h(is)g(then)f(op)s(ened)h(b)m(y)f
+(the)h(application)h(program,)h(so)0 5375 y(it)32 b(is)g(not)f(p)s
+(ossible)h(to)g(write)g(to)g(or)f(mo)s(dify)g(the)h(input)e(\014le)i
+(when)f(sp)s(ecifying)g(an)g(image)i(section.)45 b(Note)33
+b(that)0 5488 y(CFITSIO)27 b(automatically)32 b(up)s(dates)c(the)h(w)m
+(orld)f(co)s(ordinate)i(system)f(k)m(eyw)m(ords)g(in)f(the)h(header)g
+(of)g(the)g(image)0 5601 y(section,)h(if)f(they)g(exist,)h(so)f(that)g
+(the)g(co)s(ordinate)h(asso)s(ciated)g(with)e(eac)m(h)i(pixel)f(in)g
+(the)g(image)h(section)g(will)f(b)s(e)0 5714 y(computed)h(correctly)-8
+b(.)p eop end
+%%Page: 131 139
+TeXDict begin 131 138 bop 0 299 a Fh(10.9.)73 b(IMA)m(GE)31
+b(TRANSF)m(ORM)f(FIL)-8 b(TERS)2147 b Fj(131)0 555 y
+Ff(10.9)136 b(Image)46 b(T)-11 b(ransform)44 b(Filters)0
+807 y Fj(CFITSIO)33 b(can)h(apply)g(a)h(user-sp)s(eci\014ed)e
+(mathematical)j(function)e(to)h(the)g(v)-5 b(alue)34
+b(of)h(ev)m(ery)g(pixel)f(in)g(a)h(FITS)0 920 y(image,)29
+b(th)m(us)e(creating)h(a)g(new)e(virtual)h(image)i(in)d(computer)h
+(memory)g(that)h(is)f(then)f(op)s(ened)h(and)f(read)h(b)m(y)g(the)0
+1033 y(application)32 b(program.)40 b(The)30 b(original)i(FITS)d(image)
+j(is)e(not)h(mo)s(di\014ed)e(b)m(y)h(this)h(pro)s(cess.)0
+1193 y(The)20 b(image)j(transformation)e(sp)s(eci\014er)f(is)h(app)s
+(ended)e(to)j(the)f(input)f(FITS)h(\014le)g(name)g(and)f(is)h(enclosed)
+h(in)e(square)0 1306 y(brac)m(k)m(ets.)42 b(It)29 b(b)s(egins)f(with)h
+(the)g(letters)i('PIX')e(to)h(distinguish)e(it)i(from)e(other)i(t)m(yp)
+s(es)f(of)g(FITS)f(\014le)h(\014lters)g(that)0 1419 y(are)36
+b(recognized)i(b)m(y)e(CFITSIO.)e(The)i(image)h(transforming)f
+(function)f(ma)m(y)i(use)f(an)m(y)g(of)g(the)h(mathematical)0
+1532 y(op)s(erators)44 b(listed)h(in)f(the)h(follo)m(wing)h('Ro)m(w)f
+(Filtering)g(Sp)s(eci\014cation')g(section)h(of)e(this)h(do)s(cumen)m
+(t.)82 b(Some)0 1645 y(examples)31 b(of)f(image)i(transform)e
+(\014lters)g(are:)48 1913 y Fe([pix)46 b(X)i(*)f(2.0])715
+b(-)48 b(multiply)d(each)i(pixel)f(by)h(2.0)48 2026 y([pix)f
+(sqrt\(X\)])714 b(-)48 b(take)e(the)h(square)f(root)h(of)g(each)g
+(pixel)48 2139 y([pix)f(X)i(+)f(#ZEROPT)571 b(-)48 b(add)e(the)h(value)
+g(of)g(the)g(ZEROPT)f(keyword)48 2252 y([pix)g(X>0)h(?)h(log10\(X\))d
+(:)j(-99.])e(-)i(if)f(the)g(pixel)f(value)g(is)i(greater)1480
+2365 y(than)e(0,)h(compute)f(the)h(base)g(10)g(log,)1480
+2478 y(else)f(set)h(the)g(pixel)f(=)i(-99.)0 2746 y Fj(Use)24
+b(the)g(letter)h('X')f(in)f(the)h(expression)g(to)g(represen)m(t)g(the)
+g(curren)m(t)f(pixel)h(v)-5 b(alue)24 b(in)f(the)h(image.)40
+b(The)23 b(expression)0 2859 y(is)38 b(ev)-5 b(aluated)39
+b(indep)s(enden)m(tly)e(for)g(eac)m(h)i(pixel)f(in)g(the)g(image)h(and)
+e(ma)m(y)h(b)s(e)g(a)g(function)f(of)h(1\))h(the)f(original)0
+2971 y(pixel)32 b(v)-5 b(alue,)32 b(2\))g(the)f(v)-5
+b(alue)32 b(of)f(other)h(pixels)f(in)g(the)g(image)i(at)f(a)f(giv)m(en)
+i(relativ)m(e)g(o\013set)f(from)f(the)g(p)s(osition)h(of)0
+3084 y(the)d(pixel)f(that)h(is)g(b)s(eing)f(ev)-5 b(aluated,)30
+b(and)e(3\))h(the)g(v)-5 b(alue)29 b(of)f(an)m(y)h(header)f(k)m(eyw)m
+(ords.)41 b(Header)29 b(k)m(eyw)m(ord)g(v)-5 b(alues)0
+3197 y(are)31 b(represen)m(ted)f(b)m(y)g(the)h(name)f(of)h(the)f(k)m
+(eyw)m(ord)h(preceded)f(b)m(y)h(the)f('#')h(sign.)0 3357
+y(T)-8 b(o)35 b(access)h(the)f(the)g(v)-5 b(alue)35 b(of)g(adjacen)m(t)
+h(pixels)f(in)f(the)h(image,)i(sp)s(ecify)e(the)g(\(1-D\))h(o\013set)g
+(from)e(the)h(curren)m(t)0 3470 y(pixel)c(in)f(curly)g(brac)m(k)m(ets.)
+42 b(F)-8 b(or)31 b(example)48 3738 y Fe([pix)94 b(\(x{-1})46
+b(+)i(x)f(+)h(x{+1}\))e(/)h(3])0 4006 y Fj(will)25 b(replace)g(eac)m(h)
+h(pixel)f(v)-5 b(alue)25 b(with)f(the)h(running)e(mean)i(of)f(the)h(v)
+-5 b(alues)25 b(of)g(that)g(pixel)g(and)f(it's)h(2)g(neigh)m(b)s(oring)
+0 4119 y(pixels.)40 b(Note)30 b(that)g(in)e(this)g(notation)i(the)f
+(image)h(is)f(treated)g(as)g(a)g(1-D)h(arra)m(y)-8 b(,)30
+b(where)e(eac)m(h)i(ro)m(w)f(of)g(the)g(image)0 4232
+y(\(or)c(higher)f(dimensional)g(cub)s(e\))h(is)f(app)s(ended)f(one)h
+(after)h(another)g(in)f(one)h(long)g(arra)m(y)g(of)f(pixels.)39
+b(It)25 b(is)f(p)s(ossible)0 4345 y(to)35 b(refer)f(to)h(pixels)f(in)g
+(the)g(ro)m(ws)g(ab)s(o)m(v)m(e)h(or)g(b)s(elo)m(w)f(the)g(curren)m(t)g
+(pixel)h(b)m(y)f(using)f(the)h(v)-5 b(alue)35 b(of)f(the)h(NAXIS1)0
+4458 y(header)30 b(k)m(eyw)m(ord.)41 b(F)-8 b(or)32 b(example)48
+4726 y Fe([pix)46 b(\(x{-#NAXIS1})f(+)i(x)h(+)f(x{#NAXIS1}\))e(/)i(3])0
+4994 y Fj(will)34 b(compute)f(the)h(mean)f(of)g(eac)m(h)i(image)f
+(pixel)g(and)e(the)i(pixels)f(immediately)i(ab)s(o)m(v)m(e)f(and)f(b)s
+(elo)m(w)g(it)h(in)f(the)0 5107 y(adjacen)m(t)27 b(ro)m(ws)f(of)g(the)f
+(image.)41 b(The)25 b(follo)m(wing)i(more)f(complex)h(example)f
+(creates)h(a)f(smo)s(othed)g(virtual)g(image)0 5220 y(where)k(eac)m(h)h
+(pixel)g(is)g(a)f(3)h(x)f(3)h(b)s(o)m(xcar)g(a)m(v)m(erage)i(of)d(the)h
+(input)e(image)j(pixels:)95 5488 y Fe([pix)47 b(\(X)g(+)h(X{-1})e(+)i
+(X{+1})286 5601 y(+)g(X{-#NAXIS1})d(+)i(X{-#NAXIS1)e(-)i(1})h(+)f
+(X{-#NAXIS1)e(+)j(1})286 5714 y(+)g(X{#NAXIS1})d(+)i(X{#NAXIS1)f(-)h
+(1})g(+)h(X{#NAXIS1)d(+)i(1}\))g(/)h(9.])p eop end
+%%Page: 132 140
+TeXDict begin 132 139 bop 0 299 a Fj(132)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)31 b(the)h(pixel)g(o\013set)h(extends)f(b)s(ey)m(ond)f(the)
+h(\014rst)f(or)h(last)h(pixel)f(in)f(the)h(image,)i(the)e(function)g
+(will)g(ev)-5 b(aluate)33 b(to)0 668 y(unde\014ned,)28
+b(or)j(NULL.)0 828 y(F)-8 b(or)39 b(complex)g(or)g(commonly)g(used)e
+(image)j(\014ltering)f(op)s(erations,)i(one)d(can)h(write)g(the)f
+(expression)h(in)m(to)g(an)0 941 y(external)i(text)h(\014le)f(and)f
+(then)g(imp)s(ort)g(it)h(in)m(to)h(the)e(\014lter)h(using)f(the)h(syn)m
+(tax)g('[pix)g(@\014lename.txt]'.)72 b(The)0 1054 y(mathematical)29
+b(expression)e(can)g(extend)g(o)m(v)m(er)i(m)m(ultiple)e(lines)g(of)h
+(text)g(in)e(the)h(\014le.)40 b(An)m(y)27 b(lines)g(in)g(the)g
+(external)0 1167 y(text)h(\014le)e(that)i(b)s(egin)e(with)g(2)h(slash)f
+(c)m(haracters)i(\('//'\))h(will)e(b)s(e)f(ignored)h(and)f(ma)m(y)h(b)s
+(e)f(used)g(to)h(add)f(commen)m(ts)0 1280 y(in)m(to)31
+b(the)g(\014le.)0 1440 y(By)c(default,)g(the)f(datat)m(yp)s(e)i(of)e
+(the)g(resulting)h(image)g(will)g(b)s(e)e(the)i(same)f(as)h(the)f
+(original)i(image,)g(but)e(one)g(ma)m(y)0 1553 y(force)31
+b(a)g(di\013eren)m(t)g(datat)m(yp)s(e)g(b)m(y)f(app)s(ended)f(a)h(co)s
+(de)h(letter)h(to)f(the)f('pix')h(k)m(eyw)m(ord:)286
+1786 y Fe(pixb)95 b(-)g(8-bit)46 b(byte)190 b(image)46
+b(with)h(BITPIX)f(=)143 b(8)286 1898 y(pixi)95 b(-)47
+b(16-bit)f(integer)g(image)g(with)h(BITPIX)f(=)95 b(16)286
+2011 y(pixj)g(-)47 b(32-bit)f(integer)g(image)g(with)h(BITPIX)f(=)95
+b(32)286 2124 y(pixr)g(-)47 b(32-bit)f(float)142 b(image)46
+b(with)h(BITPIX)f(=)i(-32)286 2237 y(pixd)95 b(-)47 b(64-bit)f(float)
+142 b(image)46 b(with)h(BITPIX)f(=)i(-64)0 2470 y Fj(Also)23
+b(b)m(y)f(default,)j(an)m(y)d(other)h(HDUs)g(in)f(the)g(input)g(\014le)
+g(will)h(b)s(e)e(copied)i(without)g(c)m(hange)g(to)g(the)g(output)f
+(virtual)0 2583 y(FITS)k(\014le,)h(but)f(one)g(ma)m(y)h(discard)f(the)h
+(other)f(HDUs)h(b)m(y)f(adding)g(the)h(n)m(um)m(b)s(er)e('1')i(to)g
+(the)g('pix')f(k)m(eyw)m(ord)h(\(and)0 2696 y(follo)m(wing)32
+b(an)m(y)f(optional)g(datat)m(yp)s(e)g(co)s(de)g(letter\).)42
+b(F)-8 b(or)32 b(example:)239 2928 y Fe(myfile.fits[3][pixr1)90
+b(sqrt\(X\)])0 3161 y Fj(will)23 b(create)i(a)e(virtual)g(FITS)f
+(\014le)h(con)m(taining)h(only)f(a)g(primary)f(arra)m(y)i(image)g(with)
+e(32-bit)i(\015oating)g(p)s(oin)m(t)f(pixels)0 3274 y(that)29
+b(ha)m(v)m(e)h(a)f(v)-5 b(alue)30 b(equal)f(to)g(the)g(square)g(ro)s
+(ot)g(of)g(the)g(pixels)f(in)h(the)g(image)h(that)f(is)g(in)f(the)h
+(3rd)f(extension)i(of)0 3387 y(the)h('m)m(y\014le.\014ts')g(\014le.)0
+3716 y Ff(10.10)136 b(Column)45 b(and)g(Keyw)l(ord)g(Filtering)h(Sp)t
+(eci\014cation)0 3966 y Fj(The)27 b(optional)i(column/k)m(eyw)m(ord)g
+(\014ltering)f(sp)s(eci\014er)f(is)h(used)f(to)i(mo)s(dify)e(the)h
+(column)g(structure)f(and/or)h(the)0 4079 y(header)38
+b(k)m(eyw)m(ords)h(in)f(the)h(HDU)g(that)h(w)m(as)f(selected)h(with)e
+(the)h(previous)f(HDU)h(lo)s(cation)h(sp)s(eci\014er.)65
+b(This)0 4192 y(\014ltering)42 b(sp)s(eci\014er)f(m)m(ust)h(b)s(e)f
+(enclosed)i(in)e(square)h(brac)m(k)m(ets)h(and)e(can)h(b)s(e)f
+(distinguished)g(from)h(a)g(general)0 4305 y(ro)m(w)d(\014lter)g(sp)s
+(eci\014er)f(\(describ)s(ed)g(b)s(elo)m(w\))h(b)m(y)g(the)g(fact)h
+(that)f(it)g(b)s(egins)f(with)h(the)g(string)g('col)h(')f(and)f(is)h
+(not)0 4418 y(immediately)30 b(follo)m(w)m(ed)g(b)m(y)e(an)g(equals)h
+(sign.)40 b(The)28 b(original)h(\014le)f(is)h(not)f(c)m(hanged)h(b)m(y)
+f(this)h(\014ltering)f(op)s(eration,)0 4531 y(and)c(instead)h(the)g(mo)
+s(di\014cations)g(are)g(made)g(on)f(a)h(cop)m(y)h(of)e(the)h(input)f
+(FITS)g(\014le)h(\(usually)g(in)f(memory\),)i(whic)m(h)0
+4644 y(also)31 b(con)m(tains)g(a)g(cop)m(y)g(of)f(all)h(the)f(other)g
+(HDUs)h(in)f(the)g(\014le.)41 b(\(If)30 b(a)g(`#')h(c)m(haracter)g(is)f
+(app)s(ended)f(to)i(the)f(name)0 4757 y(or)d(n)m(um)m(b)s(er)e(of)i
+(the)g(table)g(HDU)h(then)e(only)h(the)g(primary)f(arra)m(y)-8
+b(,)28 b(and)e(none)h(of)g(the)f(other)h(HDUs)h(in)e(the)h(input)0
+4869 y(\014le)i(will)f(b)s(e)g(copied)h(in)m(to)g(memory\).)41
+b(This)27 b(temp)s(orary)h(\014le)h(is)f(passed)g(to)h(the)g
+(application)h(program)e(and)g(will)0 4982 y(p)s(ersist)e(only)i(un)m
+(til)f(the)g(\014le)g(is)h(closed)f(or)g(un)m(til)h(the)f(program)g
+(exits,)i(unless)d(the)h(out\014le)h(sp)s(eci\014er)e(\(see)i(ab)s(o)m
+(v)m(e\))0 5095 y(is)i(also)i(supplied.)0 5255 y(The)f(column/k)m(eyw)m
+(ord)h(\014lter)f(can)g(b)s(e)g(used)f(to)i(p)s(erform)e(the)i(follo)m
+(wing)g(op)s(erations.)44 b(More)32 b(than)f(one)g(op)s(er-)0
+5368 y(ation)g(ma)m(y)g(b)s(e)f(sp)s(eci\014ed)g(b)m(y)g(separating)h
+(them)f(with)h(commas)f(or)h(semi-colons.)136 5601 y
+Fc(\017)46 b Fj(Cop)m(y)36 b(only)g(a)g(sp)s(eci\014ed)g(list)g(of)g
+(columns)g(columns)f(to)i(the)f(\014ltered)g(input)f(\014le.)57
+b(The)36 b(list)g(of)g(column)227 5714 y(name)c(should)f(b)s(e)h
+(separated)g(b)m(y)g(semi-colons.)48 b(Wild)32 b(card)g(c)m(haracters)i
+(ma)m(y)e(b)s(e)g(used)f(in)h(the)g(column)p eop end
+%%Page: 133 141
+TeXDict begin 133 140 bop 0 299 a Fh(10.10.)73 b(COLUMN)30
+b(AND)h(KEYW)m(ORD)g(FIL)-8 b(TERING)31 b(SPECIFICA)-8
+b(TION)984 b Fj(133)227 555 y(names)37 b(to)h(matc)m(h)g(m)m(ultiple)g
+(columns.)61 b(If)37 b(the)g(expression)g(con)m(tains)i(b)s(oth)d(a)i
+(list)f(of)h(columns)f(to)h(b)s(e)227 668 y(included)h(and)f(columns)h
+(to)g(b)s(e)g(deleted,)j(then)c(all)i(the)f(columns)g(in)g(the)g
+(original)h(table)g(except)g(the)227 781 y(explicitly)32
+b(deleted)f(columns)f(will)g(app)s(ear)g(in)g(the)g(\014ltered)g(table)
+h(\(i.e.,)h(there)e(is)h(no)f(need)f(to)i(explicitly)227
+894 y(list)g(the)g(columns)f(to)h(b)s(e)f(included)f(if)i(an)m(y)f
+(columns)g(are)h(b)s(eing)f(deleted\).)136 1102 y Fc(\017)46
+b Fj(Delete)32 b(a)d(column)g(or)g(k)m(eyw)m(ord)h(b)m(y)f(listing)h
+(the)f(name)g(preceded)g(b)m(y)g(a)g(min)m(us)g(sign)g(or)g(an)g
+(exclamation)227 1215 y(mark)c(\(!\),)h(e.g.,)i('-TIME')d(will)g
+(delete)h(the)e(TIME)h(column)f(if)g(it)i(exists,)g(otherwise)f(the)g
+(TIME)f(k)m(eyw)m(ord.)227 1328 y(An)35 b(error)f(is)h(returned)e(if)i
+(neither)f(a)i(column)e(nor)g(k)m(eyw)m(ord)h(with)g(this)f(name)h
+(exists.)54 b(Note)36 b(that)g(the)227 1441 y(exclamation)27
+b(p)s(oin)m(t,)g(')10 b(!',)27 b(is)e(a)g(sp)s(ecial)h(UNIX)f(c)m
+(haracter,)j(so)d(if)g(it)h(is)f(used)f(on)h(the)g(command)g(line)g
+(rather)227 1554 y(than)33 b(en)m(tered)h(at)g(a)g(task)g(prompt,)f(it)
+h(m)m(ust)f(b)s(e)g(preceded)g(b)m(y)g(a)h(bac)m(kslash)g(to)g(force)g
+(the)f(UNIX)h(shell)227 1666 y(to)d(ignore)g(it.)136
+1874 y Fc(\017)46 b Fj(Rename)29 b(an)g(existing)g(column)f(or)h(k)m
+(eyw)m(ord)g(with)f(the)h(syn)m(tax)g('NewName)h(==)e(OldName'.)40
+b(An)28 b(error)227 1987 y(is)j(returned)e(if)h(neither)h(a)f(column)g
+(nor)g(k)m(eyw)m(ord)h(with)f(this)h(name)f(exists.)136
+2195 y Fc(\017)46 b Fj(App)s(end)37 b(a)j(new)f(column)f(or)i(k)m(eyw)m
+(ord)f(to)h(the)f(table.)68 b(T)-8 b(o)40 b(create)g(a)g(column,)h(giv)
+m(e)g(the)e(new)g(name,)227 2308 y(optionally)c(follo)m(w)m(ed)f(b)m(y)
+f(the)g(data)h(t)m(yp)s(e)f(in)f(paren)m(theses,)i(follo)m(w)m(ed)h(b)m
+(y)e(a)g(single)h(equals)f(sign)g(and)f(an)227 2421 y(expression)j(to)h
+(b)s(e)e(used)g(to)i(compute)f(the)g(v)-5 b(alue)35 b(\(e.g.,)j('new)m
+(col\(1J\))f(=)e(0')g(will)h(create)g(a)f(new)g(32-bit)227
+2534 y(in)m(teger)i(column)d(called)j('new)m(col')f(\014lled)f(with)g
+(zeros\).)55 b(The)35 b(data)g(t)m(yp)s(e)h(is)f(sp)s(eci\014ed)f
+(using)g(the)i(same)227 2647 y(syn)m(tax)j(that)g(is)f(allo)m(w)m(ed)i
+(for)e(the)g(v)-5 b(alue)39 b(of)f(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 2760 y(etc.)66
+b(for)38 b(binary)f(tables,)42 b(and)37 b('I8',)k(F12.3',)i('E20.12',)g
+(etc.)65 b(for)38 b(ASCI)s(I)f(tables\).)66 b(If)37 b(the)i(data)g(t)m
+(yp)s(e)227 2873 y(is)c(not)g(sp)s(eci\014ed)f(then)g(an)g(appropriate)
+h(data)g(t)m(yp)s(e)g(will)g(b)s(e)f(c)m(hosen)h(dep)s(ending)e(on)h
+(the)h(form)f(of)h(the)227 2986 y(expression)44 b(\(ma)m(y)g(b)s(e)f(a)
+h(c)m(haracter)i(string,)h(logical,)j(bit,)d(long)d(in)m(teger,)49
+b(or)43 b(double)h(column\).)80 b(An)227 3099 y(appropriate)39
+b(v)m(ector)i(coun)m(t)e(\(in)g(the)g(case)h(of)f(binary)f(tables\))i
+(will)f(also)h(b)s(e)e(added)g(if)h(not)g(explicitly)227
+3212 y(sp)s(eci\014ed.)227 3372 y(When)26 b(creating)h(a)f(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)h('#',)j(and)227 3485 y(the)h(expression)f
+(m)m(ust)g(ev)-5 b(aluate)30 b(to)f(a)g(scalar)g(\(i.e.,)h(cannot)f(ha)
+m(v)m(e)h(a)f(column)f(name)g(in)g(the)h(expression\).)227
+3598 y(The)j(commen)m(t)i(string)f(for)f(the)h(k)m(eyw)m(ord)h(ma)m(y)f
+(b)s(e)f(sp)s(eci\014ed)g(in)g(paren)m(theses)h(immediately)h(follo)m
+(wing)227 3711 y(the)27 b(k)m(eyw)m(ord)g(name)f(\(instead)h(of)g
+(supplying)e(a)i(data)g(t)m(yp)s(e)g(as)f(in)g(the)h(case)g(of)g
+(creating)h(a)f(new)f(column\).)227 3824 y(If)e(the)h(k)m(eyw)m(ord)g
+(name)f(ends)g(with)g(a)h(p)s(ound)d(sign)i('#',)i(then)e(c\014tsio)i
+(will)e(substitute)h(the)f(n)m(um)m(b)s(er)f(of)i(the)227
+3937 y(most)31 b(recen)m(tly)h(referenced)e(column)h(for)f(the)h(#)f(c)
+m(haracter)i(.)41 b(This)29 b(is)i(esp)s(ecially)h(useful)d(when)h
+(writing)227 4049 y(a)c(column-related)g(k)m(eyw)m(ord)g(lik)m(e)g
+(TUNITn)e(for)h(a)h(newly)f(created)h(column,)g(as)g(sho)m(wn)e(in)h
+(the)g(follo)m(wing)227 4162 y(examples.)136 4370 y Fc(\017)46
+b Fj(Recompute)f(\(o)m(v)m(erwrite\))i(the)d(v)-5 b(alues)44
+b(in)g(an)g(existing)i(column)e(or)g(k)m(eyw)m(ord)g(b)m(y)g(giving)i
+(the)e(name)227 4483 y(follo)m(w)m(ed)32 b(b)m(y)f(an)f(equals)h(sign)f
+(and)g(an)g(arithmetic)i(expression.)0 4763 y(The)23
+b(expression)g(that)i(is)e(used)g(when)g(app)s(ending)f(or)h
+(recomputing)h(columns)f(or)h(k)m(eyw)m(ords)g(can)g(b)s(e)f
+(arbitrarily)0 4876 y(complex)36 b(and)g(ma)m(y)g(b)s(e)f(a)h(function)
+g(of)g(other)g(header)g(k)m(eyw)m(ord)g(v)-5 b(alues)36
+b(and)f(other)h(columns)g(\(in)g(the)g(same)0 4989 y(ro)m(w\).)63
+b(The)37 b(full)g(syn)m(tax)i(and)e(a)m(v)-5 b(ailable)40
+b(functions)d(for)g(the)h(expression)f(are)h(describ)s(ed)f(b)s(elo)m
+(w)h(in)f(the)h(ro)m(w)0 5102 y(\014lter)30 b(sp)s(eci\014cation)i
+(section.)0 5262 y(If)27 b(the)h(expression)g(con)m(tains)g(b)s(oth)f
+(a)h(list)h(of)f(columns)f(to)h(b)s(e)g(included)e(and)i(columns)f(to)h
+(b)s(e)f(deleted,)j(then)d(all)0 5375 y(the)34 b(columns)g(in)g(the)g
+(original)h(table)g(except)g(the)f(explicitly)i(deleted)f(columns)e
+(will)i(app)s(ear)e(in)h(the)g(\014ltered)0 5488 y(table.)40
+b(If)26 b(no)g(columns)f(to)i(b)s(e)f(deleted)g(are)h(sp)s(eci\014ed,)f
+(then)g(only)g(the)h(columns)e(that)i(are)f(explicitly)i(listed)f(will)
+0 5601 y(b)s(e)k(included)g(in)g(the)h(\014ltered)f(output)h(table.)45
+b(T)-8 b(o)32 b(include)f(all)i(the)e(columns,)h(add)f(the)h('*')g
+(wildcard)g(sp)s(eci\014er)0 5714 y(at)f(the)g(end)e(of)i(the)f(list,)i
+(as)e(sho)m(wn)g(in)g(the)h(examples.)p eop end
+%%Page: 134 142
+TeXDict begin 134 141 bop 0 299 a Fj(134)1528 b Fh(CHAPTER)29
+b(10.)113 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fj(F)g(or)33 b(complex)f(or)g(commonly)h(used)e(op)s(erations,)i
+(one)f(can)h(place)g(the)f(op)s(erations)g(in)m(to)h(an)f(external)h
+(text)g(\014le)0 668 y(and)39 b(imp)s(ort)h(it)g(in)m(to)h(the)f
+(column)g(\014lter)g(using)f(the)h(syn)m(tax)h('[col)g
+(@\014lename.txt]'.)71 b(The)39 b(op)s(erations)i(can)0
+781 y(extend)26 b(o)m(v)m(er)i(m)m(ultiple)f(lines)g(of)f(the)h
+(\014le,)h(but)d(m)m(ultiple)i(op)s(erations)g(m)m(ust)f(still)i(b)s(e)
+d(separated)i(b)m(y)g(semicolons.)0 894 y(An)m(y)h(lines)h(in)f(the)g
+(external)i(text)f(\014le)f(that)h(b)s(egin)f(with)g(2)h(slash)f(c)m
+(haracters)i(\('//'\))g(will)f(b)s(e)e(ignored)i(and)e(ma)m(y)0
+1007 y(b)s(e)j(used)f(to)i(add)f(commen)m(ts)h(in)m(to)h(the)e(\014le.)
+0 1167 y(Examples:)143 1407 y Fe([col)47 b(Time;)f(rate])667
+b(-)47 b(only)g(the)g(Time)g(and)g(rate)f(columns)g(will)1670
+1520 y(appear)h(in)g(the)g(filtered)e(input)i(file.)143
+1746 y([col)g(Time,)f(*raw])667 b(-)47 b(include)f(the)h(Time)g(column)
+f(and)h(any)g(other)1670 1859 y(columns)f(whose)h(name)f(ends)h(with)g
+('raw'.)143 2085 y([col)g(-TIME;)f(Good)h(==)g(STATUS])141
+b(-)47 b(deletes)f(the)h(TIME)g(column)f(and)1670 2197
+y(renames)g(the)h(status)f(column)g(to)i('Good')143 2423
+y([col)f(PI=PHA)f(*)h(1.1)g(+)h(0.2;)e(#TUNIT#\(column)e(units\))i(=)i
+('counts';*])1575 2536 y(-)f(creates)f(new)h(PI)g(column)f(from)h(PHA)g
+(values)1670 2649 y(and)g(also)g(writes)f(the)h(TUNITn)f(keyword)1670
+2762 y(for)h(the)g(new)g(column.)94 b(The)47 b(final)f('*')1670
+2875 y(expression)f(means)i(preserve)e(all)i(the)1670
+2988 y(columns)f(in)h(the)g(input)g(table)f(in)h(the)1670
+3101 y(virtual)f(output)g(table;)94 b(without)46 b(the)h('*')1670
+3214 y(the)g(output)f(table)h(would)f(only)h(contain)1670
+3327 y(the)g(single)f('PI')h(column.)143 3552 y([col)g(rate)f(=)i
+(rate/exposure;)c(TUNIT#\(&\))h(=)j('counts/s';*])1575
+3665 y(-)f(recomputes)e(the)i(rate)g(column)f(by)h(dividing)1670
+3778 y(it)h(by)f(the)g(EXPOSURE)e(keyword)h(value.)g(This)1670
+3891 y(also)h(modifies)f(the)h(value)f(of)h(the)g(TUNITn)1670
+4004 y(keyword)f(for)h(this)g(column.)f(The)h(use)f(of)i(the)1670
+4117 y('&')f(character)f(for)h(the)f(keyword)g(comment)1670
+4230 y(string)h(means)f(preserve)f(the)i(existing)1670
+4343 y(comment)f(string)g(for)h(that)g(keyword.)e(The)1670
+4456 y(final)i('*')g(preserves)e(all)i(the)g(columns)1670
+4569 y(in)h(the)f(input)f(table)g(in)h(the)g(virtual)1670
+4681 y(output)g(table.)0 5012 y Ff(10.11)136 b(Ro)l(w)46
+b(Filtering)g(Sp)t(eci\014cation)0 5262 y Fj(When)29
+b(en)m(tering)h(the)f(name)g(of)g(a)g(FITS)f(table)i(that)g(is)e(to)i
+(b)s(e)e(op)s(ened)h(b)m(y)f(a)i(program,)f(an)g(optional)h(ro)m(w)f
+(\014lter)0 5375 y(ma)m(y)i(b)s(e)g(sp)s(eci\014ed)f(to)h(select)h(a)g
+(subset)e(of)h(the)g(ro)m(ws)f(in)h(the)g(table.)43 b(A)31
+b(temp)s(orary)f(new)g(FITS)g(\014le)h(is)g(created)0
+5488 y(on)40 b(the)f(\015y)g(whic)m(h)h(con)m(tains)h(only)e(those)h
+(ro)m(ws)g(for)f(whic)m(h)h(the)g(ro)m(w)f(\014lter)h(expression)f(ev)
+-5 b(aluates)42 b(to)e(true.)0 5601 y(The)29 b(primary)f(arra)m(y)i
+(and)f(an)m(y)g(other)h(extensions)g(in)f(the)g(input)g(\014le)g(are)h
+(also)g(copied)g(to)g(the)g(temp)s(orary)f(\014le.)0
+5714 y(\(If)35 b(a)h(`#')f(c)m(haracter)i(is)e(app)s(ended)e(to)j(the)g
+(name)f(or)g(n)m(um)m(b)s(er)f(of)h(the)g(table)h(HDU)g(then)f(only)g
+(the)h(primary)p eop end
+%%Page: 135 143
+TeXDict begin 135 142 bop 0 299 a Fh(10.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(135)0
+555 y(arra)m(y)-8 b(,)37 b(and)d(none)h(of)g(the)g(other)g(HDUs)h(in)e
+(the)i(input)e(\014le)g(will)i(b)s(e)e(copied)h(in)m(to)h(the)f(temp)s
+(orary)g(\014le\).)54 b(The)0 668 y(original)30 b(FITS)f(\014le)g(is)g
+(closed)h(and)e(the)i(new)e(virtual)i(\014le)f(is)g(op)s(ened)f(b)m(y)h
+(the)h(application)g(program.)40 b(The)29 b(ro)m(w)0
+781 y(\014lter)37 b(expression)g(is)h(enclosed)g(in)f(square)g(brac)m
+(k)m(ets)i(follo)m(wing)g(the)e(\014le)h(name)f(and)g(extension)h(name)
+f(\(e.g.,)0 894 y('\014le.\014ts[ev)m(en)m(ts][GRADE==50]')29
+b(selects)d(only)f(those)h(ro)m(ws)f(where)f(the)h(GRADE)h(column)f(v)
+-5 b(alue)25 b(equals)g(50\).)0 1007 y(When)33 b(dealing)h(with)f
+(tables)g(where)g(eac)m(h)h(ro)m(w)f(has)g(an)g(asso)s(ciated)i(time)f
+(and/or)f(2D)g(spatial)i(p)s(osition,)f(the)0 1120 y(ro)m(w)e(\014lter)
+h(expression)e(can)i(also)g(b)s(e)f(used)f(to)i(select)h(ro)m(ws)e
+(based)g(on)g(the)g(times)h(in)f(a)g(Go)s(o)s(d)g(Time)g(In)m(terv)-5
+b(als)0 1233 y(\(GTI\))31 b(extension,)g(or)f(on)h(spatial)g(p)s
+(osition)g(as)f(giv)m(en)i(in)e(a)g(SA)m(O-st)m(yle)i(region)f(\014le.)
+0 1558 y Fd(10.11.1)113 b(General)38 b(Syn)m(tax)0 1784
+y Fj(The)32 b(ro)m(w)h(\014ltering)g(expression)g(can)g(b)s(e)f(an)h
+(arbitrarily)g(complex)g(series)g(of)g(op)s(erations)g(p)s(erformed)f
+(on)g(con-)0 1897 y(stan)m(ts,)39 b(k)m(eyw)m(ord)e(v)-5
+b(alues,)38 b(and)e(column)g(data)i(tak)m(en)f(from)f(the)h(sp)s
+(eci\014ed)e(FITS)h(T)-8 b(ABLE)37 b(extension.)59 b(The)0
+2010 y(expression)37 b(m)m(ust)h(ev)-5 b(aluate)39 b(to)g(a)f(b)s(o)s
+(olean)g(v)-5 b(alue)38 b(for)f(eac)m(h)i(ro)m(w)f(of)g(the)f(table,)k
+(where)c(a)h(v)-5 b(alue)39 b(of)e(F)-10 b(ALSE)0 2123
+y(means)30 b(that)h(the)g(ro)m(w)f(will)h(b)s(e)f(excluded.)0
+2283 y(F)-8 b(or)34 b(complex)g(or)g(commonly)f(used)g(\014lters,)h
+(one)g(can)g(place)g(the)g(expression)f(in)m(to)h(a)g(text)g(\014le)g
+(and)f(imp)s(ort)f(it)0 2396 y(in)m(to)38 b(the)e(ro)m(w)h(\014lter)g
+(using)f(the)h(syn)m(tax)g('[@\014lename.txt]'.)61 b(The)36
+b(expression)h(can)f(b)s(e)g(arbitrarily)h(complex)0
+2509 y(and)27 b(extend)i(o)m(v)m(er)g(m)m(ultiple)g(lines)f(of)g(the)h
+(\014le.)40 b(An)m(y)28 b(lines)g(in)g(the)g(external)h(text)g(\014le)f
+(that)h(b)s(egin)f(with)g(2)g(slash)0 2622 y(c)m(haracters)k(\('//'\))g
+(will)f(b)s(e)f(ignored)g(and)g(ma)m(y)h(b)s(e)f(used)f(to)i(add)f
+(commen)m(ts)h(in)m(to)h(the)e(\014le.)0 2782 y(Keyw)m(ord)37
+b(and)f(column)g(data)i(are)f(referenced)g(b)m(y)g(name.)60
+b(An)m(y)37 b(string)f(of)h(c)m(haracters)i(not)e(surrounded)d(b)m(y)0
+2895 y(quotes)41 b(\(ie,)j(a)d(constan)m(t)h(string\))f(or)f(follo)m(w)
+m(ed)i(b)m(y)f(an)f(op)s(en)g(paren)m(theses)h(\(ie,)j(a)d(function)f
+(name\))h(will)g(b)s(e)0 3008 y(initially)d(in)m(terpreted)e(as)h(a)g
+(column)f(name)g(and)g(its)h(con)m(ten)m(ts)h(for)e(the)h(curren)m(t)f
+(ro)m(w)g(inserted)g(in)m(to)i(the)e(ex-)0 3121 y(pression.)k(If)28
+b(no)h(suc)m(h)g(column)g(exists,)h(a)g(k)m(eyw)m(ord)f(of)h(that)f
+(name)g(will)h(b)s(e)e(searc)m(hed)i(for)f(and)f(its)i(v)-5
+b(alue)29 b(used,)0 3234 y(if)36 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)h(as)g(a)g(k)m(eyw)m
+(ord)g(\(in)g(case)g(there)g(is)g(b)s(oth)f(a)h(column)g(and)0
+3347 y(k)m(eyw)m(ord)41 b(with)e(the)i(same)f(name\),)j(precede)d(the)h
+(k)m(eyw)m(ord)f(name)g(with)g(a)h(single)f(p)s(ound)e(sign,)43
+b('#',)g(as)d(in)0 3460 y('#NAXIS2'.)g(Due)27 b(to)g(the)f
+(generalities)j(of)d(FITS)g(column)g(and)g(k)m(eyw)m(ord)h(names,)g(if)
+f(the)h(column)f(or)g(k)m(eyw)m(ord)0 3572 y(name)33
+b(con)m(tains)h(a)f(space)h(or)f(a)g(c)m(haracter)h(whic)m(h)f(migh)m
+(t)h(app)s(ear)e(as)h(an)g(arithmetic)h(term)f(then)g(enclose)h(the)0
+3685 y(name)c(in)g('$')i(c)m(haracters)g(as)e(in)g($MAX)i(PHA$)f(or)f
+(#$MAX-PHA$.)43 b(Names)31 b(are)f(case)i(insensitiv)m(e.)0
+3846 y(T)-8 b(o)32 b(access)g(a)g(table)g(en)m(try)g(in)f(a)h(ro)m(w)f
+(other)h(than)f(the)g(curren)m(t)g(one,)h(follo)m(w)h(the)e(column's)h
+(name)f(with)g(a)h(ro)m(w)0 3958 y(o\013set)37 b(within)e(curly)g
+(braces.)57 b(F)-8 b(or)36 b(example,)i('PHA)p Fc(f)p
+Fj(-3)p Fc(g)p Fj(')g(will)e(ev)-5 b(aluate)38 b(to)e(the)g(v)-5
+b(alue)36 b(of)g(column)f(PHA,)i(3)0 4071 y(ro)m(ws)28
+b(ab)s(o)m(v)m(e)i(the)e(ro)m(w)h(curren)m(tly)f(b)s(eing)g(pro)s
+(cessed.)40 b(One)28 b(cannot)h(sp)s(ecify)f(an)g(absolute)h(ro)m(w)f
+(n)m(um)m(b)s(er,)g(only)h(a)0 4184 y(relativ)m(e)j(o\013set.)42
+b(Ro)m(ws)31 b(that)g(fall)g(outside)g(the)f(table)h(will)g(b)s(e)f
+(treated)h(as)g(unde\014ned,)d(or)j(NULLs.)0 4344 y(Bo)s(olean)h(op)s
+(erators)f(can)g(b)s(e)f(used)f(in)i(the)f(expression)h(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 4457 y(b)s(o)s(olean)g(op)s(erators)h(are)g(a)m(v)-5
+b(ailable:)191 4747 y Fe("equal")428 b(.eq.)46 b(.EQ.)h(==)95
+b("not)46 b(equal")476 b(.ne.)94 b(.NE.)h(!=)191 4860
+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 4973
+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 5086
+y("or")572 b(.or.)46 b(.OR.)h(||)95 b("and")762 b(.and.)46
+b(.AND.)h(&&)191 5199 y("negation")236 b(.not.)46 b(.NOT.)h(!)95
+b("approx.)45 b(equal\(1e-7\)")92 b(~)0 5488 y Fj(Note)32
+b(that)g(the)f(exclamation)i(p)s(oin)m(t,)e(')10 b(!',)33
+b(is)e(a)g(sp)s(ecial)g(UNIX)h(c)m(haracter,)h(so)e(if)g(it)g(is)g
+(used)f(on)h(the)g(command)0 5601 y(line)i(rather)f(than)h(en)m(tered)g
+(at)g(a)g(task)g(prompt,)g(it)g(m)m(ust)f(b)s(e)g(preceded)h(b)m(y)f(a)
+h(bac)m(kslash)g(to)h(force)f(the)g(UNIX)0 5714 y(shell)e(to)g(ignore)g
+(it.)p eop end
+%%Page: 136 144
+TeXDict begin 136 143 bop 0 299 a Fj(136)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)32 b(expression)g(ma)m(y)i(also)f(include)f(arithmetic)i
+(op)s(erators)f(and)f(functions.)47 b(T)-8 b(rigonometric)34
+b(functions)e(use)0 668 y(radians,)23 b(not)g(degrees.)38
+b(The)22 b(follo)m(wing)h(arithmetic)g(op)s(erators)g(and)e(functions)g
+(can)i(b)s(e)e(used)g(in)h(the)g(expression)0 781 y(\(function)38
+b(names)f(are)h(case)g(insensitiv)m(e\).)64 b(A)37 b(n)m(ull)h(v)-5
+b(alue)38 b(will)f(b)s(e)g(returned)g(in)g(case)h(of)g(illegal)i(op)s
+(erations)0 894 y(suc)m(h)30 b(as)h(divide)f(b)m(y)g(zero,)i
+(sqrt\(negativ)m(e\))h(log\(negativ)m(e\),)h(log10\(negativ)m(e\),)i
+(arccos\(.gt.)43 b(1\),)32 b(arcsin\(.gt.)42 b(1\).)191
+1144 y Fe("addition")474 b(+)j("subtraction")d(-)191
+1257 y("multiplication")186 b(*)477 b("division")618
+b(/)191 1370 y("negation")474 b(-)j("exponentiation")330
+b(**)143 b(^)191 1483 y("absolute)45 b(value")189 b(abs\(x\))237
+b("cosine")762 b(cos\(x\))191 1596 y("sine")666 b(sin\(x\))237
+b("tangent")714 b(tan\(x\))191 1709 y("arc)47 b(cosine")379
+b(arccos\(x\))93 b("arc)47 b(sine")667 b(arcsin\(x\))191
+1822 y("arc)47 b(tangent")331 b(arctan\(x\))93 b("arc)47
+b(tangent")523 b(arctan2\(y,x\))191 1935 y("hyperbolic)45
+b(cos")189 b(cosh\(x\))g("hyperbolic)45 b(sin")381 b(sinh\(x\))191
+2047 y("hyperbolic)45 b(tan")189 b(tanh\(x\))g("round)47
+b(to)g(nearest)f(int")94 b(round\(x\))191 2160 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 2273 y("exponential")d(exp\(x\))237 b("square)46
+b(root")524 b(sqrt\(x\))191 2386 y("natural)45 b(log")333
+b(log\(x\))237 b("common)46 b(log")572 b(log10\(x\))191
+2499 y("modulus")522 b(x)48 b(\045)f(y)286 b("random)46
+b(#)i([0.0,1.0\)")188 b(random\(\))191 2612 y("random)46
+b(Gaussian")140 b(randomn\(\))93 b("random)46 b(Poisson")380
+b(randomp\(x\))191 2725 y("minimum")522 b(min\(x,y\))141
+b("maximum")714 b(max\(x,y\))191 2838 y("cumulative)45
+b(sum")189 b(accum\(x\))141 b("sequential)45 b(difference")g
+(seqdiff\(x\))191 2951 y("if-then-else")282 b(b?x:y)191
+3064 y("angular)45 b(separation")93 b(angsep\(ra1,dec1,ra2,de2\))41
+b(\(all)47 b(in)g(degrees\))191 3177 y("substring")283
+b(strmid\(s,p,n\))44 b("string)i(search")428 b(strstr\(s,r\))0
+3427 y Fj(Three)30 b(di\013eren)m(t)h(random)f(n)m(um)m(b)s(er)f
+(functions)h(are)h(pro)m(vided:)41 b(random\(\),)30 b(with)h(no)f
+(argumen)m(ts,)h(pro)s(duces)f(a)0 3540 y(uniform)g(random)f(deviate)k
+(b)s(et)m(w)m(een)e(0)g(and)f(1;)i(randomn\(\),)e(also)i(with)e(no)h
+(argumen)m(ts,)g(pro)s(duces)f(a)h(normal)0 3653 y(\(Gaussian\))k
+(random)e(deviate)j(with)e(zero)h(mean)f(and)g(unit)f(standard)h
+(deviation;)j(randomp\(x\))d(pro)s(duces)f(a)0 3766 y(P)m(oisson)27
+b(random)f(deviate)h(whose)f(exp)s(ected)h(n)m(um)m(b)s(er)e(of)h(coun)
+m(ts)h(is)g(X.)f(X)h(ma)m(y)g(b)s(e)e(an)m(y)i(p)s(ositiv)m(e)g(real)g
+(n)m(um)m(b)s(er)0 3878 y(of)k(exp)s(ected)f(coun)m(ts,)h(including)f
+(fractional)i(v)-5 b(alues,)31 b(but)f(the)g(return)g(v)-5
+b(alue)31 b(is)f(an)g(in)m(teger.)0 4039 y(When)d(the)g(random)g
+(functions)f(are)i(used)e(in)h(a)h(v)m(ector)g(expression,)g(b)m(y)f
+(default)h(the)f(same)h(random)e(v)-5 b(alue)28 b(will)0
+4152 y(b)s(e)g(used)f(when)h(ev)-5 b(aluating)30 b(eac)m(h)f(elemen)m
+(t)h(of)f(the)g(v)m(ector.)41 b(If)28 b(di\013eren)m(t)h(random)f(n)m
+(um)m(b)s(ers)f(are)i(desired,)f(then)0 4264 y(the)37
+b(name)g(of)g(a)g(v)m(ector)i(column)e(should)e(b)s(e)i(supplied)e(as)i
+(the)h(single)f(argumen)m(t)g(to)h(the)f(random)f(function)0
+4377 y(\(e.g.,)31 b("\015ux)c(+)h(0.1)h(*)g(random\(\015ux\)",)f(where)
+g("\015ux')g(is)g(the)g(name)h(of)f(a)h(v)m(ector)h(column\).)40
+b(This)27 b(will)i(create)h(a)0 4490 y(v)m(ector)d(of)f(random)f(n)m
+(um)m(b)s(ers)f(that)i(will)g(b)s(e)f(used)f(in)i(sequence)g(when)e(ev)
+-5 b(aluating)27 b(eac)m(h)g(elemen)m(t)g(of)f(the)f(v)m(ector)0
+4603 y(expression.)0 4763 y(An)31 b(alternate)i(syn)m(tax)f(for)f(the)g
+(min)g(and)g(max)g(functions)g(has)g(only)g(a)h(single)g(argumen)m(t)g
+(whic)m(h)f(should)f(b)s(e)h(a)0 4876 y(v)m(ector)g(v)-5
+b(alue)30 b(\(see)g(b)s(elo)m(w\).)41 b(The)29 b(result)g(will)h(b)s(e)
+e(the)i(minim)m(um/maxim)m(um)f(elemen)m(t)h(con)m(tained)h(within)e
+(the)0 4989 y(v)m(ector.)0 5149 y(The)35 b(accum\(x\))i(function)f
+(forms)f(the)h(cum)m(ulativ)m(e)i(sum)d(of)h(x,)h(elemen)m(t)h(b)m(y)e
+(elemen)m(t.)58 b(V)-8 b(ector)38 b(columns)e(are)0 5262
+y(supp)s(orted)h(simply)h(b)m(y)g(p)s(erforming)f(the)i(summation)g
+(pro)s(cess)f(through)f(all)j(the)f(v)-5 b(alues.)65
+b(Null)39 b(v)-5 b(alues)39 b(are)0 5375 y(treated)30
+b(as)f(0.)41 b(The)29 b(seqdi\013\(x\))h(function)e(forms)h(the)g
+(sequen)m(tial)i(di\013erence)e(of)h(x,)f(elemen)m(t)i(b)m(y)e(elemen)m
+(t.)41 b(The)0 5488 y(\014rst)36 b(v)-5 b(alue)38 b(of)f(seqdi\013)g
+(is)g(the)g(\014rst)g(v)-5 b(alue)37 b(of)g(x.)61 b(A)37
+b(single)h(n)m(ull)f(v)-5 b(alue)38 b(in)e(x)h(causes)h(a)f(pair)g(of)g
+(n)m(ulls)g(in)g(the)0 5601 y(output.)55 b(The)35 b(seqdi\013)g(and)g
+(accum)g(functions)g(are)h(functional)f(in)m(v)m(erses,)j(i.e.,)g
+(seqdi\013\(accum\(x\)\))f(==)e(x)g(as)0 5714 y(long)c(as)g(no)f(n)m
+(ull)g(v)-5 b(alues)31 b(are)g(presen)m(t.)p eop end
+%%Page: 137 145
+TeXDict begin 137 144 bop 0 299 a Fh(10.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(137)0
+555 y(In)36 b(the)h(if-then-else)i(expression,)f("b?x:y",)i(b)c(is)h
+(an)g(explicit)h(b)s(o)s(olean)f(v)-5 b(alue)37 b(or)g(expression.)61
+b(There)36 b(is)h(no)0 668 y(automatic)d(t)m(yp)s(e)e(con)m(v)m(ersion)
+h(from)e(n)m(umeric)h(to)g(b)s(o)s(olean)g(v)-5 b(alues,)33
+b(so)f(one)g(needs)f(to)i(use)e("iV)-8 b(al!=0")35 b(instead)0
+781 y(of)30 b(merely)g("iV)-8 b(al")32 b(as)e(the)g(b)s(o)s(olean)g
+(argumen)m(t.)41 b(x)30 b(and)f(y)h(can)g(b)s(e)f(an)m(y)h(scalar)h
+(data)g(t)m(yp)s(e)f(\(including)f(string\).)0 941 y(The)22
+b(angsep)g(function)f(computes)i(the)f(angular)g(separation)h(in)e
+(degrees)i(b)s(et)m(w)m(een)g(2)f(celestial)j(p)s(ositions,)e(where)0
+1054 y(the)36 b(\014rst)f(2)h(parameters)g(giv)m(e)h(the)f(RA-lik)m(e)i
+(and)d(Dec-lik)m(e)j(co)s(ordinates)f(\(in)f(decimal)g(degrees\))h(of)f
+(the)g(\014rst)0 1167 y(p)s(osition,)31 b(and)e(the)i(3rd)f(and)g(4th)g
+(parameters)h(giv)m(e)h(the)e(co)s(ordinates)i(of)e(the)h(second)f(p)s
+(osition.)0 1327 y(The)38 b(substring)f(function)i(strmid\(S,P)-8
+b(,N\))39 b(extracts)g(a)g(substring)f(from)g(S,)g(starting)h(at)g
+(string)g(p)s(osition)f(P)-8 b(,)0 1440 y(with)33 b(a)h(substring)f
+(length)h(N.)g(The)f(\014rst)g(c)m(haracter)j(p)s(osition)d(in)h(S)f
+(is)h(lab)s(eled)g(as)g(1.)51 b(If)33 b(P)g(is)h(0,)h(or)f(refers)f(to)
+0 1553 y(a)i(p)s(osition)g(b)s(ey)m(ond)f(the)h(end)e(of)i(S,)g(then)f
+(the)h(extracted)h(substring)d(will)i(b)s(e)f(NULL.)h(S,)f(P)-8
+b(,)36 b(and)e(N)g(ma)m(y)i(b)s(e)0 1666 y(functions)30
+b(of)g(other)h(columns.)0 1826 y(The)39 b(string)h(searc)m(h)h
+(function)e(strstr\(S,R\))h(searc)m(hes)h(for)f(the)g(\014rst)f(o)s
+(ccurrence)h(of)g(the)g(substring)f(R)h(in)f(S.)0 1939
+y(The)c(result)h(is)f(an)h(in)m(teger,)i(indicating)f(the)e(c)m
+(haracter)i(p)s(osition)f(of)g(the)g(\014rst)e(matc)m(h)j(\(where)e(1)h
+(is)g(the)g(\014rst)0 2052 y(c)m(haracter)c(p)s(osition)e(of)h(S\).)f
+(If)g(no)h(matc)m(h)g(is)f(found,)g(then)g(strstr\(\))g(returns)f(a)i
+(NULL)f(v)-5 b(alue.)0 2212 y(The)38 b(follo)m(wing)i(t)m(yp)s(e)f
+(casting)h(op)s(erators)f(are)g(a)m(v)-5 b(ailable,)44
+b(where)38 b(the)h(inclosing)h(paren)m(theses)f(are)g(required)0
+2325 y(and)30 b(tak)m(en)h(from)f(the)h(C)f(language)h(usage.)42
+b(Also,)31 b(the)g(in)m(teger)g(to)h(real)f(casts)g(v)-5
+b(alues)30 b(to)i(double)e(precision:)764 2545 y Fe("real)46
+b(to)h(integer")189 b(\(int\))46 b(x)239 b(\(INT\))46
+b(x)764 2658 y("integer)f(to)i(real")190 b(\(float\))46
+b(i)143 b(\(FLOAT\))45 b(i)0 2878 y Fj(In)30 b(addition,)g(sev)m(eral)i
+(constan)m(ts)g(are)f(built)f(in)g(for)g(use)g(in)g(n)m(umerical)h
+(expressions:)382 3098 y Fe(#pi)667 b(3.1415...)284 b(#e)620
+b(2.7182...)382 3211 y(#deg)f(#pi/180)380 b(#row)524
+b(current)46 b(row)h(number)382 3324 y(#null)428 b(undefined)45
+b(value)142 b(#snull)428 b(undefined)45 b(string)0 3544
+y Fj(A)40 b(string)f(constan)m(t)i(m)m(ust)e(b)s(e)g(enclosed)h(in)g
+(quotes)g(as)f(in)h('Crab'.)67 b(The)39 b("n)m(ull")i(constan)m(ts)f
+(are)g(useful)f(for)0 3657 y(conditionally)g(setting)g(table)g(v)-5
+b(alues)38 b(to)g(a)g(NULL,)g(or)g(unde\014ned,)f(v)-5
+b(alue)39 b(\(eg.,)i("col1==-99)f(?)62 b(#NULL)38 b(:)0
+3770 y(col1"\).)0 3930 y(There)27 b(is)g(also)i(a)e(function)g(for)h
+(testing)g(if)f(t)m(w)m(o)i(v)-5 b(alues)28 b(are)g(close)g(to)h(eac)m
+(h)f(other,)h(i.e.,)g(if)e(they)h(are)g("near")g(eac)m(h)0
+4043 y(other)c(to)h(within)e(a)h(user)g(sp)s(eci\014ed)f(tolerance.)40
+b(The)24 b(argumen)m(ts,)h(v)-5 b(alue)p 2502 4043 28
+4 v 34 w(1)24 b(and)f(v)-5 b(alue)p 2979 4043 V 33 w(2)25
+b(can)f(b)s(e)f(in)m(teger)i(or)f(real)0 4156 y(and)32
+b(represen)m(t)h(the)g(t)m(w)m(o)h(v)-5 b(alues)33 b(who's)f(pro)m
+(ximit)m(y)i(is)f(b)s(eing)f(tested)h(to)h(b)s(e)e(within)g(the)h(sp)s
+(eci\014ed)f(tolerance,)0 4269 y(also)f(an)g(in)m(teger)g(or)g(real:)
+955 4489 y Fe(near\(value_1,)44 b(value_2,)h(tolerance\))0
+4709 y Fj(When)24 b(a)i(NULL,)e(or)h(unde\014ned,)f(v)-5
+b(alue)25 b(is)g(encoun)m(tered)g(in)g(the)f(FITS)g(table,)j(the)e
+(expression)g(will)g(ev)-5 b(aluate)26 b(to)0 4822 y(NULL)31
+b(unless)f(the)h(unde\014ned)e(v)-5 b(alue)31 b(is)g(not)g(actually)h
+(required)e(for)h(ev)-5 b(aluation,)33 b(e.g.)43 b("TR)m(UE)31
+b(.or.)43 b(NULL")0 4935 y(ev)-5 b(aluates)32 b(to)f(TR)m(UE.)g(The)f
+(follo)m(wing)h(t)m(w)m(o)h(functions)e(allo)m(w)i(some)f(NULL)f
+(detection)i(and)e(handling:)430 5155 y Fe("a)47 b(null)f(value?")667
+b(ISNULL\(x\))430 5268 y("define)45 b(a)j(value)e(for)h(null")190
+b(DEFNULL\(x,y\))0 5488 y Fj(The)36 b(former)h(returns)e(a)i(b)s(o)s
+(olean)g(v)-5 b(alue)37 b(of)g(TR)m(UE)g(if)g(the)g(argumen)m(t)g(x)g
+(is)g(NULL.)g(The)f(later)i("de\014nes")f(a)0 5601 y(v)-5
+b(alue)35 b(to)g(b)s(e)e(substituted)h(for)g(NULL)g(v)-5
+b(alues;)37 b(it)e(returns)e(the)h(v)-5 b(alue)35 b(of)f(x)g(if)g(x)h
+(is)f(not)g(NULL,)h(otherwise)f(it)0 5714 y(returns)29
+b(the)i(v)-5 b(alue)31 b(of)f(y)-8 b(.)p eop end
+%%Page: 138 146
+TeXDict begin 138 145 bop 0 299 a Fj(138)1528 b Fh(CHAPTER)29
+b(10.)113 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fd(10.11.2)113 b(Bit)36 b(Masks)0 774 y Fj(Bit)g(masks)f(can)h(b)
+s(e)f(used)f(to)i(select)h(out)e(ro)m(ws)h(from)e(bit)i(columns)f(\(TF)
+m(ORMn)g(=)g(#X\))h(in)f(FITS)f(\014les.)55 b(T)-8 b(o)0
+887 y(represen)m(t)30 b(the)h(mask,)g(binary)-8 b(,)30
+b(o)s(ctal,)i(and)e(hex)g(formats)g(are)h(allo)m(w)m(ed:)811
+1141 y Fe(binary:)142 b(b0110xx1010000101xxxx00)o(01)811
+1254 y(octal:)190 b(o720x1)46 b(->)h(\(b111010000xxx001\))811
+1367 y(hex:)286 b(h0FxD)94 b(->)47 b(\(b00001111xxxx1101\))0
+1621 y Fj(In)22 b(all)i(the)f(represen)m(tations,)j(an)c(x)h(or)g(X)g
+(is)g(allo)m(w)m(ed)i(in)d(the)h(mask)g(as)g(a)h(wild)e(card.)38
+b(Note)25 b(that)e(the)g(x)g(represen)m(ts)0 1734 y(a)k(di\013eren)m(t)
+h(n)m(um)m(b)s(er)e(of)h(wild)f(card)h(bits)g(in)g(eac)m(h)h(represen)m
+(tation.)41 b(All)27 b(represen)m(tations)h(are)g(case)g(insensitiv)m
+(e.)0 1894 y(T)-8 b(o)28 b(construct)g(the)g(b)s(o)s(olean)f
+(expression)h(using)f(the)h(mask)f(as)h(the)g(b)s(o)s(olean)f(equal)h
+(op)s(erator)g(describ)s(ed)f(ab)s(o)m(v)m(e)0 2007 y(on)34
+b(a)h(bit)g(table)h(column.)53 b(F)-8 b(or)35 b(example,)i(if)d(y)m(ou)
+h(had)f(a)h(7)g(bit)g(column)f(named)g(\015ags)h(in)f(a)h(FITS)f(table)
+i(and)0 2119 y(w)m(an)m(ted)31 b(all)g(ro)m(ws)g(ha)m(ving)g(the)f(bit)
+h(pattern)f(0010011,)k(the)c(selection)j(expression)d(w)m(ould)g(b)s
+(e:)1336 2373 y Fe(flags)47 b(==)g(b0010011)191 2486
+y(or)1336 2599 y(flags)g(.eq.)f(b10011)0 2853 y Fj(It)35
+b(is)g(also)h(p)s(ossible)e(to)i(test)g(if)f(a)g(range)g(of)g(bits)g
+(is)g(less)g(than,)h(less)f(than)g(equal,)i(greater)f(than)e(and)h
+(greater)0 2966 y(than)30 b(equal)h(to)g(a)g(particular)g(b)s(o)s
+(olean)f(v)-5 b(alue:)1336 3220 y Fe(flags)47 b(<=)g(bxxx010xx)1336
+3333 y(flags)g(.gt.)f(bxxx100xx)1336 3446 y(flags)h(.le.)f(b1xxxxxxx)0
+3700 y Fj(Notice)32 b(the)f(use)f(of)h(the)f(x)g(bit)h(v)-5
+b(alue)31 b(to)g(limit)g(the)f(range)h(of)g(bits)f(b)s(eing)g
+(compared.)0 3860 y(It)i(is)h(not)f(necessary)h(to)g(sp)s(ecify)f(the)h
+(leading)g(\(most)g(signi\014can)m(t\))h(zero)f(\(0\))g(bits)f(in)g
+(the)h(mask,)g(as)g(sho)m(wn)e(in)0 3973 y(the)g(second)f(expression)g
+(ab)s(o)m(v)m(e.)0 4133 y(Bit)44 b(wise)f(AND,)h(OR)e(and)g(NOT)h(op)s
+(erations)g(are)g(also)h(p)s(ossible)e(on)h(t)m(w)m(o)h(or)f(more)g
+(bit)g(\014elds)f(using)h(the)0 4246 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)34 b(of)f(these)h(op)s(erators)g(result)f(in)h
+(a)g(bit)f(\014eld)g(whic)m(h)0 4359 y(can)e(then)f(b)s(e)f(used)h
+(with)g(the)h(equal)g(op)s(erator.)41 b(F)-8 b(or)31
+b(example:)1241 4613 y Fe(\(!flags\))45 b(==)j(b1101100)1241
+4726 y(\(flags)e(&)h(b1000001\))f(==)h(bx000001)0 4979
+y Fj(Bit)35 b(\014elds)f(can)g(b)s(e)f(app)s(ended)g(as)h(w)m(ell)h
+(using)f(the)g('+')g(op)s(erator.)53 b(Strings)33 b(can)i(b)s(e)e
+(concatenated)j(this)e(w)m(a)m(y)-8 b(,)0 5092 y(to)s(o.)0
+5382 y Fd(10.11.3)113 b(V)-9 b(ector)36 b(Columns)0 5601
+y Fj(V)-8 b(ector)37 b(columns)e(can)h(also)g(b)s(e)f(used)f(in)h
+(building)g(the)g(expression.)56 b(No)36 b(sp)s(ecial)g(syn)m(tax)f(is)
+h(required)e(if)i(one)0 5714 y(w)m(an)m(ts)46 b(to)f(op)s(erate)h(on)f
+(all)h(elemen)m(ts)g(of)f(the)h(v)m(ector.)86 b(Simply)44
+b(use)h(the)g(column)g(name)g(as)g(for)g(a)g(scalar)p
+eop end
+%%Page: 139 147
+TeXDict begin 139 146 bop 0 299 a Fh(10.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(139)0
+555 y(column.)42 b(V)-8 b(ector)32 b(columns)f(can)g(b)s(e)f(freely)h
+(in)m(termixed)h(with)e(scalar)i(columns)e(or)h(constan)m(ts)h(in)f
+(virtually)g(all)0 668 y(expressions.)40 b(The)29 b(result)g(will)g(b)s
+(e)g(of)g(the)g(same)h(dimension)e(as)i(the)f(v)m(ector.)42
+b(Tw)m(o)29 b(v)m(ectors)i(in)e(an)g(expression,)0 781
+y(though,)h(need)g(to)i(ha)m(v)m(e)f(the)g(same)g(n)m(um)m(b)s(er)e(of)
+h(elemen)m(ts)i(and)e(ha)m(v)m(e)h(the)g(same)g(dimensions.)0
+941 y(Arithmetic)24 b(and)e(logical)k(op)s(erations)d(are)h(all)g(p)s
+(erformed)d(on)i(an)g(elemen)m(t)h(b)m(y)f(elemen)m(t)i(basis.)38
+b(Comparing)23 b(t)m(w)m(o)0 1054 y(v)m(ector)32 b(columns,)e(eg)h
+("COL1)f(==)g(COL2",)g(th)m(us)g(results)g(in)g(another)g(v)m(ector)i
+(of)e(b)s(o)s(olean)h(v)-5 b(alues)30 b(indicating)0
+1167 y(whic)m(h)g(elemen)m(ts)i(of)e(the)h(t)m(w)m(o)h(v)m(ectors)f
+(are)g(equal.)0 1327 y(Eigh)m(t)g(functions)f(are)h(a)m(v)-5
+b(ailable)33 b(that)e(op)s(erate)g(on)f(a)h(v)m(ector)h(and)d(return)h
+(a)g(scalar)i(result:)191 1570 y Fe("minimum")284 b(MIN\(V\))475
+b("maximum")714 b(MAX\(V\))191 1683 y("average")284 b(AVERAGE\(V\))f
+("median")762 b(MEDIAN\(V\))191 1796 y("summation")188
+b(SUM\(V\))475 b("standard)46 b(deviation")188 b(STDDEV\(V\))191
+1909 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 2151 y Fj(where)40
+b(V)h(represen)m(ts)g(the)g(name)g(of)h(a)f(v)m(ector)h(column)f(or)g
+(a)h(man)m(ually)f(constructed)g(v)m(ector)i(using)d(curly)0
+2264 y(brac)m(k)m(ets)27 b(as)f(describ)s(ed)e(b)s(elo)m(w.)39
+b(The)25 b(\014rst)g(6)h(of)g(these)g(functions)f(ignore)h(an)m(y)g(n)m
+(ull)f(v)-5 b(alues)26 b(in)f(the)h(v)m(ector)h(when)0
+2377 y(computing)k(the)f(result.)41 b(The)30 b(STDDEV\(\))h(function)g
+(computes)f(the)h(sample)g(standard)e(deviation,)j(i.e.)42
+b(it)31 b(is)0 2490 y(prop)s(ortional)f(to)h(1/SQR)-8
+b(T\(N-1\))32 b(instead)f(of)g(1/SQR)-8 b(T\(N\),)31
+b(where)f(N)h(is)f(NV)-10 b(ALID\(V\).)0 2650 y(The)31
+b(SUM)h(function)f(literally)j(sums)d(all)h(the)g(elemen)m(ts)h(in)f
+(x,)g(returning)f(a)h(scalar)h(v)-5 b(alue.)45 b(If)31
+b(V)h(is)g(a)g(b)s(o)s(olean)0 2763 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.)60
+b(The)36 b(NELEM)g(function)g(returns)f(the)h(n)m(um)m(b)s(er)0
+2876 y(of)h(elemen)m(ts)g(in)g(v)m(ector)h(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)g(elemen)
+m(ts)i(in)e(the)h(v)m(ector.)0 2989 y(\(NELEM)28 b(also)h(op)s(erates)f
+(on)g(bit)f(and)g(string)h(columns,)g(returning)f(their)h(column)f
+(widths.\))40 b(As)27 b(an)h(example,)0 3102 y(to)42
+b(test)g(whether)f(all)h(elemen)m(ts)h(of)f(t)m(w)m(o)g(v)m(ectors)h
+(satisfy)f(a)g(giv)m(en)g(logical)i(comparison,)g(one)e(can)g(use)f
+(the)0 3215 y(expression)668 3457 y Fe(SUM\()47 b(COL1)f(>)i(COL2)f(\))
+g(==)g(NELEM\()f(COL1)h(\))0 3700 y Fj(whic)m(h)32 b(will)g(return)f
+(TR)m(UE)h(if)g(all)h(elemen)m(ts)g(of)f(COL1)g(are)g(greater)h(than)f
+(their)g(corresp)s(onding)f(elemen)m(ts)i(in)0 3813 y(COL2.)0
+3973 y(T)-8 b(o)32 b(sp)s(ecify)f(a)i(single)f(elemen)m(t)h(of)f(a)g(v)
+m(ector,)i(giv)m(e)f(the)f(column)f(name)h(follo)m(w)m(ed)h(b)m(y)f(a)g
+(comma-separated)h(list)0 4086 y(of)c(co)s(ordinates)g(enclosed)h(in)e
+(square)h(brac)m(k)m(ets.)41 b(F)-8 b(or)30 b(example,)g(if)e(a)h(v)m
+(ector)i(column)d(named)h(PHAS)f(exists)h(in)0 4199 y(the)e(table)g(as)
+g(a)g(one)g(dimensional,)h(256)g(comp)s(onen)m(t)f(list)g(of)g(n)m(um)m
+(b)s(ers)e(from)h(whic)m(h)h(y)m(ou)g(w)m(an)m(ted)g(to)g(select)i(the)
+0 4312 y(57th)j(comp)s(onen)m(t)g(for)f(use)g(in)g(the)h(expression,)f
+(then)h(PHAS[57])g(w)m(ould)f(do)h(the)f(tric)m(k.)45
+b(Higher)32 b(dimensional)0 4425 y(arra)m(ys)41 b(of)h(data)f(ma)m(y)h
+(app)s(ear)f(in)f(a)i(column.)73 b(But)41 b(in)g(order)f(to)i(in)m
+(terpret)f(them,)j(the)e(TDIMn)e(k)m(eyw)m(ord)0 4538
+y(m)m(ust)34 b(app)s(ear)g(in)g(the)g(header.)52 b(Assuming)34
+b(that)h(a)f(\(4,4,4,4\))k(arra)m(y)c(is)h(pac)m(k)m(ed)g(in)m(to)g
+(eac)m(h)h(ro)m(w)e(of)g(a)h(column)0 4650 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)
+g(of)g(eac)m(h)g(ro)m(w)g(is)f(accessed)i(b)m(y)e(ARRA)-8
+b(Y4D[1,2,3,4].)0 4763 y(Arra)m(ys)33 b(up)e(to)j(dimension)e(5)h(are)f
+(curren)m(tly)h(supp)s(orted.)46 b(Eac)m(h)33 b(v)m(ector)h(index)e
+(can)h(itself)g(b)s(e)f(an)h(expression,)0 4876 y(although)39
+b(it)g(m)m(ust)g(ev)-5 b(aluate)40 b(to)f(an)g(in)m(teger)h(v)-5
+b(alue)39 b(within)f(the)h(b)s(ounds)d(of)j(the)g(v)m(ector.)67
+b(V)-8 b(ector)40 b(columns)0 4989 y(whic)m(h)31 b(con)m(tain)h(spaces)
+g(or)f(arithmetic)h(op)s(erators)g(m)m(ust)f(ha)m(v)m(e)h(their)f
+(names)g(enclosed)h(in)f("$")h(c)m(haracters)h(as)0 5102
+y(with)d($ARRA)-8 b(Y-4D$[1,2,3,4].)0 5262 y(A)45 b(more)f(C-lik)m(e)i
+(syn)m(tax)g(for)e(sp)s(ecifying)g(v)m(ector)j(indices)d(is)h(also)h(a)
+m(v)-5 b(ailable.)85 b(The)45 b(elemen)m(t)h(used)d(in)i(the)0
+5375 y(preceding)28 b(example)h(alternativ)m(ely)i(could)d(b)s(e)g(sp)s
+(eci\014ed)g(with)f(the)i(syn)m(tax)g(ARRA)-8 b(Y4D[4][3][2][1].)45
+b(Note)30 b(the)0 5488 y(rev)m(erse)40 b(order)f(of)h(indices)f(\(as)h
+(in)f(C\),)h(as)f(w)m(ell)i(as)e(the)h(fact)g(that)g(the)g(v)-5
+b(alues)40 b(are)f(still)i(ones-based)e(\(as)h(in)0 5601
+y(F)-8 b(ortran)39 b({)g(adopted)g(to)g(a)m(v)m(oid)h(am)m(biguit)m(y)g
+(for)f(1D)g(v)m(ectors\).)67 b(With)39 b(this)g(syn)m(tax,)i(one)e(do)s
+(es)f(not)h(need)f(to)0 5714 y(sp)s(ecify)30 b(all)h(of)g(the)f
+(indices.)41 b(T)-8 b(o)31 b(extract)h(a)f(3D)g(slice)g(of)g(this)f(4D)
+h(arra)m(y)-8 b(,)32 b(use)e(ARRA)-8 b(Y4D[4].)p eop
+end
+%%Page: 140 148
+TeXDict begin 140 147 bop 0 299 a Fj(140)1528 b Fh(CHAPTER)29
+b(10.)113 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fj(V)g(ariable-length)33 b(v)m(ector)f(columns)e(are)g(not)h
+(supp)s(orted.)0 715 y(V)-8 b(ectors)24 b(can)e(b)s(e)f(man)m(ually)h
+(constructed)h(within)e(the)h(expression)g(using)f(a)h(comma-separated)
+i(list)f(of)f(elemen)m(ts)0 828 y(surrounded)35 b(b)m(y)j(curly)g
+(braces)h(\(')p Fc(fg)p Fj('\).)66 b(F)-8 b(or)38 b(example,)j(')p
+Fc(f)p Fj(1,3,6,1)p Fc(g)p Fj(')h(is)d(a)f(4-elemen)m(t)i(v)m(ector)g
+(con)m(taining)g(the)0 941 y(v)-5 b(alues)26 b(1,)h(3,)g(6,)g(and)e(1.)
+40 b(The)25 b(v)m(ector)i(can)f(con)m(tain)h(only)f(b)s(o)s(olean,)g
+(in)m(teger,)j(and)c(real)h(v)-5 b(alues)26 b(\(or)g(expressions\).)0
+1054 y(The)c(elemen)m(ts)i(will)f(b)s(e)f(promoted)h(to)g(the)g
+(highest)g(data)g(t)m(yp)s(e)g(presen)m(t.)38 b(An)m(y)22
+b(elemen)m(ts)i(whic)m(h)f(are)g(themselv)m(es)0 1167
+y(v)m(ectors,)40 b(will)d(b)s(e)f(expanded)g(out)h(with)g(eac)m(h)g(of)
+g(its)g(elemen)m(ts)i(b)s(ecoming)d(an)h(elemen)m(t)h(in)f(the)g
+(constructed)0 1280 y(v)m(ector.)0 1567 y Fd(10.11.4)113
+b(Go)s(o)s(d)38 b(Time)g(In)m(terv)-6 b(al)37 b(Filtering)0
+1786 y Fj(A)44 b(common)g(\014ltering)h(metho)s(d)e(in)m(v)m(olv)m(es)j
+(selecting)g(ro)m(ws)e(whic)m(h)f(ha)m(v)m(e)j(a)e(time)h(v)-5
+b(alue)44 b(whic)m(h)g(lies)g(within)0 1899 y(what)37
+b(is)g(called)i(a)f(Go)s(o)s(d)f(Time)g(In)m(terv)-5
+b(al)38 b(or)f(GTI.)g(The)g(time)h(in)m(terv)-5 b(als)38
+b(are)g(de\014ned)e(in)h(a)g(separate)i(FITS)0 2012 y(table)i
+(extension)g(whic)m(h)e(con)m(tains)i(2)g(columns)f(giving)g(the)h
+(start)f(and)g(stop)g(time)g(of)g(eac)m(h)i(go)s(o)s(d)e(in)m(terv)-5
+b(al.)0 2124 y(The)34 b(\014ltering)h(op)s(eration)h(accepts)g(only)e
+(those)i(ro)m(ws)e(of)h(the)g(input)f(table)i(whic)m(h)e(ha)m(v)m(e)i
+(an)f(asso)s(ciated)h(time)0 2237 y(whic)m(h)f(falls)i(within)e(one)h
+(of)g(the)g(time)g(in)m(terv)-5 b(als)37 b(de\014ned)e(in)g(the)h(GTI)g
+(extension.)57 b(A)36 b(high)g(lev)m(el)h(function,)0
+2350 y(gti\014lter\(a,b,c,d\),)44 b(is)c(a)m(v)-5 b(ailable)42
+b(whic)m(h)d(ev)-5 b(aluates)41 b(eac)m(h)g(ro)m(w)e(of)h(the)f(input)g
+(table)h(and)f(returns)f(TR)m(UE)i(or)0 2463 y(F)-10
+b(ALSE)30 b(dep)s(ending)f(whether)h(the)g(ro)m(w)h(is)f(inside)g(or)g
+(outside)h(the)g(go)s(o)s(d)f(time)h(in)m(terv)-5 b(al.)42
+b(The)30 b(syn)m(tax)h(is)286 2700 y Fe(gtifilter\()45
+b([)j("gtifile")d([,)i(expr)g([,)g("STARTCOL",)e("STOPCOL")g(])j(])f(])
+g(\))191 2812 y(or)286 2925 y(gtifilter\()e([)j('gtifile')d([,)i(expr)g
+([,)g('STARTCOL',)e('STOPCOL')g(])j(])f(])g(\))0 3162
+y Fj(where)20 b(eac)m(h)h("[]")h(demarks)e(optional)h(parameters.)38
+b(Note)21 b(that)g(the)g(quotes)f(around)g(the)g(gti\014le)i(and)d(ST)
+-8 b(AR)g(T/STOP)0 3275 y(column)33 b(are)h(required.)50
+b(Either)34 b(single)g(or)g(double)f(quotes)h(ma)m(y)g(b)s(e)f(used.)50
+b(In)33 b(cases)h(where)g(this)f(expression)0 3387 y(is)d(en)m(tered)g
+(on)g(the)g(Unix)g(command)g(line,)g(enclose)h(the)f(en)m(tire)h
+(expression)f(in)f(double)h(quotes,)g(and)g(then)f(use)0
+3500 y(single)c(quotes)g(within)e(the)i(expression)f(to)h(enclose)g
+(the)g('gti\014le')h(and)d(other)i(terms.)38 b(It)25
+b(is)f(also)h(usually)f(p)s(ossible)0 3613 y(to)38 b(do)e(the)h(rev)m
+(erse,)j(and)c(enclose)i(the)f(whole)g(expression)g(in)f(single)i
+(quotes)f(and)f(then)h(use)f(double)g(quotes)0 3726 y(within)d(the)g
+(expression.)50 b(The)33 b(gti\014le,)i(if)f(sp)s(eci\014ed,)f(can)h(b)
+s(e)f(blank)g(\(""\))i(whic)m(h)e(will)g(mean)h(to)g(use)f(the)h
+(\014rst)0 3839 y(extension)g(with)g(the)f(name)h("*GTI*")h(in)f(the)f
+(curren)m(t)h(\014le,)h(a)f(plain)f(extension)h(sp)s(eci\014er)f(\(eg,)
+j("+2",)g("[2]",)0 3952 y(or)30 b("[STDGTI]"\))i(whic)m(h)e(will)h(b)s
+(e)f(used)f(to)j(select)g(an)e(extension)h(in)f(the)h(curren)m(t)f
+(\014le,)h(or)f(a)h(regular)g(\014lename)0 4065 y(with)f(or)h(without)f
+(an)h(extension)g(sp)s(eci\014er)f(whic)m(h)g(in)g(the)h(latter)h(case)
+f(will)g(mean)f(to)i(use)e(the)h(\014rst)e(extension)0
+4178 y(with)37 b(an)g(extension)g(name)h("*GTI*".)62
+b(Expr)36 b(can)h(b)s(e)g(an)m(y)g(arithmetic)i(expression,)f
+(including)f(simply)g(the)0 4291 y(time)f(column)g(name.)57
+b(A)36 b(v)m(ector)h(time)g(expression)e(will)h(pro)s(duce)f(a)h(v)m
+(ector)h(b)s(o)s(olean)f(result.)57 b(ST)-8 b(AR)g(TCOL)0
+4404 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)i(in)f(the)h(GTI)g(extension.)41
+b(If)27 b(one)h(of)g(them)0 4517 y(is)i(sp)s(eci\014ed,)g(they)h(b)s
+(oth)f(m)m(ust)g(b)s(e.)0 4677 y(In)21 b(its)h(simplest)g(form,)i(no)d
+(parameters)h(need)g(to)h(b)s(e)e(pro)m(vided)g({)h(default)g(v)-5
+b(alues)22 b(will)h(b)s(e)e(used.)37 b(The)21 b(expression)0
+4790 y("gti\014lter\(\)")33 b(is)e(equiv)-5 b(alen)m(t)31
+b(to)334 5026 y Fe(gtifilter\()45 b("",)i(TIME,)f("*START*",)f
+("*STOP*")h(\))0 5262 y Fj(This)31 b(will)g(searc)m(h)h(the)g(curren)m
+(t)f(\014le)g(for)g(a)h(GTI)f(extension,)h(\014lter)g(the)f(TIME)g
+(column)g(in)g(the)h(curren)m(t)f(table,)0 5375 y(using)j(ST)-8
+b(AR)g(T/STOP)34 b(times)i(tak)m(en)f(from)g(columns)f(in)h(the)g(GTI)g
+(extension)g(with)g(names)f(con)m(taining)j(the)0 5488
+y(strings)32 b("ST)-8 b(AR)g(T")33 b(and)e("STOP".)46
+b(The)32 b(wildcards)f(\('*'\))j(allo)m(w)g(sligh)m(t)f(v)-5
+b(ariations)33 b(in)f(naming)g(con)m(v)m(en)m(tions)0
+5601 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)g(v)-5 b(alues)38
+b(apply)g(for)g(unsp)s(eci\014ed)f(parame-)0 5714 y(ters)f(when)f(the)h
+(\014rst)f(one)i(or)f(t)m(w)m(o)h(parameters)f(are)h(sp)s(eci\014ed.)56
+b(The)36 b(function)f(automatically)k(searc)m(hes)e(for)p
+eop end
+%%Page: 141 149
+TeXDict begin 141 148 bop 0 299 a Fh(10.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(141)0
+555 y(TIMEZER)m(O/I/F)37 b(k)m(eyw)m(ords)f(in)g(the)h(curren)m(t)f
+(and)g(GTI)g(extensions,)i(applying)f(a)f(relativ)m(e)j(time)e
+(o\013set,)i(if)0 668 y(necessary)-8 b(.)0 958 y Fd(10.11.5)113
+b(Spatial)38 b(Region)g(Filtering)0 1177 y Fj(Another)g(common)g
+(\014ltering)g(metho)s(d)f(selects)i(ro)m(ws)f(based)g(on)f(whether)h
+(the)g(spatial)h(p)s(osition)e(asso)s(ciated)0 1290 y(with)32
+b(eac)m(h)i(ro)m(w)e(is)h(lo)s(cated)h(within)e(a)h(giv)m(en)g
+(2-dimensional)g(region.)48 b(The)32 b(syn)m(tax)h(for)f(this)h
+(high-lev)m(el)h(\014lter)0 1403 y(is)334 1659 y Fe(regfilter\()45
+b("regfilename")f([)k(,)f(Xexpr,)f(Yexpr)h([)g(,)h("wcs)e(cols")h(])g
+(])g(\))0 1915 y Fj(where)22 b(eac)m(h)i("[]")g(demarks)e(optional)i
+(parameters.)38 b(The)22 b(region)h(\014le)g(name)f(is)h(required)f
+(and)g(m)m(ust)g(b)s(e)g(enclosed)0 2028 y(in)34 b(quotes.)51
+b(The)33 b(remaining)h(parameters)h(are)f(optional.)52
+b(There)33 b(are)i(2)f(supp)s(orted)e(formats)i(for)f(the)h(region)0
+2141 y(\014le:)62 b(ASCI)s(I)39 b(\014le)h(or)h(FITS)f(binary)g(table.)
+73 b(The)40 b(region)h(\014le)g(con)m(tains)h(a)f(list)g(of)g(one)g(or)
+g(more)g(geometric)0 2254 y(shap)s(es)30 b(\(circle,)j(ellipse,)g(b)s
+(o)m(x,)e(etc.\))44 b(whic)m(h)31 b(de\014nes)f(a)i(region)g(on)f(the)g
+(celestial)j(sphere)c(or)h(an)g(area)h(within)f(a)0 2367
+y(particular)36 b(2D)g(image.)57 b(The)35 b(region)h(\014le)f(is)g(t)m
+(ypically)j(generated)e(using)f(an)g(image)i(displa)m(y)e(program)g
+(suc)m(h)0 2480 y(as)e(fv/PO)m(W)g(\(distribute)f(b)m(y)h(the)f(HEASAR)
+m(C\),)h(or)g(ds9)f(\(distributed)g(b)m(y)g(the)h(Smithsonian)f
+(Astroph)m(ysical)0 2593 y(Observ)-5 b(atory\).)69 b(Users)39
+b(should)g(refer)g(to)h(the)g(do)s(cumen)m(tation)h(pro)m(vided)e(with)
+g(these)h(programs)f(for)h(more)0 2706 y(details)29 b(on)f(the)g(syn)m
+(tax)h(used)e(in)h(the)h(region)f(\014les.)40 b(The)28
+b(FITS)f(region)i(\014le)f(format)h(is)f(de\014ned)f(in)h(a)g(do)s
+(cumen)m(t)0 2819 y(a)m(v)-5 b(ailable)33 b(from)d(the)g(FITS)g(Supp)s
+(ort)e(O\016ce)j(at)g(h)m(ttp://\014ts.gsfc.nasa.go)m(v/)k(registry/)c
+(region.h)m(tml)0 2979 y(In)21 b(its)h(simplest)g(form,)i(\(e.g.,)h
+(reg\014lter\("region.reg"\))h(\))c(the)g(co)s(ordinates)g(in)g(the)g
+(default)g('X')h(and)e('Y')h(columns)0 3092 y(will)43
+b(b)s(e)g(used)f(to)i(determine)f(if)g(eac)m(h)h(ro)m(w)f(is)g(inside)g
+(or)g(outside)g(the)g(area)h(sp)s(eci\014ed)e(in)h(the)g(region)h
+(\014le.)0 3204 y(Alternate)32 b(p)s(osition)e(column)g(names,)h(or)f
+(expressions,)h(ma)m(y)g(b)s(e)e(en)m(tered)i(if)g(needed,)f(as)h(in)
+382 3461 y Fe(regfilter\("region.reg",)41 b(XPOS,)47
+b(YPOS\))0 3717 y Fj(Region)37 b(\014ltering)f(can)g(b)s(e)f(applied)g
+(most)h(unam)m(biguously)f(if)h(the)g(p)s(ositions)g(in)f(the)h(region)
+g(\014le)g(and)f(in)h(the)0 3830 y(table)g(to)g(b)s(e)e(\014ltered)h
+(are)h(b)s(oth)e(giv)m(e)j(in)e(terms)g(of)g(absolute)h(celestial)i(co)
+s(ordinate)e(units.)54 b(In)35 b(this)g(case)h(the)0
+3943 y(lo)s(cations)26 b(and)d(sizes)i(of)g(the)f(geometric)i(shap)s
+(es)e(in)g(the)g(region)h(\014le)f(are)h(sp)s(eci\014ed)f(in)g(angular)
+g(units)g(on)g(the)g(sky)0 4056 y(\(e.g.,)32 b(p)s(ositions)e(giv)m(en)
+i(in)e(R.A.)g(and)g(Dec.)42 b(and)30 b(sizes)h(in)f(arcseconds)g(or)h
+(arcmin)m(utes\).)41 b(Similarly)-8 b(,)31 b(eac)m(h)h(ro)m(w)0
+4168 y(of)h(the)h(\014ltered)f(table)h(will)f(ha)m(v)m(e)i(a)e
+(celestial)j(co)s(ordinate)e(asso)s(ciated)g(with)f(it.)50
+b(This)32 b(asso)s(ciation)j(is)e(usually)0 4281 y(implemen)m(ted)39
+b(using)e(a)i(set)g(of)f(so-called)i('W)-8 b(orld)39
+b(Co)s(ordinate)g(System')f(\(or)h(W)m(CS\))f(FITS)g(k)m(eyw)m(ords)g
+(that)0 4394 y(de\014ne)27 b(the)g(co)s(ordinate)h(transformation)g
+(that)g(m)m(ust)f(b)s(e)f(applied)h(to)h(the)g(v)-5 b(alues)27
+b(in)g(the)h('X')g(and)e('Y')i(columns)0 4507 y(to)j(calculate)i(the)d
+(co)s(ordinate.)0 4667 y(Alternativ)m(ely)-8 b(,)30 b(one)d(can)g(p)s
+(erform)e(spatial)j(\014ltering)e(using)g(unitless)h('pixel')g(co)s
+(ordinates)h(for)e(the)h(regions)g(and)0 4780 y(ro)m(w)33
+b(p)s(ositions.)49 b(In)33 b(this)g(case)h(the)f(user)g(m)m(ust)g(b)s
+(e)f(careful)h(to)h(ensure)f(that)g(the)h(p)s(ositions)f(in)g(the)g(2)g
+(\014les)h(are)0 4893 y(self-consisten)m(t.)54 b(A)34
+b(t)m(ypical)i(problem)d(is)h(that)h(the)f(region)h(\014le)f(ma)m(y)h
+(b)s(e)e(generated)j(using)d(a)i(binned)d(image,)0 5006
+y(but)g(the)h(un)m(binned)e(co)s(ordinates)i(are)g(giv)m(en)h(in)e(the)
+h(ev)m(en)m(t)i(table.)48 b(The)32 b(R)m(OSA)-8 b(T)33
+b(ev)m(en)m(ts)h(\014les,)g(for)e(example,)0 5119 y(ha)m(v)m(e)f(X)f
+(and)f(Y)g(pixel)h(co)s(ordinates)g(that)h(range)f(from)f(1)h(-)g
+(15360.)42 b(These)30 b(co)s(ordinates)g(are)g(t)m(ypically)h(binned)0
+5232 y(b)m(y)i(a)h(factor)g(of)f(32)h(to)g(pro)s(duce)e(a)i(480x480)i
+(pixel)d(image.)51 b(If)32 b(one)i(then)f(uses)g(a)g(region)h(\014le)f
+(generated)h(from)0 5345 y(this)c(image)i(\(in)f(image)g(pixel)g
+(units\))g(to)g(\014lter)f(the)h(R)m(OSA)-8 b(T)30 b(ev)m(en)m(ts)i
+(\014le,)f(then)f(the)h(X)g(and)f(Y)g(column)h(v)-5 b(alues)0
+5458 y(m)m(ust)30 b(b)s(e)g(con)m(v)m(erted)i(to)f(corresp)s(onding)e
+(pixel)i(units)f(as)g(in:)382 5714 y Fe(regfilter\("rosat.reg",)42
+b(X/32.+.5,)j(Y/32.+.5\))p eop end
+%%Page: 142 150
+TeXDict begin 142 149 bop 0 299 a Fj(142)1528 b Fh(CHAPTER)29
+b(10.)113 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fj(Note)46 b(that)f(this)f(binning)f(con)m(v)m(ersion)j(is)e(not)
+h(necessary)g(if)f(the)h(region)g(\014le)f(is)h(sp)s(eci\014ed)e(using)
+h(celestial)0 668 y(co)s(ordinate)h(units)f(instead)g(of)g(pixel)h
+(units)f(b)s(ecause)g(CFITSIO)e(is)j(then)e(able)i(to)g(directly)g
+(compare)g(the)0 781 y(celestial)30 b(co)s(ordinate)f(of)e(eac)m(h)i
+(ro)m(w)f(in)f(the)h(table)g(with)g(the)f(celestial)k(co)s(ordinates)d
+(in)f(the)h(region)g(\014le)g(without)0 894 y(ha)m(ving)j(to)g(kno)m(w)
+f(an)m(ything)h(ab)s(out)f(ho)m(w)h(the)f(image)i(ma)m(y)f(ha)m(v)m(e)g
+(b)s(een)f(binned.)0 1054 y(The)f(last)h("w)m(cs)g(cols")h(parameter)f
+(should)e(rarely)h(b)s(e)g(needed.)40 b(If)29 b(supplied,)f(this)i
+(string)f(con)m(tains)i(the)e(names)0 1167 y(of)37 b(the)g(2)h(columns)
+f(\(space)h(or)f(comma)g(separated\))h(whic)m(h)f(ha)m(v)m(e)h(the)g
+(asso)s(ciated)g(W)m(CS)f(k)m(eyw)m(ords.)61 b(If)37
+b(not)0 1280 y(supplied,)f(the)g(\014lter)g(will)h(scan)f(the)g(X)g
+(and)f(Y)h(expressions)g(for)g(column)f(names.)58 b(If)35
+b(only)h(one)h(is)f(found)e(in)0 1393 y(eac)m(h)e(expression,)e(those)h
+(columns)f(will)h(b)s(e)e(used,)h(otherwise)h(an)f(error)g(will)h(b)s
+(e)f(returned.)0 1553 y(These)g(region)h(shap)s(es)f(are)g(supp)s
+(orted)f(\(names)h(are)h(case)h(insensitiv)m(e\):)334
+1817 y Fe(Point)428 b(\()48 b(X1,)f(Y1)g(\))715 b(<-)48
+b(One)f(pixel)f(square)g(region)334 1930 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 2043 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 2156 y(Rectangle)236
+b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2,)h(A)h(\))334 b(|)47 b(boundaries)e
+(considered)334 2269 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 2382 y(Diamond)332
+b(\()48 b(Xc,)f(Yc,)g(Wdth,)f(Hght,)g(A)i(\))334 2494
+y(Circle)380 b(\()48 b(Xc,)f(Yc,)g(R)g(\))334 2607 y(Annulus)332
+b(\()48 b(Xc,)f(Yc,)g(Rin,)f(Rout)h(\))334 2720 y(Ellipse)332
+b(\()48 b(Xc,)f(Yc,)g(Rx,)f(Ry,)h(A)h(\))334 2833 y(Elliptannulus)c(\()
+k(Xc,)f(Yc,)g(Rinx,)f(Riny,)g(Routx,)g(Routy,)g(Ain,)h(Aout)g(\))334
+2946 y(Sector)380 b(\()48 b(Xc,)f(Yc,)g(Amin,)f(Amax)h(\))0
+3210 y Fj(where)28 b(\(Xc,Yc\))j(is)d(the)h(co)s(ordinate)h(of)e(the)h
+(shap)s(e's)f(cen)m(ter;)j(\(X#,Y#\))e(are)g(the)g(co)s(ordinates)g(of)
+g(the)g(shap)s(e's)0 3323 y(edges;)39 b(Rxxx)c(are)g(the)h(shap)s(es')f
+(v)-5 b(arious)35 b(Radii)h(or)f(semima)5 b(jor/minor)36
+b(axes;)i(and)d(Axxx)g(are)h(the)g(angles)g(of)0 3436
+y(rotation)d(\(or)e(b)s(ounding)f(angles)i(for)f(Sector\))h(in)f
+(degrees.)44 b(F)-8 b(or)32 b(rotated)h(shap)s(es,)e(the)g(rotation)i
+(angle)f(can)g(b)s(e)0 3549 y(left)g(o\013,)h(indicating)f(no)f
+(rotation.)46 b(Common)31 b(alternate)i(names)e(for)h(the)f(regions)h
+(can)g(also)h(b)s(e)d(used:)43 b(rotb)s(o)m(x)0 3662
+y(=)29 b(b)s(o)m(x;)g(rotrectangle)i(=)e(rectangle;)i(\(rot\)rhom)m
+(bus)e(=)f(\(rot\)diamond;)j(and)d(pie)h(=)f(sector.)42
+b(When)28 b(a)i(shap)s(e's)0 3775 y(name)e(is)g(preceded)f(b)m(y)h(a)g
+(min)m(us)g(sign,)g('-',)i(the)e(de\014ned)e(region)j(is)f(instead)g
+(the)g(area)h(*outside*)g(its)f(b)s(oundary)0 3888 y(\(ie,)36
+b(the)e(region)h(is)f(in)m(v)m(erted\).)53 b(All)34 b(the)g(shap)s(es)f
+(within)h(a)g(single)h(region)f(\014le)h(are)f(OR'd)f(together)j(to)e
+(create)0 4000 y(the)29 b(region,)i(and)d(the)i(order)f(is)g
+(signi\014can)m(t.)41 b(The)29 b(o)m(v)m(erall)i(w)m(a)m(y)g(of)e(lo)s
+(oking)h(at)g(region)g(\014les)f(is)g(that)h(if)f(the)h(\014rst)0
+4113 y(region)f(is)g(an)g(excluded)g(region)g(then)f(a)i(dumm)m(y)d
+(included)h(region)i(of)f(the)g(whole)g(detector)h(is)f(inserted)f(in)h
+(the)0 4226 y(fron)m(t.)40 b(Then)25 b(eac)m(h)j(region)f(sp)s
+(eci\014cation)h(as)f(it)g(is)g(pro)s(cessed)f(o)m(v)m(errides)h(an)m
+(y)g(selections)i(inside)d(of)h(that)g(region)0 4339
+y(sp)s(eci\014ed)36 b(b)m(y)g(previous)g(regions.)59
+b(Another)37 b(w)m(a)m(y)g(of)g(thinking)f(ab)s(out)g(this)g(is)h(that)
+g(if)f(a)h(previous)f(excluded)0 4452 y(region)31 b(is)f(completely)i
+(inside)f(of)f(a)h(subsequen)m(t)e(included)h(region)h(the)g(excluded)f
+(region)h(is)f(ignored.)0 4612 y(The)44 b(p)s(ositional)i(co)s
+(ordinates)g(ma)m(y)f(b)s(e)g(giv)m(en)h(either)f(in)g(pixel)g(units,)j
+(decimal)e(degrees)g(or)f(hh:mm:ss.s,)0 4725 y(dd:mm:ss.s)25
+b(units.)38 b(The)26 b(shap)s(e)f(sizes)i(ma)m(y)f(b)s(e)g(giv)m(en)h
+(in)e(pixels,)j(degrees,)f(arcmin)m(utes,)h(or)e(arcseconds.)40
+b(Lo)s(ok)0 4838 y(at)31 b(examples)g(of)f(region)h(\014le)g(pro)s
+(duced)d(b)m(y)i(fv/PO)m(W)h(or)g(ds9)f(for)g(further)f(details)i(of)g
+(the)f(region)h(\014le)f(format.)0 4998 y(There)h(are)g(three)h(lo)m
+(w-lev)m(el)i(functions)d(that)g(are)h(primarily)f(for)g(use)g(with)g
+(reg\014lter)g(function,)h(but)e(they)i(can)0 5111 y(b)s(e)j(called)i
+(directly)-8 b(.)59 b(They)35 b(return)g(a)h(b)s(o)s(olean)g(true)g(or)
+g(false)h(dep)s(ending)d(on)i(whether)f(a)i(t)m(w)m(o)g(dimensional)0
+5224 y(p)s(oin)m(t)30 b(is)h(in)f(the)g(region)h(or)g(not.)41
+b(The)30 b(p)s(ositional)h(co)s(ordinates)g(m)m(ust)f(b)s(e)g(giv)m(en)
+h(in)f(pixel)h(units:)191 5488 y Fe("point)46 b(in)h(a)h(circular)d
+(region")477 5601 y(circle\(xcntr,ycntr,radius)o(,Xco)o(lumn)o(,Yc)o
+(olum)o(n\))p eop end
+%%Page: 143 151
+TeXDict begin 143 150 bop 0 299 a Fh(10.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)31 b(SPECIFICA)-8 b(TION)1936 b Fj(143)191
+555 y Fe("point)46 b(in)h(an)g(elliptical)e(region")430
+668 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 894 y("point)h(in)h(a)h
+(rectangular)c(region")620 1007 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
+1233 y(where)334 1346 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
+1458 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 1571 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
+1684 y(\(radius\))f(is)h(half)f(the)h(diameter)f(of)h(the)g(circle)334
+1797 y(\(rotation\))e(is)i(the)g(angle\(degrees\))d(that)j(the)g
+(region)f(is)h(rotated)f(with)620 1910 y(respect)g(to)h
+(\(xcntr,ycntr\))334 2023 y(\(Xcoord,Ycoord\))d(are)j(the)g(\(x,y\))f
+(coordinates)f(to)i(test,)f(usually)g(column)620 2136
+y(names)334 2249 y(NOTE:)g(each)h(parameter)e(can)i(itself)f(be)i(an)f
+(expression,)d(not)j(merely)f(a)620 2362 y(column)h(name)f(or)h
+(constant.)0 2669 y Fd(10.11.6)113 b(Example)38 b(Ro)m(w)f(Filters)191
+2891 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 3004
+y(than)94 b(fifth)47 b(magnitude)e(\(note)h(that)1766
+3117 y(the)h(initial)f(space)g(is)h(necessary)e(to)1766
+3230 y(prevent)h(it)h(from)g(being)f(treated)g(as)h(a)1766
+3343 y(binning)f(specification\))191 3569 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 3794 y([IMAGE[4,5])f(.gt.)h(100])476 b(-)48
+b(Extract)e(all)h(rows)f(that)h(have)g(the)1766 3907
+y(\(4,5\))f(component)g(of)h(the)g(IMAGE)f(column)1766
+4020 y(greater)g(than)g(100)191 4246 y([abs\(sin\(theta)e(*)j(#deg\)\))
+f(<)i(0.5])e(-)i(Extract)e(all)h(rows)f(having)g(the)1766
+4359 y(absolute)f(value)i(of)g(the)g(sine)g(of)g(theta)1766
+4472 y(less)94 b(than)47 b(a)g(half)g(where)f(the)h(angles)1766
+4585 y(are)g(tabulated)e(in)i(degrees)191 4811 y([SUM\()f(SPEC)h(>)g
+(3*BACKGRND)e(\)>=1])94 b(-)48 b(Extract)e(all)h(rows)f(containing)f(a)
+1766 4924 y(spectrum,)g(held)i(in)g(vector)f(column)1766
+5036 y(SPEC,)g(with)h(at)g(least)f(one)h(value)g(3)1766
+5149 y(times)f(greater)g(than)h(the)g(background)1766
+5262 y(level)f(held)h(in)g(a)h(keyword,)d(BACKGRND)191
+5488 y([VCOL=={1,4,2}])759 b(-)48 b(Extract)e(all)h(rows)f(whose)h
+(vector)f(column)1766 5601 y(VCOL)h(contains)e(the)i(3-elements)e(1,)i
+(4,)g(and)1766 5714 y(2.)p eop end
+%%Page: 144 152
+TeXDict begin 144 151 bop 0 299 a Fj(144)1528 b Fh(CHAPTER)29
+b(10.)113 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)191
+668 y Fe([@rowFilter.txt])711 b(-)48 b(Extract)e(rows)g(using)h(the)g
+(expression)1766 781 y(contained)e(within)h(the)h(text)g(file)1766
+894 y(rowFilter.txt)191 1120 y([gtifilter\(\)])855 b(-)48
+b(Search)e(the)h(current)f(file)g(for)h(a)h(GTI)239 1233
+y(extension,)92 b(filter)i(the)47 b(TIME)239 1346 y(column)f(in)h(the)g
+(current)f(table,)g(using)239 1458 y(START/STOP)f(times)h(taken)g(from)
+239 1571 y(columns)f(in)j(the)f(GTI)94 b(extension)191
+1797 y([regfilter\("pow.reg"\)])423 b(-)48 b(Extract)e(rows)g(which)h
+(have)f(a)i(coordinate)1766 1910 y(\(as)f(given)f(in)h(the)g(X)h(and)f
+(Y)g(columns\))1766 2023 y(within)f(the)h(spatial)f(region)g(specified)
+1766 2136 y(in)h(the)g(pow.reg)f(region)g(file.)191 2362
+y([regfilter\("pow.reg",)c(Xs,)47 b(Ys\)])f(-)i(Same)f(as)g(above,)f
+(except)g(that)h(the)1766 2475 y(Xs)g(and)g(Ys)g(columns)f(will)h(be)g
+(used)f(to)1766 2588 y(determine)f(the)i(coordinate)e(of)i(each)1766
+2700 y(row)g(in)g(the)g(table.)0 3027 y Ff(10.12)181
+b(Binning)44 b(or)h(Histogramming)i(Sp)t(eci\014cation)0
+3277 y Fj(The)22 b(optional)i(binning)e(sp)s(eci\014er)g(is)h(enclosed)
+h(in)f(square)f(brac)m(k)m(ets)j(and)d(can)h(b)s(e)f(distinguished)g
+(from)h(a)g(general)0 3390 y(ro)m(w)32 b(\014lter)h(sp)s(eci\014cation)
+g(b)m(y)f(the)h(fact)g(that)g(it)g(b)s(egins)f(with)g(the)g(k)m(eyw)m
+(ord)h('bin')f(not)h(immediately)g(follo)m(w)m(ed)0 3503
+y(b)m(y)41 b(an)f(equals)i(sign.)72 b(When)41 b(binning)e(is)i(sp)s
+(eci\014ed,)i(a)e(temp)s(orary)g(N-dimensional)g(FITS)f(primary)g(arra)
+m(y)0 3615 y(is)j(created)h(b)m(y)f(computing)h(the)f(histogram)h(of)f
+(the)g(v)-5 b(alues)44 b(in)e(the)i(sp)s(eci\014ed)e(columns)h(of)g(a)h
+(FITS)e(table)0 3728 y(extension.)f(After)30 b(the)f(histogram)h(is)g
+(computed)f(the)h(input)e(FITS)h(\014le)h(con)m(taining)h(the)e(table)i
+(is)e(then)g(closed)0 3841 y(and)34 b(the)h(temp)s(orary)f(FITS)g
+(primary)g(arra)m(y)h(is)g(op)s(ened)f(and)g(passed)g(to)h(the)g
+(application)h(program.)54 b(Th)m(us,)0 3954 y(the)39
+b(application)h(program)f(nev)m(er)g(sees)g(the)g(original)h(FITS)e
+(table)i(and)e(only)h(sees)h(the)f(image)h(in)e(the)h(new)0
+4067 y(temp)s(orary)32 b(\014le)h(\(whic)m(h)g(has)f(no)h(additional)g
+(extensions\).)49 b(Ob)m(viously)-8 b(,)34 b(the)f(application)h
+(program)e(m)m(ust)h(b)s(e)0 4180 y(exp)s(ecting)e(to)g(op)s(en)f(a)h
+(FITS)e(image)j(and)e(not)g(a)h(FITS)f(table)h(in)f(this)g(case.)0
+4340 y(The)g(data)h(t)m(yp)s(e)f(of)h(the)f(FITS)g(histogram)g(image)i
+(ma)m(y)f(b)s(e)f(sp)s(eci\014ed)f(b)m(y)h(app)s(ending)f('b')h(\(for)h
+(8-bit)g(b)m(yte\),)g('i')0 4453 y(\(for)g(16-bit)g(in)m(tegers\),)h
+('j')f(\(for)g(32-bit)g(in)m(teger\),)i('r')d(\(for)h(32-bit)g
+(\015oating)h(p)s(oin)m(ts\),)e(or)h('d')f(\(for)h(64-bit)g(double)0
+4566 y(precision)j(\015oating)i(p)s(oin)m(t\))e(to)h(the)g('bin')f(k)m
+(eyw)m(ord)h(\(e.g.)54 b('[binr)33 b(X]')i(creates)h(a)f(real)g
+(\015oating)g(p)s(oin)m(t)f(image\).)0 4679 y(If)g(the)i(data)f(t)m(yp)
+s(e)g(is)g(not)h(explicitly)g(sp)s(eci\014ed)e(then)h(a)g(32-bit)i(in)m
+(teger)f(image)g(will)f(b)s(e)g(created)h(b)m(y)e(default,)0
+4792 y(unless)24 b(the)i(w)m(eigh)m(ting)g(option)g(is)f(also)h(sp)s
+(eci\014ed)e(in)h(whic)m(h)g(case)h(the)f(image)i(will)e(ha)m(v)m(e)h
+(a)g(32-bit)g(\015oating)g(p)s(oin)m(t)0 4905 y(data)31
+b(t)m(yp)s(e)g(b)m(y)f(default.)0 5065 y(The)24 b(histogram)g(image)i
+(ma)m(y)f(ha)m(v)m(e)g(from)f(1)g(to)h(4)g(dimensions)e(\(axes\),)k
+(dep)s(ending)c(on)h(the)g(n)m(um)m(b)s(er)f(of)h(columns)0
+5178 y(that)31 b(are)g(sp)s(eci\014ed.)40 b(The)30 b(general)h(form)f
+(of)g(the)h(binning)e(sp)s(eci\014cation)i(is:)48 5389
+y Fe([bin{bijrd})92 b(Xcol=min:max:binsize,)42 b(Ycol=)47
+b(...,)f(Zcol=...,)f(Tcol=...;)h(weight])0 5601 y Fj(in)39
+b(whic)m(h)g(up)f(to)i(4)g(columns,)h(eac)m(h)f(corresp)s(onding)e(to)i
+(an)g(axis)f(of)h(the)f(image,)k(are)d(listed.)67 b(The)39
+b(column)0 5714 y(names)27 b(are)h(case)h(insensitiv)m(e,)g(and)e(the)h
+(column)f(n)m(um)m(b)s(er)f(ma)m(y)i(b)s(e)f(giv)m(en)h(instead)g(of)g
+(the)g(name,)g(preceded)f(b)m(y)p eop end
+%%Page: 145 153
+TeXDict begin 145 152 bop 0 299 a Fh(10.12.)113 b(BINNING)32
+b(OR)e(HISTOGRAMMING)g(SPECIFICA)-8 b(TION)1223 b Fj(145)0
+555 y(a)32 b(p)s(ound)e(sign)i(\(e.g.,)i([bin)d(#4=1:512]\).)47
+b(If)31 b(the)h(column)g(name)g(is)f(not)h(sp)s(eci\014ed,)g(then)f
+(CFITSIO)g(will)h(\014rst)0 668 y(try)37 b(to)h(use)f(the)g('preferred)
+f(column')i(as)f(sp)s(eci\014ed)g(b)m(y)g(the)g(CPREF)g(k)m(eyw)m(ord)h
+(if)f(it)g(exists)h(\(e.g.,)j('CPREF)0 781 y(=)i('DETX,DETY'\),)h
+(otherwise)g(column)f(names)g('X',)h('Y',)g('Z',)f(and)f('T')i(will)f
+(b)s(e)f(assumed)h(for)g(eac)m(h)h(of)0 894 y(the)37
+b(4)h(axes,)i(resp)s(ectiv)m(ely)-8 b(.)62 b(In)37 b(cases)h(where)e
+(the)i(column)f(name)g(could)g(b)s(e)f(confused)h(with)g(an)g
+(arithmetic)0 1007 y(expression,)30 b(enclose)i(the)f(column)f(name)g
+(in)g(paren)m(theses)h(to)g(force)g(the)f(name)h(to)g(b)s(e)f(in)m
+(terpreted)g(literally)-8 b(.)0 1167 y(Eac)m(h)33 b(column)f(name)g(ma)
+m(y)h(b)s(e)f(follo)m(w)m(ed)h(b)m(y)g(an)f(equals)g(sign)h(and)e(then)
+h(the)g(lo)m(w)m(er)i(and)e(upp)s(er)e(range)i(of)h(the)0
+1280 y(histogram,)f(and)e(the)h(size)h(of)f(the)g(histogram)h(bins,)e
+(separated)h(b)m(y)g(colons.)43 b(Spaces)31 b(are)g(allo)m(w)m(ed)i(b)s
+(efore)e(and)0 1393 y(after)e(the)g(equals)g(sign)f(but)g(not)h(within)
+f(the)h('min:max:binsize')g(string.)40 b(The)29 b(min,)f(max)h(and)f
+(binsize)h(v)-5 b(alues)0 1506 y(ma)m(y)32 b(b)s(e)e(in)m(teger)i(or)f
+(\015oating)h(p)s(oin)m(t)f(n)m(um)m(b)s(ers,)f(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)g(the)g(header)g(of)0
+1619 y(the)g(table.)41 b(If)30 b(the)h(latter,)h(then)e(the)g(v)-5
+b(alue)31 b(of)g(that)g(k)m(eyw)m(ord)f(is)h(substituted)f(in)m(to)h
+(the)g(expression.)0 1779 y(Default)37 b(v)-5 b(alues)36
+b(for)g(the)g(min,)h(max)f(and)g(binsize)g(quan)m(tities)h(will)f(b)s
+(e)f(used)h(if)f(not)i(explicitly)g(giv)m(en)g(in)f(the)0
+1892 y(binning)29 b(expression)h(as)h(sho)m(wn)f(in)g(these)h
+(examples:)191 2118 y Fe([bin)47 b(x)g(=)g(:512:2])94
+b(-)47 b(use)g(default)f(minimum)g(value)191 2231 y([bin)h(x)g(=)g
+(1::2])190 b(-)47 b(use)g(default)f(maximum)g(value)191
+2344 y([bin)h(x)g(=)g(1:512])142 b(-)47 b(use)g(default)f(bin)h(size)
+191 2457 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 2570 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
+2682 y([bin)g(x)g(=)g(2])334 b(-)47 b(use)g(default)f(minimum)g(and)h
+(maximum)f(values)191 2795 y([bin)h(x])524 b(-)47 b(use)g(default)f
+(minimum,)g(maximum)g(and)g(bin)h(size)191 2908 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 3021 y([bin])619 b(-)47 b(default)f(2-D)h(image)0
+3247 y Fj(CFITSIO)31 b(will)i(use)f(the)h(v)-5 b(alue)33
+b(of)g(the)g(TLMINn,)f(TLMAXn,)h(and)f(TDBINn)h(k)m(eyw)m(ords,)h(if)e
+(they)h(exist,)h(for)0 3360 y(the)j(default)f(min,)i(max,)g(and)e
+(binsize,)i(resp)s(ectiv)m(ely)-8 b(.)61 b(If)36 b(they)h(do)f(not)h
+(exist)g(then)f(CFITSIO)f(will)i(use)f(the)0 3473 y(actual)d(minim)m
+(um)e(and)h(maxim)m(um)g(v)-5 b(alues)32 b(in)g(the)g(column)f(for)h
+(the)g(histogram)h(min)e(and)h(max)g(v)-5 b(alues.)45
+b(The)0 3586 y(default)34 b(binsize)f(will)h(b)s(e)f(set)h(to)h(1,)g
+(or)e(\(max)h(-)g(min\))f(/)h(10.,)i(whic)m(hev)m(er)e(is)g(smaller,)h
+(so)e(that)i(the)e(histogram)0 3699 y(will)e(ha)m(v)m(e)g(at)g(least)h
+(10)f(bins)f(along)h(eac)m(h)h(axis.)0 3859 y(A)41 b(shortcut)g
+(notation)h(is)f(allo)m(w)m(ed)i(if)e(all)h(the)f(columns/axes)h(ha)m
+(v)m(e)g(the)f(same)g(binning)f(sp)s(eci\014cation.)74
+b(In)0 3972 y(this)33 b(case)g(all)h(the)f(column)f(names)h(ma)m(y)g(b)
+s(e)f(listed)h(within)f(paren)m(theses,)i(follo)m(w)m(ed)h(b)m(y)d(the)
+h(\(single\))h(binning)0 4085 y(sp)s(eci\014cation,)d(as)g(in:)191
+4311 y Fe([bin)47 b(\(X,Y\)=1:512:2])191 4424 y([bin)g(\(X,Y\))f(=)h
+(5])0 4650 y Fj(The)31 b(optional)i(w)m(eigh)m(ting)h(factor)e(is)g
+(the)g(last)g(item)h(in)e(the)h(binning)f(sp)s(eci\014er)g(and,)h(if)f
+(presen)m(t,)i(is)e(separated)0 4763 y(from)38 b(the)g(list)h(of)f
+(columns)g(b)m(y)g(a)h(semi-colon.)65 b(As)39 b(the)f(histogram)h(is)f
+(accum)m(ulated,)k(this)c(w)m(eigh)m(t)i(is)e(used)0
+4876 y(to)d(incremen)m(ted)f(the)g(v)-5 b(alue)35 b(of)f(the)g
+(appropriated)f(bin)h(in)f(the)h(histogram.)52 b(If)34
+b(the)g(w)m(eigh)m(ting)i(factor)f(is)f(not)0 4989 y(sp)s(eci\014ed,)24
+b(then)f(the)g(default)g(w)m(eigh)m(t)i(=)d(1)i(is)f(assumed.)37
+b(The)23 b(w)m(eigh)m(ting)i(factor)f(ma)m(y)f(b)s(e)g(a)g(constan)m(t)
+i(in)m(teger)f(or)0 5102 y(\015oating)30 b(p)s(oin)m(t)f(n)m(um)m(b)s
+(er,)f(or)h(the)g(name)g(of)g(a)g(k)m(eyw)m(ord)h(con)m(taining)g(the)g
+(w)m(eigh)m(ting)g(v)-5 b(alue.)41 b(Or)28 b(the)h(w)m(eigh)m(ting)0
+5215 y(factor)g(ma)m(y)g(b)s(e)e(the)h(name)g(of)h(a)f(table)h(column)f
+(in)g(whic)m(h)f(case)j(the)e(v)-5 b(alue)28 b(in)g(that)h(column,)f
+(on)g(a)h(ro)m(w)f(b)m(y)g(ro)m(w)0 5328 y(basis,)i(will)h(b)s(e)f
+(used.)0 5488 y(In)35 b(some)h(cases,)i(the)d(column)h(or)f(k)m(eyw)m
+(ord)h(ma)m(y)g(giv)m(e)h(the)f(recipro)s(cal)g(of)g(the)g(actual)h(w)m
+(eigh)m(t)g(v)-5 b(alue)36 b(that)g(is)0 5601 y(needed.)49
+b(In)32 b(this)h(case,)i(precede)e(the)h(w)m(eigh)m(t)g(k)m(eyw)m(ord)g
+(or)f(column)g(name)g(b)m(y)g(a)g(slash)g('/')h(to)g(tell)g(CFITSIO)0
+5714 y(to)d(use)f(the)h(recipro)s(cal)g(of)f(the)h(v)-5
+b(alue)31 b(when)e(constructing)i(the)g(histogram.)p
+eop end
+%%Page: 146 154
+TeXDict begin 146 153 bop 0 299 a Fj(146)1528 b Fh(CHAPTER)29
+b(10.)113 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fj(F)g(or)25 b(complex)g(or)f(commonly)g(used)g(histograms,)i
+(one)e(can)h(also)g(place)g(its)f(description)g(in)m(to)h(a)g(text)g
+(\014le)f(and)g(im-)0 668 y(p)s(ort)e(it)g(in)m(to)h(the)g(binning)e
+(sp)s(eci\014cation)i(using)e(the)i(syn)m(tax)f([bin)g
+(@\014lename.txt].)39 b(The)22 b(\014le's)g(con)m(ten)m(ts)i(can)e(ex-)
+0 781 y(tend)h(o)m(v)m(er)i(m)m(ultiple)f(lines,)h(although)f(it)g(m)m
+(ust)f(still)h(conform)f(to)h(the)g(no-spaces)g(rule)f(for)g(the)h
+(min:max:binsize)0 894 y(syn)m(tax)35 b(and)f(eac)m(h)h(axis)g(sp)s
+(eci\014cation)h(m)m(ust)e(still)h(b)s(e)f(comma-separated.)55
+b(An)m(y)34 b(lines)h(in)f(the)h(external)g(text)0 1007
+y(\014le)27 b(that)g(b)s(egin)g(with)f(2)i(slash)e(c)m(haracters)j
+(\('//'\))g(will)e(b)s(e)f(ignored)h(and)f(ma)m(y)i(b)s(e)e(used)g(to)i
+(add)e(commen)m(ts)i(in)m(to)0 1120 y(the)j(\014le.)0
+1280 y(Examples:)191 1540 y Fe([bini)46 b(detx,)h(dety])762
+b(-)47 b(2-D,)g(16-bit)f(integer)g(histogram)1861 1653
+y(of)i(DETX)e(and)h(DETY)g(columns,)e(using)1861 1766
+y(default)h(values)g(for)h(the)g(histogram)1861 1878
+y(range)g(and)g(binsize)191 2104 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
+2217 y(and)g(DETY)g(columns)f(with)g(a)i(bin)f(size)f(=)i(16)1861
+2330 y(in)g(both)e(axes.)h(The)f(histogram)g(values)1861
+2443 y(are)h(divided)f(by)h(the)g(EXPOSURE)f(keyword)1861
+2556 y(value.)191 2782 y([bin)h(time=TSTART:TSTOP:0.1])280
+b(-)47 b(1-D)g(lightcurve,)e(range)h(determined)f(by)1861
+2895 y(the)i(TSTART)f(and)h(TSTOP)g(keywords,)1861 3008
+y(with)g(0.1)g(unit)g(size)f(bins.)191 3233 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 3346 y(of)i(the)e(PHA)h(column)f(for)h(the)g(X)h(axis,)
+1861 3459 y(and)f(1000)g(bins)g(in)g(the)g(range)1861
+3572 y(8000.)g(to)g(8100.)f(for)h(the)g(Y)h(axis.)191
+3798 y([bin)f(@binFilter.txt])616 b(-)47 b(Use)g(the)g(contents)f(of)h
+(the)g(text)f(file)1861 3911 y(binFilter.txt)f(for)h(the)h(binning)1861
+4024 y(specifications.)p eop end
+%%Page: 147 155
+TeXDict begin 147 154 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)h(is)g(created)g(with)g(a)f(call)i(to)g
+(\014ts)p 2101 2180 28 4 v 32 w(create)p 2369 2180 V
+35 w(\014le,)g(the)f(name)g(of)g(a)g(template)h(\014le)e(ma)m(y)0
+2293 y(b)s(e)h(supplied)g(in)h(paren)m(theses)g(immediately)h(follo)m
+(wing)g(the)g(name)f(of)g(the)g(new)f(\014le)h(to)h(b)s(e)e(created.)71
+b(This)0 2406 y(template)27 b(is)e(used)g(to)h(de\014ne)f(the)h
+(structure)f(of)h(one)f(or)h(more)g(HDUs)g(in)f(the)h(new)f(\014le.)39
+b(The)25 b(template)i(\014le)e(ma)m(y)0 2518 y(b)s(e)32
+b(another)h(FITS)f(\014le,)i(in)f(whic)m(h)f(case)i(the)f(newly)g
+(created)h(\014le)f(will)g(ha)m(v)m(e)h(exactly)h(the)e(same)g(k)m(eyw)
+m(ords)g(in)0 2631 y(eac)m(h)25 b(HDU)g(as)g(in)f(the)g(template)i
+(FITS)d(\014le,)j(but)d(all)j(the)e(data)h(units)e(will)i(b)s(e)f
+(\014lled)g(with)f(zeros.)40 b(The)24 b(template)0 2744
+y(\014le)i(ma)m(y)h(also)g(b)s(e)e(an)h(ASCI)s(I)e(text)j(\014le,)g
+(where)f(eac)m(h)h(line)f(\(in)g(general\))i(describ)s(es)d(one)h(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)i(\014le)g(is)f(describ)s(ed)f(in)i(the)f(follo)m(wing)i
+(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)k(line)f(closely)h(follo)
+m(ws)f(the)g(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)f(sign)h(ma)m(y)f(app)s(ear)g(at)h(an)m(y)g
+(p)s(osition)f(in)g(the)h(line\))g(and)0 4039 y(T)-8
+b(AB)34 b(c)m(haracters)g(are)g(allo)m(w)m(ed)h(and)e(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)g(are)h
+(optional.)43 b(The)30 b(equals)h(sign)f(c)m(haracter)j(is)d(also)i
+(optional,)g(but)e(it)h(is)f(recommended)0 4264 y(that)42
+b(it)f(b)s(e)g(included)f(for)h(clarit)m(y)-8 b(.)75
+b(An)m(y)41 b(template)i(line)e(that)h(b)s(egins)f(with)f(the)i(p)s
+(ound)d('#')i(c)m(haracter)i(is)0 4377 y(ignored)30 b(b)m(y)h(the)f
+(template)i(parser)e(and)g(ma)m(y)h(b)s(e)e(use)h(to)h(insert)g(commen)
+m(ts)g(in)m(to)g(the)g(template)h(\014le)e(itself.)0
+4538 y(The)c(KEYW)m(ORD)g(name)g(\014eld)g(is)g(limited)h(to)g(8)f(c)m
+(haracters)h(in)f(length)h(and)e(only)h(the)g(letters)i(A-Z,)e(digits)h
+(0-9,)0 4650 y(and)h(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)h(an)m(y)f(em)m(b)s
+(edded)g(spaces.)40 b(Lo)m(w)m(ercase)0 4763 y(letters)22
+b(in)f(the)h(template)g(k)m(eyw)m(ord)g(name)f(will)g(b)s(e)g(con)m(v)m
+(erted)i(to)f(upp)s(ercase.)36 b(Leading)22 b(spaces)f(in)g(the)h
+(template)0 4876 y(line)k(preceding)g(the)f(k)m(eyw)m(ord)h(name)g(are)
+g(generally)h(ignored,)g(except)f(if)g(the)g(\014rst)f(8)h(c)m
+(haracters)h(of)f(a)g(template)0 4989 y(line)f(are)h(all)g(blank,)g
+(then)f(the)g(en)m(tire)h(line)g(is)f(treated)h(as)f(a)h(FITS)e(commen)
+m(t)i(k)m(eyw)m(ord)g(\(with)f(a)h(blank)e(k)m(eyw)m(ord)0
+5102 y(name\))31 b(and)f(is)g(copied)h(v)m(erbatim)g(in)m(to)g(the)g
+(FITS)e(header.)0 5262 y(The)37 b(KEYV)-10 b(ALUE)37
+b(\014eld)g(ma)m(y)h(ha)m(v)m(e)g(an)m(y)g(allo)m(w)m(ed)h(FITS)e(data)
+h(t)m(yp)s(e:)54 b(c)m(haracter)39 b(string,)h(logical,)h(in)m(teger,)0
+5375 y(real,)34 b(complex)f(in)m(teger,)i(or)d(complex)i(real.)47
+b(The)32 b(c)m(haracter)j(string)d(v)-5 b(alues)33 b(need)f(not)h(b)s
+(e)f(enclosed)h(in)f(single)0 5488 y(quote)d(c)m(haracters)h(unless)e
+(they)g(are)h(necessary)g(to)g(distinguish)e(the)i(string)f(from)g(a)h
+(di\013eren)m(t)g(data)g(t)m(yp)s(e)f(\(e.g.)0 5601 y(2.0)h(is)e(a)h
+(real)h(but)e('2.0')i(is)f(a)g(string\).)40 b(The)27
+b(k)m(eyw)m(ord)h(has)f(an)h(unde\014ned)d(\(n)m(ull\))j(v)-5
+b(alue)29 b(if)e(the)h(template)h(record)0 5714 y(only)h(con)m(tains)i
+(blanks)e(follo)m(wing)i(the)e("=")h(or)g(b)s(et)m(w)m(een)g(the)f("=")
+h(and)f(the)g("/")i(commen)m(t)g(\014eld)d(delimiter.)1882
+5942 y(147)p eop end
+%%Page: 148 156
+TeXDict begin 148 155 bop 0 299 a Fj(148)2250 b Fh(CHAPTER)29
+b(11.)72 b(TEMPLA)-8 b(TE)30 b(FILES)0 555 y Fj(String)c(k)m(eyw)m(ord)
+h(v)-5 b(alues)27 b(longer)g(than)f(68)h(c)m(haracters)h(\(the)f(maxim)
+m(um)f(length)h(that)g(will)g(\014t)f(in)g(a)h(single)g(FITS)0
+668 y(k)m(eyw)m(ord)41 b(record\))g(are)g(p)s(ermitted)f(using)g(the)h
+(CFITSIO)e(long)i(string)g(con)m(v)m(en)m(tion.)74 b(They)40
+b(can)h(either)g(b)s(e)0 781 y(sp)s(eci\014ed)28 b(as)i(a)f(single)h
+(long)f(line)h(in)e(the)i(template,)h(or)e(b)m(y)f(using)h(m)m(ultiple)
+h(lines)f(where)f(the)i(con)m(tin)m(uing)g(lines)0 894
+y(con)m(tain)i(the)e('CONTINUE')g(k)m(eyw)m(ord,)h(as)g(in)f(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)h(lines)e(with)h(CONTINUE)e
+(k)m(eyw)m(ord)i(is)g(v)m(ery)g(strict:)41 b(3)30 b(spaces)g(m)m(ust)f
+(follo)m(w)i(CON-)0 1610 y(TINUE)f(and)g(the)g(rest)h(of)f(the)h(line)g
+(is)f(copied)h(v)m(erbatim)g(to)g(the)g(FITS)e(\014le.)0
+1771 y(The)i(start)h(of)g(the)f(optional)i(COMMENT)e(\014eld)g(m)m(ust)
+h(b)s(e)e(preceded)i(b)m(y)f("/",)i(whic)m(h)e(is)h(used)f(to)h
+(separate)g(it)0 1883 y(from)e(the)g(k)m(eyw)m(ord)h(v)-5
+b(alue)30 b(\014eld.)41 b(Exceptions)30 b(are)h(if)f(the)h(KEYW)m(ORD)g
+(name)f(\014eld)g(con)m(tains)h(COMMENT,)0 1996 y(HISTOR)-8
+b(Y,)30 b(CONTINUE,)g(or)g(if)g(the)h(\014rst)f(8)g(c)m(haracters)i(of)
+f(the)f(template)i(line)f(are)g(blanks.)0 2157 y(More)c(than)f(one)h
+(Header-Data)i(Unit)e(\(HDU\))g(ma)m(y)g(b)s(e)f(de\014ned)f(in)h(the)h
+(template)h(\014le.)39 b(The)26 b(start)h(of)g(an)f(HDU)0
+2269 y(de\014nition)k(is)g(denoted)h(with)f(a)h(SIMPLE)e(or)i(XTENSION)
+e(template)j(line:)0 2430 y(1\))i(SIMPLE)f(b)s(egins)g(a)h(Primary)g
+(HDU)g(de\014nition.)50 b(SIMPLE)33 b(ma)m(y)h(only)g(app)s(ear)f(as)h
+(the)g(\014rst)f(k)m(eyw)m(ord)h(in)0 2543 y(the)e(template)i(\014le.)
+45 b(If)32 b(the)g(template)i(\014le)e(b)s(egins)f(with)h(XTENSION)f
+(instead)h(of)g(SIMPLE,)g(then)f(a)i(default)0 2655 y(empt)m(y)d
+(Primary)e(HDU)i(is)g(created,)h(and)d(the)i(template)h(is)e(then)g
+(assumed)f(to)i(de\014ne)f(the)h(k)m(eyw)m(ords)f(starting)0
+2768 y(with)h(the)h(\014rst)e(extension)i(follo)m(wing)h(the)f(Primary)
+f(HDU.)0 2928 y(2\))35 b(XTENSION)e(marks)g(the)i(b)s(eginning)e(of)h
+(a)h(new)e(extension)i(HDU)f(de\014nition.)52 b(The)33
+b(previous)h(HDU)h(will)0 3041 y(b)s(e)30 b(closed)h(at)g(this)f(p)s
+(oin)m(t)h(and)e(pro)s(cessing)i(of)f(the)h(next)f(extension)h(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)g(k)m(eyw)m(ord)g(name)f(ends)g(with)g
+(a)g("#")h(c)m(haracter,)i(it)e(is)f(said)g(to)h(b)s(e)f
+('auto-indexed'.)44 b(Eac)m(h)32 b("#")0 3736 y(c)m(haracter)i(will)f
+(b)s(e)f(replaced)i(b)m(y)e(the)h(curren)m(t)g(in)m(teger)h(index)e(v)
+-5 b(alue,)34 b(whic)m(h)f(gets)g(reset)h(=)e(1)h(at)h(the)e(start)i
+(of)0 3849 y(eac)m(h)h(new)f(HDU)g(in)g(the)g(\014le)g(\(or)g(7)h(in)e
+(the)h(sp)s(ecial)h(case)g(of)f(a)g(GR)m(OUP)h(de\014nition\).)51
+b(The)33 b(FIRST)g(indexed)0 3962 y(k)m(eyw)m(ord)c(in)f(eac)m(h)h
+(template)h(HDU)f(de\014nition)f(is)g(used)f(as)i(the)f('incremen)m
+(tor';)j(eac)m(h)e(subsequen)m(t)f(o)s(ccurrence)0 4075
+y(of)k(this)f(SAME)g(k)m(eyw)m(ord)h(will)g(cause)g(the)g(index)f(v)-5
+b(alue)32 b(to)g(b)s(e)f(incremen)m(ted.)44 b(This)31
+b(b)s(eha)m(vior)g(can)h(b)s(e)f(rather)0 4188 y(subtle,)d(as)g
+(illustrated)h(in)e(the)h(follo)m(wing)h(examples)f(in)f(whic)m(h)h
+(the)g(TTYPE)e(k)m(eyw)m(ord)i(is)g(the)g(incremen)m(tor)g(in)0
+4300 y(b)s(oth)i(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)26 b(create)i(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)g(the)g(template)h(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
+end
+%%Page: 149 157
+TeXDict begin 149 156 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(149)0
+555 y(this)31 b(results)f(in)h(a)g(FITS)f(\014les)h(with)f(TTYPE1,)h
+(TTYPE2,)g(TF)m(ORM2,)h(and)e(TF)m(ORM2,)i(whic)m(h)f(is)g(probably)0
+668 y(not)g(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)i(to)f(the)g(template)i(lines)e(whic)m(h)g
+(de\014ne)f(individual)h(k)m(eyw)m(ords,)g(the)g(template)i(parser)d
+(recognizes)0 1363 y(3)h(sp)s(ecial)h(directiv)m(es)g(whic)m(h)f(are)g
+(eac)m(h)h(preceded)f(b)m(y)f(the)h(bac)m(kslash)h(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')h(directiv)m(e)i(m)m(ust)
+d(b)s(e)h(follo)m(w)m(ed)h(b)m(y)f(a)g(\014lename.)63
+b(It)38 b(forces)g(the)g(parser)f(to)i(temp)s(orarily)f(stop)0
+1749 y(reading)d(the)g(curren)m(t)g(template)h(\014le)f(and)f(b)s(egin)
+h(reading)g(the)g(include)f(\014le.)55 b(Once)35 b(the)g(parser)f(reac)
+m(hes)i(the)0 1862 y(end)f(of)h(the)g(include)f(\014le)h(it)g(con)m
+(tin)m(ues)g(parsing)g(the)f(curren)m(t)h(template)h(\014le.)56
+b(Include)35 b(\014les)h(can)g(b)s(e)f(nested,)0 1975
+y(and)30 b(HDU)h(de\014nitions)f(can)g(span)g(m)m(ultiple)h(template)h
+(\014les.)0 2135 y(The)f(start)h(of)g(a)g(GR)m(OUP)h(de\014nition)e(is)
+h(denoted)g(with)f(the)h('group')g(directiv)m(e,)h(and)f(the)f(end)h
+(of)f(a)i(GR)m(OUP)0 2248 y(de\014nition)k(is)h(denoted)f(with)g(the)h
+('end')f(directiv)m(e.)63 b(Eac)m(h)39 b(GR)m(OUP)e(con)m(tains)i(0)f
+(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)i(of)f(t)m(yp)s
+(e)g(GR)m(OUP)g(can)g(con)m(tain)h(their)f(o)m(wn)g(mem)m(b)s(er)f(blo)
+s(c)m(ks.)0 2474 y(The)32 b(GR)m(OUP)g(de\014nition)g(itself)h(o)s
+(ccupies)g(one)f(FITS)g(\014le)g(HDU)h(of)f(sp)s(ecial)h(t)m(yp)s(e)f
+(\(GR)m(OUP)h(HDU\),)h(so)e(if)h(a)0 2587 y(template)f(sp)s(eci\014es)e
+(1)h(group)e(with)h(1)h(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)g(with)g(3)h(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)32 b(sp)s(eaking,)e(the)f(GR)m
+(OUP)i(HDU)f(is)g(a)g(BINT)-8 b(ABLE)30 b(with)g(6)g(columns.)40
+b(Applications)31 b(can)f(de\014ne)0 4382 y(additional)23
+b(columns)f(in)f(a)i(GR)m(OUP)f(HDU)h(using)f(TF)m(ORMn)f(and)h(TTYPEn)
+f(\(where)g(n)h(is)g(7,)i(8,)h(....\))39 b(k)m(eyw)m(ords)0
+4494 y(or)30 b(their)h(auto-indexing)g(equiv)-5 b(alen)m(ts.)0
+4655 y(F)d(or)26 b(a)f(more)g(complicated)h(example)f(of)g(a)h
+(template)g(\014le)f(using)f(the)h(group)f(directiv)m(es,)k(lo)s(ok)d
+(at)g(the)g(sample.tpl)0 4767 y(\014le)30 b(that)h(is)g(included)e(in)i
+(the)f(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)i(syn)m(tax)f(can)f(formally)h(b)s(e)f(de\014ned)f
+(as)i(follo)m(ws:)191 5601 y Fe(TEMPLATE)45 b(=)j(BLOCK)e([)i(BLOCK)e
+(...)h(])p eop end
+%%Page: 150 158
+TeXDict begin 150 157 bop 0 299 a Fj(150)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,)i(the)e(template)i
+(de\014nes)c(1)j(or)e(more)h(template)h(blo)s(c)m(ks.)49
+b(Blo)s(c)m(ks)34 b(can)f(b)s(e)f(either)h(HDU)0 2050
+y(\(Header)27 b(Data)h(Unit\))g(or)e(a)h(GR)m(OUP)-8
+b(.)28 b(F)-8 b(or)27 b(eac)m(h)g(blo)s(c)m(k)g(the)g(parser)f(creates)
+i(1)f(\(or)g(more)f(for)h(GR)m(OUPs\))g(FITS)0 2163 y(\014le)j(HDUs.)0
+2495 y Ff(11.5)136 b(Errors)0 2745 y Fj(In)24 b(general)h(the)f(\014ts)
+p 692 2745 28 4 v 33 w(execute)p 1019 2745 V 34 w(template\(\))i
+(function)e(tries)h(to)g(b)s(e)f(as)g(atomic)i(as)f(p)s(ossible,)g(so)f
+(either)h(ev)m(erything)0 2858 y(is)f(done)g(or)g(nothing)f(is)h(done.)
+39 b(If)23 b(an)h(error)f(o)s(ccurs)h(during)f(parsing)g(of)h(the)g
+(template,)j(\014ts)p 3125 2858 V 33 w(execute)p 3452
+2858 V 34 w(template\(\))0 2971 y(will)k(\(try)g(to\))h(delete)g(the)f
+(top)g(lev)m(el)h(BLOCK)e(\(with)h(all)g(its)h(c)m(hildren)e(if)h(an)m
+(y\))g(in)g(whic)m(h)f(the)h(error)f(o)s(ccurred,)0 3084
+y(then)g(it)h(will)g(stop)f(reading)h(the)f(template)i(\014le)e(and)g
+(it)h(will)g(return)e(with)h(an)g(error.)0 3417 y Ff(11.6)136
+b(Examples)0 3667 y Fj(1.)54 b(This)34 b(template)i(\014le)f(will)g
+(create)h(a)f(200)h(x)e(300)i(pixel)f(image,)j(with)c(4-b)m(yte)i(in)m
+(teger)g(pixel)f(v)-5 b(alues,)36 b(in)f(the)0 3780 y(primary)29
+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)i(v)-5 b(alues)36 b(of)f(BITPIX)g(are)
+h(8,)h(16,)h(32,)g(-32,)g(or)d(-64,)j(represen)m(ting,)f(resp)s(ectiv)m
+(ely)-8 b(,)39 b(8-bit)d(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)f(64)h
+(bit)g(\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,)26 b(the)c(template)i
+(\014rst)e(needs)g(to)i(include)e(XTENSION)g(=)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)h(is)g(an)f(ASCI)s(I)g(or)g(binary)g(table,)i(and)f(NAXIS2)g(to)g
+(de\014ne)f(the)h(n)m(um)m(b)s(er)f(of)h(ro)m(ws)f(in)h(the)0
+5348 y(table.)50 b(Tw)m(o)34 b(template)g(lines)g(are)g(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,)f(as)h(in)f(this)g(example:)
+95 5714 y Fe(xtension)46 b(=)h(bintable)p eop end
+%%Page: 151 159
+TeXDict begin 151 158 bop 0 299 a Fh(11.6.)73 b(EXAMPLES)2993
+b Fj(151)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)e(de\014nes)f(a)i(n)m(ull)f
+(primary)f(arra)m(y)h(follo)m(w)m(ed)i(b)m(y)e(a)g(40-ro)m(w)h(binary)e
+(table)i(extension)g(with)f(3)0 1718 y(columns)h(called)h('Name',)h
+('Np)s(oin)m(ts',)f(and)f('Rate',)i(with)e(data)h(formats)f(of)g('10A')
+i(\(ASCI)s(I)d(c)m(haracter)i(string\),)0 1831 y('1J')k(\(in)m(teger\))
+i(and)d('1E')i(\(\015oating)f(p)s(oin)m(t\),)h(resp)s(ectiv)m(ely)-8
+b(.)50 b(Note)34 b(that)f(the)g(other)g(required)f(FITS)g(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)j(de\014ned)d(in)i(the)f(template)i(b)s(ecause)f(their)
+g(v)-5 b(alues)38 b(can)g(b)s(e)f(inferred)f(from)i(the)f(other)h(k)m
+(eyw)m(ords)g(in)0 2170 y(the)d(template.)55 b(This)34
+b(example)i(also)g(illustrates)f(that)h(the)f(templates)h(are)f
+(generally)h(case-insensitiv)m(e)h(\(the)0 2283 y(k)m(eyw)m(ord)29
+b(names)g(and)g(TF)m(ORMn)f(v)-5 b(alues)30 b(are)f(con)m(v)m(erted)i
+(to)e(upp)s(er-case)g(in)f(the)h(FITS)g(\014le\))g(and)f(that)i(string)
+0 2396 y(k)m(eyw)m(ord)h(v)-5 b(alues)31 b(generally)g(do)f(not)h(need)
+f(to)h(b)s(e)f(enclosed)h(in)f(quotes.)p eop end
+%%Page: 152 160
+TeXDict begin 152 159 bop 0 299 a Fj(152)2250 b Fh(CHAPTER)29
+b(11.)72 b(TEMPLA)-8 b(TE)30 b(FILES)p eop end
+%%Page: 153 161
+TeXDict begin 153 160 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)j(lo)s(cal)f(FITS)f
+(con)m(v)m(en)m(tions)j(whic)m(h)d(are)h(not)g(de\014ned)e(in)h(the)h
+(o\016cial)h(NOST)e(FITS)0 2293 y(standard)k(and)g(whic)m(h)h(are)g
+(not)g(necessarily)g(recognized)h(or)f(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)f(b)s(e)g(cautious)i(ab)s(out)e(using)h(these)g(features,)i
+(esp)s(ecially)f(if)f(the)g(FITS)f(\014les)h(that)h(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)f(do)h(not)f(use)h
+(the)f(CFITSIO)0 2631 y(in)m(terface.)0 2990 y Ff(12.1)136
+b(64-Bit)45 b(Long)g(In)l(tegers)0 3246 y Fj(CFITSIO)37
+b(supp)s(orts)g(reading)i(and)f(writing)h(FITS)f(images)i(or)f(table)h
+(columns)e(con)m(taining)i(64-bit)h(in)m(teger)0 3359
+y(data)26 b(v)-5 b(alues.)40 b(Supp)s(ort)23 b(for)i(64-bit)i(in)m
+(tegers)g(w)m(as)f(added)e(to)j(the)e(o\016cial)i(FITS)e(Standard)f(in)
+i(Decem)m(b)s(er)g(2005.)0 3472 y(FITS)g(64-bit)i(images)g(ha)m(v)m(e)g
+(BITPIX)e(=)h(64,)h(and)e(the)h(64-bit)h(binary)e(table)i(columns)f(ha)
+m(v)m(e)h(TF)m(ORMn)e(=)h('K'.)0 3584 y(CFITSIO)35 b(also)i(supp)s
+(orts)e(the)i('Q')f(v)-5 b(ariable-length)38 b(arra)m(y)f(table)h
+(column)e(format)h(whic)m(h)f(is)g(analogous)i(to)0 3697
+y(the)31 b('P')f(column)g(format)h(except)g(that)g(the)g(arra)m(y)g
+(descriptor)f(is)h(stored)f(as)h(a)f(pair)h(of)f(64-bit)i(in)m(tegers.)
+0 3858 y(F)-8 b(or)33 b(the)f(con)m(v)m(enience)i(of)f(C)e
+(programmers,)h(the)h(\014tsio.h)f(include)g(\014le)g(de\014nes)f
+(\(with)h(a)h(t)m(yp)s(edef)f(statemen)m(t\))0 3970 y(the)39
+b('LONGLONG')g(datat)m(yp)s(e)h(to)f(b)s(e)f(equiv)-5
+b(alen)m(t)40 b(to)f(an)g(appropriate)g(64-bit)h(in)m(teger)g(datat)m
+(yp)s(e)f(on)g(eac)m(h)0 4083 y(platform.)g(Since)27
+b(there)f(is)g(curren)m(tly)g(no)g(univ)m(ersal)h(standard)e(for)h(the)
+g(name)g(of)h(the)f(64-bit)h(in)m(teger)h(datat)m(yp)s(e)0
+4196 y(\(it)33 b(migh)m(t)f(b)s(e)f(de\014ned)g(as)h('long)g(long',)i
+('long',)f(or)f(')p 1832 4196 28 4 v 1865 4196 V 66 w(in)m(t64')h(dep)s
+(ending)d(on)i(the)g(platform\))g(C)g(programmers)0 4309
+y(ma)m(y)24 b(prefer)f(to)i(use)e(the)h('LONGLONG')h(datat)m(yp)s(e)f
+(when)f(declaring)i(or)e(allo)s(cating)j(64-bit)f(in)m(teger)h(quan)m
+(tities)0 4422 y(when)33 b(writing)h(co)s(de)g(whic)m(h)f(needs)h(to)h
+(run)d(on)i(m)m(ultiple)g(platforms.)52 b(Note)35 b(that)f(CFITSIO)f
+(will)h(implicitly)0 4535 y(con)m(v)m(ert)h(the)e(datat)m(yp)s(e)h
+(when)f(reading)g(or)g(writing)h(FITS)e(64-bit)j(in)m(teger)f(images)h
+(and)d(columns)h(with)g(data)0 4648 y(arra)m(ys)40 b(of)h(a)f
+(di\013eren)m(t)h(in)m(teger)g(or)f(\015oating)h(p)s(oin)m(t)f(datat)m
+(yp)s(e,)k(but)c(there)g(is)g(an)g(increased)g(risk)g(of)g(loss)h(of)0
+4761 y(n)m(umerical)31 b(precision)f(or)h(n)m(umerical)g(o)m(v)m
+(er\015o)m(w)h(in)e(this)g(case.)0 5120 y Ff(12.2)136
+b(Long)44 b(String)i(Keyw)l(ord)f(V)-11 b(alues.)0 5375
+y Fj(The)43 b(length)i(of)f(a)g(standard)g(FITS)f(string)h(k)m(eyw)m
+(ord)g(is)g(limited)h(to)g(68)f(c)m(haracters)i(b)s(ecause)e(it)g(m)m
+(ust)g(\014t)0 5488 y(en)m(tirely)35 b(within)e(a)h(single)h(FITS)e
+(header)g(k)m(eyw)m(ord)i(record.)50 b(In)33 b(some)i(instances)f(it)g
+(is)g(necessary)g(to)h(enco)s(de)0 5601 y(strings)29
+b(longer)i(than)e(this)g(limit,)i(so)f(CFITSIO)e(supp)s(orts)g(a)h(lo)s
+(cal)i(con)m(v)m(en)m(tion)h(in)d(whic)m(h)h(the)f(string)h(v)-5
+b(alue)30 b(is)0 5714 y(con)m(tin)m(ued)36 b(o)m(v)m(er)g(m)m(ultiple)f
+(k)m(eyw)m(ords.)55 b(This)34 b(con)m(tin)m(uation)i(con)m(v)m(en)m
+(tion)h(uses)e(an)f(amp)s(ersand)g(c)m(haracter)i(at)1882
+5942 y(153)p eop end
+%%Page: 154 162
+TeXDict begin 154 161 bop 0 299 a Fj(154)1741 b Fh(CHAPTER)30
+b(12.)112 b(LOCAL)29 b(FITS)h(CONVENTIONS)0 555 y Fj(the)c(end)f(of)h
+(eac)m(h)g(substring)f(to)h(indicate)h(that)f(it)h(is)e(con)m(tin)m
+(ued)i(on)e(the)h(next)g(k)m(eyw)m(ord,)h(and)e(the)h(con)m(tin)m
+(uation)0 668 y(k)m(eyw)m(ords)40 b(all)h(ha)m(v)m(e)g(the)f(name)g
+(CONTINUE)f(without)h(an)g(equal)g(sign)g(in)g(column)g(9.)69
+b(The)40 b(string)f(v)-5 b(alue)0 781 y(ma)m(y)33 b(b)s(e)f(con)m(tin)m
+(ued)h(in)g(this)f(w)m(a)m(y)h(o)m(v)m(er)h(as)f(man)m(y)g(additional)g
+(CONTINUE)f(k)m(eyw)m(ords)h(as)f(is)h(required.)46 b(The)0
+894 y(follo)m(wing)37 b(lines)e(illustrate)h(this)f(con)m(tin)m(uation)
+i(con)m(v)m(en)m(tion)h(whic)m(h)c(is)i(used)e(in)h(the)g(v)-5
+b(alue)36 b(of)f(the)g(STRKEY)0 1007 y(k)m(eyw)m(ord:)0
+1297 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 1410 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 1523 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 1636 y(CONTINUE)e('FITS)47 b(header.')e(/)j(This)e(is)h(another)f
+(optional)g(comment.)0 1926 y Fj(It)29 b(is)g(recommended)f(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)i(b)
+s(e)d(included)g(in)g(an)m(y)h(HDU)0 2039 y(that)i(uses)f(this)g
+(longstring)h(con)m(v)m(en)m(tion)i(as)e(a)f(w)m(arning)h(to)g(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 2152 y(routine)d(called)g(\014ts)p 712 2152 28
+4 v 33 w(write)p 947 2152 V 33 w(k)m(ey)p 1113 2152 V
+33 w(longw)m(arn)g(has)f(b)s(een)g(pro)m(vided)g(in)h(CFITSIO)d(to)k
+(write)e(this)h(k)m(eyw)m(ord)g(if)f(it)0 2265 y(do)s(es)30
+b(not)h(already)g(exist.)0 2425 y(This)f(long)h(string)f(con)m(v)m(en)m
+(tion)i(is)f(supp)s(orted)d(b)m(y)j(the)f(follo)m(wing)i(CFITSIO)d
+(routines:)191 2716 y Fe(fits_write_key_longstr)89 b(-)48
+b(write)e(a)i(long)e(string)g(keyword)g(value)191 2829
+y(fits_insert_key_longstr)41 b(-)48 b(insert)e(a)h(long)g(string)f
+(keyword)g(value)191 2942 y(fits_modify_key_longstr)41
+b(-)48 b(modify)e(a)h(long)g(string)f(keyword)g(value)191
+3054 y(fits_update_key_longstr)41 b(-)48 b(modify)e(a)h(long)g(string)f
+(keyword)g(value)191 3167 y(fits_read_key_longstr)137
+b(-)48 b(read)94 b(a)48 b(long)e(string)g(keyword)g(value)191
+3280 y(fits_delete_key)425 b(-)48 b(delete)e(a)h(keyword)0
+3571 y Fj(The)36 b(\014ts)p 320 3571 V 32 w(read)p 524
+3571 V 33 w(k)m(ey)p 690 3571 V 34 w(longstr)g(routine)h(is)f(unique)f
+(among)i(all)h(the)e(CFITSIO)f(routines)h(in)g(that)h(it)g(in)m
+(ternally)0 3684 y(allo)s(cates)f(memory)d(for)h(the)f(long)h(string)g
+(v)-5 b(alue;)36 b(all)e(the)g(other)g(CFITSIO)e(routines)h(that)h
+(deal)g(with)g(arra)m(ys)0 3797 y(require)39 b(that)h(the)g(calling)h
+(program)e(pre-allo)s(cate)j(adequate)e(space)g(to)g(hold)f(the)h(arra)
+m(y)g(of)f(data.)69 b(Conse-)0 3909 y(quen)m(tly)-8 b(,)31
+b(programs)f(whic)m(h)g(use)g(the)g(\014ts)p 1443 3909
+V 32 w(read)p 1647 3909 V 33 w(k)m(ey)p 1813 3909 V 34
+w(longstr)g(routine)g(m)m(ust)g(b)s(e)g(careful)g(to)h(free)g(the)f
+(allo)s(cated)0 4022 y(memory)g(for)g(the)h(string)f(when)g(it)h(is)f
+(no)g(longer)h(needed.)0 4183 y(The)f(follo)m(wing)i(2)e(routines)h
+(also)g(ha)m(v)m(e)h(limited)f(supp)s(ort)d(for)i(this)h(long)g(string)
+f(con)m(v)m(en)m(tion,)286 4473 y Fe(fits_modify_key_str)43
+b(-)k(modify)f(an)i(existing)d(string)h(keyword)g(value)286
+4586 y(fits_update_key_str)d(-)k(update)f(a)i(string)e(keyword)g(value)
+0 4876 y Fj(in)24 b(that)h(they)f(will)h(correctly)g(o)m(v)m(erwrite)h
+(an)e(existing)h(long)g(string)f(v)-5 b(alue,)27 b(but)c(the)h(new)g
+(string)g(v)-5 b(alue)25 b(is)f(limited)0 4989 y(to)31
+b(a)g(maxim)m(um)f(of)h(68)g(c)m(haracters)h(in)e(length.)0
+5149 y(The)f(more)h(commonly)h(used)e(CFITSIO)f(routines)i(to)g(write)g
+(string)g(v)-5 b(alued)30 b(k)m(eyw)m(ords)g(\(\014ts)p
+3254 5149 V 33 w(up)s(date)p 3563 5149 V 32 w(k)m(ey)h(and)0
+5262 y(\014ts)p 127 5262 V 32 w(write)p 361 5262 V 33
+w(k)m(ey\))j(do)e(not)h(supp)s(ort)d(this)i(long)h(string)g(con)m(v)m
+(en)m(tion)h(and)e(only)g(supp)s(ort)f(strings)h(up)f(to)i(68)g(c)m
+(har-)0 5375 y(acters)g(in)f(length.)48 b(This)31 b(has)h(b)s(een)g
+(done)g(delib)s(erately)h(to)g(prev)m(en)m(t)g(programs)f(from)g(inadv)
+m(erten)m(tly)i(writing)0 5488 y(k)m(eyw)m(ords)25 b(using)f(this)h
+(non-standard)e(con)m(v)m(en)m(tion)k(without)e(the)g(explicit)h(in)m
+(ten)m(t)g(of)f(the)f(programmer)h(or)f(user.)0 5601
+y(The)36 b(\014ts)p 320 5601 V 32 w(write)p 554 5601
+V 33 w(k)m(ey)p 720 5601 V 34 w(longstr)h(routine)f(m)m(ust)h(b)s(e)f
+(called)i(instead)e(to)i(write)e(long)h(strings.)59 b(This)36
+b(routine)h(can)0 5714 y(also)31 b(b)s(e)f(used)g(to)h(write)f
+(ordinary)g(string)g(v)-5 b(alues)31 b(less)g(than)f(68)h(c)m
+(haracters)h(in)e(length.)p eop end
+%%Page: 155 163
+TeXDict begin 155 162 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(155)0 555 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 820 y Fj(CFITSIO)25 b(supp)s(orts)g(2)i(w)m(a)m(ys)g(to)g(sp)
+s(ecify)f(that)i(a)f(c)m(haracter)h(column)e(in)g(a)h(binary)f(table)i
+(con)m(tains)f(an)g(arra)m(y)g(of)0 933 y(\014xed-length)32
+b(strings.)46 b(The)32 b(\014rst)f(w)m(a)m(y)-8 b(,)34
+b(whic)m(h)e(is)g(o\016cially)i(supp)s(orted)c(b)m(y)i(the)h(FITS)e
+(Standard)g(do)s(cumen)m(t,)0 1046 y(uses)38 b(the)g(TDIMn)g(k)m(eyw)m
+(ord.)65 b(F)-8 b(or)39 b(example,)i(if)d(TF)m(ORMn)g(=)g('60A')h(and)f
+(TDIMn)g(=)g('\(12,5\)')i(then)e(that)0 1159 y(column)30
+b(will)h(b)s(e)f(in)m(terpreted)g(as)h(con)m(taining)h(an)e(arra)m(y)h
+(of)g(5)f(strings,)h(eac)m(h)g(12)g(c)m(haracters)h(long.)0
+1319 y(CFITSIO)j(also)j(supp)s(orts)c(a)j(lo)s(cal)h(con)m(v)m(en)m
+(tion)h(for)d(the)h(format)g(of)g(the)f(TF)m(ORMn)h(k)m(eyw)m(ord)g(v)
+-5 b(alue)37 b(of)g(the)0 1432 y(form)42 b('rAw')g(where)g('r')g(is)h
+(an)f(in)m(teger)i(sp)s(ecifying)e(the)g(total)j(width)c(in)h(c)m
+(haracters)i(of)f(the)f(column,)k(and)0 1545 y('w')36
+b(is)g(an)g(in)m(teger)h(sp)s(ecifying)f(the)g(\(\014xed\))g(length)h
+(of)f(an)g(individual)f(unit)h(string)f(within)h(the)g(v)m(ector.)59
+b(F)-8 b(or)0 1658 y(example,)29 b(TF)m(ORM1)f(=)f('120A10')j(w)m(ould)
+d(indicate)h(that)g(the)f(binary)g(table)h(column)f(is)g(120)i(c)m
+(haracters)f(wide)0 1771 y(and)42 b(consists)h(of)f(12)h(10-c)m
+(haracter)i(length)e(strings.)77 b(This)41 b(con)m(v)m(en)m(tion)k(is)d
+(recognized)i(b)m(y)e(the)g(CFITSIO)0 1884 y(routines)26
+b(that)h(read)e(or)h(write)h(strings)e(in)h(binary)f(tables.)40
+b(The)26 b(Binary)g(T)-8 b(able)27 b(de\014nition)e(do)s(cumen)m(t)h
+(sp)s(eci\014es)0 1996 y(that)i(other)f(optional)h(c)m(haracters)h(ma)m
+(y)e(follo)m(w)i(the)e(data)h(t)m(yp)s(e)f(co)s(de)g(in)g(the)g(TF)m
+(ORM)h(k)m(eyw)m(ord,)g(so)g(this)f(lo)s(cal)0 2109 y(con)m(v)m(en)m
+(tion)f(is)d(in)h(compliance)h(with)e(the)h(FITS)e(standard)h(although)
+h(other)g(FITS)f(readers)g(ma)m(y)h(not)g(recognize)0
+2222 y(this)30 b(con)m(v)m(en)m(tion.)0 2382 y(The)25
+b(Binary)h(T)-8 b(able)27 b(de\014nition)e(do)s(cumen)m(t)h(that)h(w)m
+(as)f(appro)m(v)m(ed)g(b)m(y)g(the)g(IA)m(U)g(in)g(1994)i(con)m(tains)f
+(an)e(app)s(endix)0 2495 y(describing)d(an)h(alternate)h(con)m(v)m(en)m
+(tion)h(for)e(sp)s(ecifying)f(arra)m(ys)h(of)g(\014xed)f(or)h(v)-5
+b(ariable)24 b(length)f(strings)f(in)h(a)g(binary)0 2608
+y(table)35 b(c)m(haracter)g(column)f(\(with)g(the)h(form)e
+('rA:SSTRw/nnn\)'.)50 b(This)33 b(app)s(endix)f(w)m(as)j(not)f
+(o\016cially)i(v)m(oted)0 2721 y(on)30 b(b)m(y)h(the)f(IA)m(U)h(and)f
+(hence)g(is)h(still)g(pro)m(visional.)42 b(CFITSIO)29
+b(do)s(es)h(not)g(curren)m(tly)h(supp)s(ort)d(this)j(prop)s(osal.)0
+3129 y Ff(12.4)136 b(Keyw)l(ord)45 b(Units)h(Strings)0
+3394 y Fj(One)37 b(limitation)j(of)d(the)h(curren)m(t)g(FITS)e
+(Standard)h(is)h(that)g(it)g(do)s(es)f(not)h(de\014ne)f(a)h(sp)s
+(eci\014c)f(con)m(v)m(en)m(tion)j(for)0 3507 y(recording)30
+b(the)g(ph)m(ysical)h(units)f(of)g(a)g(k)m(eyw)m(ord)h(v)-5
+b(alue.)41 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)f(the)0 3620 y(ph)m(ysical)36 b(units)f(of)g(the)h(v)-5
+b(alues)36 b(in)f(a)g(table)i(column,)f(but)f(there)g(is)h(no)f
+(analogous)i(con)m(v)m(en)m(tion)g(for)e(k)m(eyw)m(ord)0
+3732 y(v)-5 b(alues.)42 b(The)30 b(commen)m(t)h(\014eld)g(of)f(the)h(k)
+m(eyw)m(ord)g(is)g(often)g(used)f(for)g(this)g(purp)s(ose,)g(but)f(the)
+i(units)f(are)h(usually)0 3845 y(not)g(sp)s(eci\014ed)e(in)h(a)h(w)m
+(ell)g(de\014ned)f(format)g(that)h(FITS)f(readers)g(can)h(easily)g
+(recognize)h(and)e(extract.)0 4006 y(T)-8 b(o)27 b(solv)m(e)i(this)d
+(problem,)i(CFITSIO)d(uses)i(a)g(lo)s(cal)h(con)m(v)m(en)m(tion)h(in)e
+(whic)m(h)f(the)i(k)m(eyw)m(ord)f(units)f(are)i(enclosed)f(in)0
+4118 y(square)20 b(brac)m(k)m(ets)j(as)e(the)f(\014rst)g(tok)m(en)i(in)
+f(the)f(k)m(eyw)m(ord)i(commen)m(t)f(\014eld;)j(more)d(sp)s
+(eci\014cally)-8 b(,)24 b(the)d(op)s(ening)f(square)0
+4231 y(brac)m(k)m(et)28 b(immediately)g(follo)m(ws)f(the)g(slash)f('/')
+h(commen)m(t)h(\014eld)e(delimiter)h(and)f(a)g(single)h(space)g(c)m
+(haracter.)41 b(The)0 4344 y(follo)m(wing)32 b(examples)f(illustrate)g
+(k)m(eyw)m(ords)g(that)g(use)f(this)g(con)m(v)m(en)m(tion:)0
+4667 y Fe(EXPOSURE=)713 b(1800.0)47 b(/)g([s])g(elapsed)f(exposure)f
+(time)0 4780 y(V_HELIO)h(=)763 b(16.23)47 b(/)g([km)g(s**\(-1\)])e
+(heliocentric)g(velocity)0 4893 y(LAMBDA)94 b(=)763 b(5400.)47
+b(/)g([angstrom])e(central)h(wavelength)0 5005 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,)h(the)g(units)e(named)h(in)g(the)h
+(IA)m(U\(1988\))i(St)m(yle)e(Guide)f(are)h(recommended,)f(with)g(the)h
+(main)f(excep-)0 5441 y(tion)j(that)g(the)f(preferred)g(unit)f(for)i
+(angle)g(is)f('deg')i(for)e(degrees.)0 5601 y(The)38
+b(\014ts)p 322 5601 28 4 v 33 w(read)p 527 5601 V 33
+w(k)m(ey)p 693 5601 V 33 w(unit)h(and)f(\014ts)p 1234
+5601 V 32 w(write)p 1468 5601 V 33 w(k)m(ey)p 1634 5601
+V 34 w(unit)g(routines)h(in)g(CFITSIO)e(read)i(and)f(write,)k(resp)s
+(ectiv)m(ely)-8 b(,)0 5714 y(the)31 b(k)m(eyw)m(ord)f(unit)g(strings)h
+(in)f(an)g(existing)h(k)m(eyw)m(ord.)p eop end
+%%Page: 156 164
+TeXDict begin 156 163 bop 0 299 a Fj(156)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)i(whic)m(h)e(allo)m(ws)h(k)m(eyw)m(ord)f
+(names)g(that)h(are)0 918 y(longer)34 b(then)e(8)i(c)m(haracters)g(and)
+f(ma)m(y)h(con)m(tain)g(the)f(full)g(range)g(of)h(prin)m(table)f(ASCI)s
+(I)e(text)j(c)m(haracters.)51 b(This)0 1031 y(con)m(v)m(en)m(tion)39
+b(w)m(as)f(dev)m(elop)s(ed)f(at)h(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(,)55 b(this)47
+b(con)m(v)m(en)m(tion)j(uses)d(the)h(FITS)f(k)m(eyw)m(ord)h('HIERAR)m
+(CH')h(to)f(indicate)h(that)f(this)f(con)m(v)m(en-)0
+1759 y(tion)e(is)f(b)s(eing)g(used,)j(then)d(the)g(actual)i(k)m(eyw)m
+(ord)e(name)h(\()p Fe('ESO)i(INS)f(FOCU)h(POS')c Fj(in)h(this)g
+(example\))h(b)s(e-)0 1872 y(gins)40 b(in)f(column)g(10)i(and)e(can)h
+(con)m(tain)g(an)m(y)g(prin)m(table)g(ASCI)s(I)e(text)j(c)m(haracters,)
+i(including)d(spaces.)68 b(The)0 1985 y(equals)44 b(sign)h(marks)e(the)
+h(end)g(of)g(the)g(k)m(eyw)m(ord)h(name)f(and)f(is)i(follo)m(w)m(ed)g
+(b)m(y)f(the)g(usual)g(v)-5 b(alue)45 b(and)e(com-)0
+2098 y(men)m(t)31 b(\014elds)f(just)g(as)h(in)f(standard)g(FITS)g(k)m
+(eyw)m(ords.)41 b(F)-8 b(urther)30 b(details)i(of)f(this)f(con)m(v)m
+(en)m(tion)j(are)e(describ)s(ed)e(at)0 2211 y(h)m
+(ttp://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.)q(h)m(tml)36
+b(\(searc)m(h)c(for)e(HIERAR)m(CH\).)0 2371 y(This)43
+b(con)m(v)m(en)m(tion)k(allo)m(ws)f(a)e(m)m(uc)m(h)h(broader)e(range)i
+(of)f(k)m(eyw)m(ord)h(names)f(than)h(is)f(allo)m(w)m(ed)i(b)m(y)e(the)h
+(FITS)0 2484 y(Standard.)40 b(Here)30 b(are)h(more)g(examples)g(of)f
+(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)i(transparen)m(tly)g(read)g(and)f(write)g(these)i(k)m(eyw)m
+(ords,)i(so)d(application)h(programs)e(do)g(not)h(in)0
+3325 y(general)33 b(need)f(to)h(kno)m(w)f(an)m(ything)h(ab)s(out)f(the)
+g(sp)s(eci\014c)g(implemen)m(tation)i(details)f(of)g(the)f(HIERAR)m(CH)
+g(con-)0 3438 y(v)m(en)m(tion.)50 b(In)32 b(particular,)j(application)f
+(programs)e(do)h(not)h(need)e(to)i(sp)s(ecify)f(the)g(`HIERAR)m(CH')h
+(part)f(of)g(the)0 3551 y(k)m(eyw)m(ord)g(name)f(when)g(reading)g(or)g
+(writing)h(k)m(eyw)m(ords)f(\(although)h(it)g(ma)m(y)g(b)s(e)f
+(included)f(if)i(desired\).)46 b(When)0 3664 y(writing)35
+b(a)g(k)m(eyw)m(ord,)h(CFITSIO)d(\014rst)h(c)m(hec)m(ks)i(to)f(see)g
+(if)g(the)g(k)m(eyw)m(ord)g(name)f(is)h(legal)h(as)f(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)f(and)f(con)m(taining)i(only)e(letters,)k(digits,)f(or)e(a)g(min)
+m(us)e(sign)i(or)0 3889 y(underscore\).)68 b(If)39 b(so)h(it)g(writes)g
+(it)g(as)f(a)h(standard)f(FITS)g(k)m(eyw)m(ord,)k(otherwise)d(it)g
+(uses)f(the)h(hierarc)m(h)f(con-)0 4002 y(v)m(en)m(tion)34
+b(to)f(write)g(the)f(k)m(eyw)m(ord.)48 b(The)32 b(maxim)m(um)g(k)m(eyw)
+m(ord)h(name)f(length)h(is)g(67)g(c)m(haracters,)i(whic)m(h)d(lea)m(v)m
+(es)0 4115 y(only)c(1)h(space)g(for)f(the)h(v)-5 b(alue)29
+b(\014eld.)39 b(A)29 b(more)f(practical)i(limit)f(is)g(ab)s(out)f(40)h
+(c)m(haracters,)i(whic)m(h)d(lea)m(v)m(es)i(enough)0
+4228 y(ro)s(om)e(for)h(most)f(k)m(eyw)m(ord)h(v)-5 b(alues.)41
+b(CFITSIO)27 b(returns)g(an)h(error)h(if)f(there)h(is)f(not)h(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)32 b(on)f(the)h(80-c)m(haracter)h
+(card,)f(except)g(for)f(string-v)-5 b(alued)32 b(k)m(eyw)m(ords)0
+4454 y(whic)m(h)h(are)g(simply)f(truncated)h(so)g(that)h(the)f(closing)
+h(quote)g(c)m(haracter)g(falls)f(in)g(column)g(80.)49
+b(In)32 b(the)h(curren)m(t)0 4567 y(implemen)m(tation,)e(CFITSIO)c
+(preserv)m(es)i(the)g(case)h(of)f(the)g(letters)h(when)e(writing)h(the)
+g(k)m(eyw)m(ord)g(name,)g(but)f(it)0 4680 y(is)d(case-insensitiv)m(e)i
+(when)d(reading)h(or)g(searc)m(hing)h(for)f(a)g(k)m(eyw)m(ord.)40
+b(The)24 b(curren)m(t)h(implemen)m(tation)h(allo)m(ws)h(an)m(y)0
+4793 y(ASCI)s(I)i(text)j(c)m(haracter)h(\(ASCI)s(I)c(32)j(to)f(ASCI)s
+(I)f(126\))i(in)f(the)g(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)g(also)g(required)f(on)g
+(either)h(side)f(of)h(the)f(equal)h(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)i(for)d
+(compressing)h(n-dimensional)f(images)h(and)f(storing)h(the)g
+(resulting)0 5601 y(b)m(yte)i(stream)g(in)f(a)h(v)-5
+b(ariable-length)41 b(column)e(in)g(a)h(FITS)f(binary)f(table.)69
+b(The)39 b(general)i(principle)e(used)f(in)0 5714 y(this)c(con)m(v)m
+(en)m(tion)j(is)d(to)h(\014rst)f(divide)g(the)h(n-dimensional)f(image)i
+(in)m(to)f(a)g(rectangular)g(grid)f(of)h(subimages)f(or)p
+eop end
+%%Page: 157 165
+TeXDict begin 157 164 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(157)0 555 y(`tiles'.)57
+b(Eac)m(h)35 b(tile)i(is)e(then)g(compressed)g(as)g(a)h(con)m(tin)m
+(uous)g(blo)s(c)m(k)f(of)h(data,)h(and)e(the)g(resulting)g(compressed)0
+668 y(b)m(yte)i(stream)h(is)f(stored)g(in)f(a)h(ro)m(w)g(of)g(a)h(v)-5
+b(ariable)37 b(length)g(column)g(in)g(a)g(FITS)f(binary)g(table.)61
+b(By)37 b(dividing)0 781 y(the)j(image)g(in)m(to)g(tiles)h(it)f(is)f
+(generally)i(p)s(ossible)e(to)h(extract)h(and)d(uncompress)g
+(subsections)i(of)f(the)h(image)0 894 y(without)d(ha)m(ving)h(to)g
+(uncompress)e(the)h(whole)g(image.)62 b(The)37 b(default)g(tiling)h
+(pattern)g(treats)g(eac)m(h)g(ro)m(w)f(of)h(a)0 1007
+y(2-dimensional)e(image)g(\(or)f(higher)f(dimensional)h(cub)s(e\))g(as)
+g(a)g(tile,)j(suc)m(h)c(that)i(eac)m(h)g(tile)g(con)m(tains)g(NAXIS1)0
+1120 y(pixels)29 b(\(except)h(the)f(default)g(with)g(the)g(HCOMPRESS)e
+(algorithm)j(is)f(to)h(compress)f(the)g(whole)g(2D)h(image)g(as)0
+1233 y(a)35 b(single)g(tile\).)56 b(An)m(y)34 b(other)h(rectangular)h
+(tiling)g(pattern)f(ma)m(y)g(also)h(b)s(e)e(de\014ned.)52
+b(In)34 b(the)h(case)h(of)f(relativ)m(ely)0 1346 y(small)25
+b(images)h(it)f(ma)m(y)g(b)s(e)f(su\016cien)m(t)h(to)h(compress)e(the)h
+(en)m(tire)g(image)h(as)f(a)g(single)h(tile,)h(resulting)d(in)h(an)f
+(output)0 1458 y(binary)29 b(table)i(with)f(1)g(ro)m(w.)41
+b(In)29 b(the)h(case)h(of)f(3-dimensional)h(data)g(cub)s(es,)e(it)i(ma)
+m(y)f(b)s(e)f(adv)-5 b(an)m(tageous)32 b(to)f(treat)0
+1571 y(eac)m(h)i(plane)f(of)g(the)g(cub)s(e)f(as)h(a)g(separate)h(tile)
+g(if)f(application)h(soft)m(w)m(are)h(t)m(ypically)f(needs)f(to)g
+(access)i(the)e(cub)s(e)0 1684 y(on)e(a)h(plane)f(b)m(y)h(plane)f
+(basis.)0 1844 y(See)41 b(section)g(5.6)h(\\Image)f(Compression")f(for)
+g(more)h(information)g(on)f(using)g(this)g(tile-compressed)i(image)0
+1957 y(format.)p eop end
+%%Page: 158 166
+TeXDict begin 158 165 bop 0 299 a Fj(158)1741 b Fh(CHAPTER)30
+b(12.)112 b(LOCAL)29 b(FITS)h(CONVENTIONS)p eop end
+%%Page: 159 167
+TeXDict begin 159 166 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)i(designed)f(to)h(obtain)g(the)f(highest)h
+(p)s(ossible)e(sp)s(eed)h(when)f(reading)h(and)g(writing)0
+2293 y(FITS)33 b(\014les.)51 b(In)33 b(order)h(to)g(ac)m(hiev)m(e)i
+(the)e(b)s(est)g(p)s(erformance,)g(ho)m(w)m(ev)m(er,)i(application)g
+(programmers)d(m)m(ust)h(b)s(e)0 2406 y(careful)24 b(to)h(call)g(the)f
+(CFITSIO)f(routines)g(appropriately)i(and)e(in)h(an)f(e\016cien)m(t)j
+(sequence;)h(inappropriate)c(usage)0 2518 y(of)31 b(CFITSIO)d(routines)
+j(can)f(greatly)i(slo)m(w)f(do)m(wn)f(the)h(execution)g(sp)s(eed)f(of)g
+(a)h(program.)0 2679 y(The)f(maxim)m(um)h(p)s(ossible)f(I/O)h(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)f(is)g(running)e(on.)41
+b(As)30 b(a)g(rough)g(guide,)g(the)g(curren)m(t)g(generation)h(of)f(w)m
+(orkstations)h(can)g(ac)m(hiev)m(e)h(sp)s(eeds)0 2904
+y(of)j(2)g({)g(10)g(MB/s)h(when)e(reading)h(or)f(writing)h(FITS)f
+(images)i(and)e(similar,)i(or)f(sligh)m(tly)h(slo)m(w)m(er)g(sp)s(eeds)
+d(with)0 3017 y(FITS)c(binary)h(tables.)41 b(Reading)31
+b(of)f(FITS)g(\014les)g(can)h(o)s(ccur)f(at)h(ev)m(en)f(higher)g(rates)
+h(\(30MB/s)i(or)d(more\))h(if)f(the)0 3130 y(FITS)c(\014le)h(is)f
+(still)i(cac)m(hed)g(in)e(system)h(memory)f(follo)m(wing)j(a)e
+(previous)f(read)g(or)h(write)g(op)s(eration)g(on)g(the)g(same)0
+3243 y(\014le.)44 b(T)-8 b(o)32 b(more)g(accurately)h(predict)e(the)h
+(b)s(est)f(p)s(erformance)g(that)h(is)f(p)s(ossible)g(on)h(an)m(y)g
+(particular)f(system,)i(a)0 3356 y(diagnostic)h(program)f(called)h
+(\\sp)s(eed.c")f(is)g(included)f(with)h(the)g(CFITSIO)e(distribution)h
+(whic)m(h)h(can)g(b)s(e)f(run)0 3469 y(to)f(appro)m(ximately)h(measure)
+e(the)h(maxim)m(um)f(p)s(ossible)g(sp)s(eed)f(of)i(writing)f(and)g
+(reading)h(a)f(test)i(FITS)d(\014le.)0 3629 y(The)k(follo)m(wing)h(2)g
+(sections)g(pro)m(vide)g(some)f(bac)m(kground)g(on)h(ho)m(w)f(CFITSIO)f
+(in)m(ternally)i(manages)g(the)f(data)0 3742 y(I/O)g(and)g(describ)s
+(es)f(some)i(strategies)h(that)f(ma)m(y)g(b)s(e)e(used)h(to)h(optimize)
+g(the)g(pro)s(cessing)f(sp)s(eed)f(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)i(in)m(v)m(olv)m(e)i(transferring)d(only)h(a)
+g(small)g(n)m(um)m(b)s(er)f(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)e(a)g(k)m(eyw)m(ord,)h(or)f
+(writing)g(a)g(ro)m(w)g(in)f(a)h(table\);)i(it)f(w)m(ould)e(b)s(e)g(v)m
+(ery)i(ine\016cien)m(t)g(to)f(ph)m(ysically)h(read)0
+4763 y(or)i(write)h(suc)m(h)f(small)g(blo)s(c)m(ks)h(of)f(data)h
+(directly)g(in)f(the)g(FITS)g(\014le)g(on)g(disk,)h(therefore)f
+(CFITSIO)f(main)m(tains)0 4876 y(a)38 b(set)g(of)g(in)m(ternal)h
+(Input{Output)c(\(IO\))j(bu\013ers)f(in)g(RAM)h(memory)g(that)g(eac)m
+(h)h(con)m(tain)g(one)f(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)f(the)g(FITS)f(\014le,)j(it)e(\014rst)f(transfers)h
+(the)0 5102 y(FITS)30 b(blo)s(c)m(k)h(con)m(taining)h(those)f(b)m(ytes)
+g(in)m(to)g(one)g(of)f(the)h(IO)f(bu\013ers)f(in)h(memory)-8
+b(.)42 b(The)30 b(next)g(time)h(CFITSIO)0 5215 y(needs)36
+b(to)g(access)i(b)m(ytes)e(in)g(the)g(same)h(blo)s(c)m(k)f(it)h(can)f
+(then)g(go)h(to)f(the)h(fast)f(IO)f(bu\013er)g(rather)h(than)g(using)g
+(a)0 5328 y(m)m(uc)m(h)c(slo)m(w)m(er)i(system)e(disk)g(access)h
+(routine.)46 b(The)32 b(n)m(um)m(b)s(er)f(of)h(a)m(v)-5
+b(ailable)35 b(IO)d(bu\013ers)f(is)h(determined)g(b)m(y)g(the)0
+5441 y(NIOBUF)f(parameter)g(\(in)f(\014tsio2.h\))h(and)f(is)h(curren)m
+(tly)f(set)h(to)g(40)g(b)m(y)g(default.)0 5601 y(Whenev)m(er)24
+b(CFITSIO)f(reads)g(or)h(writes)g(data)g(it)h(\014rst)e(c)m(hec)m(ks)i
+(to)g(see)f(if)g(that)g(blo)s(c)m(k)h(of)f(the)g(FITS)f(\014le)g(is)h
+(already)0 5714 y(loaded)33 b(in)m(to)g(one)f(of)g(the)g(IO)g
+(bu\013ers.)44 b(If)32 b(not,)h(and)e(if)h(there)g(is)g(an)g(empt)m(y)h
+(IO)e(bu\013er)g(a)m(v)-5 b(ailable,)35 b(then)d(it)h(will)1882
+5942 y(159)p eop end
+%%Page: 160 168
+TeXDict begin 160 167 bop 0 299 a Fj(160)1876 b Fh(CHAPTER)30
+b(13.)112 b(OPTIMIZING)29 b(PR)m(OGRAMS)0 555 y Fj(load)k(that)h(blo)s
+(c)m(k)f(in)m(to)g(the)g(IO)g(bu\013er)e(\(when)h(reading)h(a)g(FITS)f
+(\014le\))h(or)g(will)g(initialize)i(a)e(new)f(blo)s(c)m(k)i(\(when)0
+668 y(writing)j(to)h(a)g(FITS)f(\014le\).)62 b(If)37
+b(all)h(the)g(IO)e(bu\013ers)h(are)g(already)h(full,)h(it)f(m)m(ust)g
+(decide)f(whic)m(h)g(one)h(to)g(reuse)0 781 y(\(generally)c(the)f(one)g
+(that)g(has)f(b)s(een)g(accessed)i(least)f(recen)m(tly\),)i(and)d
+(\015ush)f(the)i(con)m(ten)m(ts)h(bac)m(k)g(to)f(disk)f(if)g(it)0
+894 y(has)e(b)s(een)g(mo)s(di\014ed)f(b)s(efore)h(loading)h(the)g(new)f
+(blo)s(c)m(k.)0 1054 y(The)g(one)g(ma)5 b(jor)30 b(exception)i(to)f
+(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)i(con)m(tiguous)f(set)g(of)f(b)m(ytes)h(are)0
+1167 y(accessed,)37 b(as)d(migh)m(t)i(o)s(ccur)e(when)f(reading)i(or)f
+(writing)g(a)h(FITS)f(image.)54 b(In)34 b(this)g(case)h(CFITSIO)e(b)m
+(ypasses)0 1280 y(the)i(in)m(ternal)h(IO)f(bu\013ers)f(and)g(simply)h
+(reads)g(or)g(writes)h(the)f(desired)g(b)m(ytes)g(directly)h(in)f(the)g
+(disk)g(\014le)g(with)0 1393 y(a)i(single)g(call)g(to)g(a)g(lo)m(w-lev)
+m(el)i(\014le)d(read)g(or)h(write)f(routine.)58 b(The)36
+b(minim)m(um)g(threshold)f(for)h(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)g(this)h(w)m(a)m(y)g(is)f
+(set)h(b)m(y)f(the)g(MINDIRECT)g(parameter)h(and)e(is)i(curren)m(tly)f
+(set)h(to)g(3)0 1619 y(FITS)28 b(blo)s(c)m(ks)g(=)g(8640)i(b)m(ytes.)41
+b(This)28 b(is)g(the)g(most)h(e\016cien)m(t)h(w)m(a)m(y)f(to)g(read)g
+(or)f(write)h(large)g(c)m(h)m(unks)f(of)g(data)i(and)0
+1732 y(can)37 b(ac)m(hiev)m(e)i(IO)d(transfer)g(rates)h(of)g(5)g({)g
+(10MB/s)i(or)d(greater.)61 b(Note)38 b(that)f(this)g(fast)g(direct)g
+(IO)f(pro)s(cess)g(is)0 1844 y(not)29 b(applicable)g(when)e(accessing)j
+(columns)f(of)f(data)h(in)f(a)h(FITS)f(table)h(b)s(ecause)g(the)f(b)m
+(ytes)h(are)g(generally)h(not)0 1957 y(con)m(tiguous)g(since)f(they)g
+(are)h(in)m(terlea)m(v)m(ed)h(b)m(y)e(the)g(other)g(columns)g(of)g
+(data)g(in)g(the)g(table.)41 b(This)28 b(explains)h(wh)m(y)0
+2070 y(the)i(sp)s(eed)e(for)h(accessing)i(FITS)e(tables)h(is)f
+(generally)i(slo)m(w)m(er)f(than)g(accessing)g(FITS)f(images.)0
+2230 y(Giv)m(en)i(this)g(bac)m(kground)f(information,)h(the)g(general)g
+(strategy)h(for)e(e\016cien)m(tly)i(accessing)g(FITS)e(\014les)g
+(should)0 2343 y(b)s(e)e(apparen)m(t:)41 b(when)28 b(dealing)j(with)e
+(FITS)g(images,)i(read)e(or)h(write)g(large)g(c)m(h)m(unks)g(of)g(data)
+g(at)g(a)g(time)g(so)g(that)0 2456 y(the)25 b(direct)g(IO)f(mec)m
+(hanism)g(will)h(b)s(e)f(in)m(v)m(ok)m(ed;)k(when)c(accessing)i(FITS)e
+(headers)g(or)g(FITS)g(tables,)j(on)d(the)h(other)0 2569
+y(hand,)35 b(once)g(a)g(particular)g(FITS)f(blo)s(c)m(k)i(has)e(b)s
+(een)g(loading)i(in)m(to)f(one)g(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)g(in)g(that)g
+(blo)s(c)m(k)h(b)s(efore)f(it)g(gets)h(\015ushed)d(out)j(of)f(the)g(IO)
+f(bu\013er.)40 b(It)30 b(is)g(imp)s(ortan)m(t)g(to)0
+2795 y(a)m(v)m(oid)e(the)f(situation)g(where)f(the)h(same)g(FITS)e(blo)
+s(c)m(k)i(is)g(b)s(eing)f(read)g(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)i(section)f(giv)m(es)h(more)e(sp)s(eci\014c)h
+(suggestions)g(for)f(optimizing)i(the)e(use)g(of)h(CFITSIO.)0
+3411 y Ff(13.2)136 b(Optimization)46 b(Strategies)0 3663
+y Fj(1.)d(Because)32 b(the)f(data)g(in)g(FITS)f(\014les)h(is)g(alw)m(a)
+m(ys)h(stored)f(in)g("big-endian")h(b)m(yte)f(order,)g(where)f(the)h
+(\014rst)f(b)m(yte)0 3776 y(of)g(n)m(umeric)h(v)-5 b(alues)30
+b(con)m(tains)i(the)e(most)h(signi\014can)m(t)g(bits)f(and)g(the)g
+(last)i(b)m(yte)e(con)m(tains)i(the)e(least)i(signi\014can)m(t)0
+3889 y(bits,)e(CFITSIO)f(m)m(ust)h(sw)m(ap)g(the)g(order)f(of)h(the)h
+(b)m(ytes)f(when)f(reading)h(or)g(writing)g(FITS)g(\014les)g(when)f
+(running)0 4002 y(on)k(little-endian)i(mac)m(hines)f(\(e.g.,)i(Lin)m
+(ux)d(and)g(Microsoft)i(Windo)m(ws)e(op)s(erating)h(systems)g(running)d
+(on)j(PCs)0 4115 y(with)c(x86)h(CPUs\).)0 4275 y(On)i(fairly)h(new)f
+(CPUs)g(that)i(supp)s(ort)d("SSSE3")h(mac)m(hine)h(instructions)g
+(\(e.g.,)i(starting)f(with)e(In)m(tel)i(Core)f(2)0 4388
+y(CPUs)21 b(in)h(2007,)j(and)d(in)f(AMD)i(CPUs)e(b)s(eginning)g(in)h
+(2011\))i(signi\014can)m(tly)f(faster)f(4-b)m(yte)h(and)e(8-b)m(yte)i
+(sw)m(apping)0 4501 y(algorithms)k(are)g(a)m(v)-5 b(ailable.)42
+b(These)26 b(faster)h(b)m(yte)g(sw)m(apping)f(functions)g(are)h(not)g
+(used)e(b)m(y)i(default)f(in)g(CFITSIO)0 4614 y(\(b)s(ecause)c(of)f
+(the)h(p)s(oten)m(tial)g(co)s(de)g(p)s(ortablilit)m(y)g(issues\),)i
+(but)c(users)h(can)g(enable)h(them)f(on)h(supp)s(orted)d(platforms)0
+4727 y(b)m(y)38 b(adding)f(the)h(appropriate)f(compiler)i(\015ags)e
+(\(-mssse3)i(with)e(gcc)i(or)f(icc)g(on)g(lin)m(ux\))g(when)e
+(compiling)j(the)0 4840 y(sw)m(appro)s(c.c)30 b(source)g(\014le,)g
+(whic)m(h)g(will)g(allo)m(w)i(the)e(compiler)g(to)h(generate)h(co)s(de)
+e(using)f(the)h(SSSE3)f(instruction)0 4952 y(set.)41
+b(A)28 b(con)m(v)m(enien)m(t)i(w)m(a)m(y)f(to)g(do)g(this)f(is)g(to)h
+(con\014gure)f(the)g(CFITSIO)f(library)h(with)g(the)g(follo)m(wing)i
+(command:)95 5220 y Fe(>)96 b(./configure)44 b(--enable-ssse3)0
+5488 y Fj(Note,)37 b(ho)m(w)m(ev)m(er,)h(that)d(a)g(binary)f
+(executable)j(\014le)e(that)g(is)g(created)h(using)e(these)h(faster)g
+(functions)g(will)g(only)0 5601 y(run)c(on)h(mac)m(hines)g(that)h(supp)
+s(ort)d(the)i(SSSE3)f(mac)m(hine)i(instructions.)45 b(It)33
+b(will)f(crash)g(on)g(mac)m(hines)g(that)h(do)0 5714
+y(not)e(supp)s(ort)d(them.)p eop end
+%%Page: 161 169
+TeXDict begin 161 168 bop 0 299 a Fh(13.2.)73 b(OPTIMIZA)-8
+b(TION)29 b(STRA)-8 b(TEGIES)2186 b Fj(161)0 555 y(F)-8
+b(or)36 b(faster)f(2-b)m(yte)i(sw)m(aps)e(on)g(virtually)g(all)h
+(x86-64)h(CPUs)e(\(ev)m(en)h(those)g(that)f(do)g(not)h(supp)s(ort)d
+(SSSE3\),)j(a)0 668 y(v)-5 b(arian)m(t)26 b(using)e(only)g(SSE2)g
+(instructions)h(exists.)39 b(SSE2)24 b(is)h(enabled)f(b)m(y)h(default)g
+(on)f(x86)p 3066 668 28 4 v 34 w(64)h(CPUs)f(with)h(64-bit)0
+781 y(op)s(erating)30 b(systems)f(\(and)g(is)g(also)i(automatically)h
+(enabled)d(b)m(y)g(the)g({enable-ssse3)i(\015ag\).)41
+b(When)30 b(running)d(on)0 894 y(x86)p 143 894 V 34 w(64)k(CPUs)g(with)
+f(32-bit)i(op)s(erating)g(systems,)f(these)g(faster)h(2-b)m(yte)g(sw)m
+(apping)f(algorithms)g(are)h(not)f(used)0 1007 y(b)m(y)f(default)h(in)f
+(CFITSIO,)f(but)h(can)g(b)s(e)g(enabled)g(explicitly)i(with:)0
+1233 y Fe(./configure)45 b(--enable-sse2)0 1460 y Fj(Preliminary)f
+(testing)h(indicates)g(that)g(these)f(SSSE3)f(and)g(SSE2)g(based)h(b)m
+(yte-sw)m(apping)h(algorithms)g(can)0 1573 y(b)s(o)s(ost)31
+b(the)h(CFITSIO)e(p)s(erformance)h(when)f(reading)i(or)f(writing)h
+(FITS)f(images)h(b)m(y)g(20\045)g(-)g(30\045)g(or)f(more.)45
+b(It)0 1686 y(is)36 b(imp)s(ortan)m(t)g(to)g(note,)i(ho)m(w)m(ev)m(er,)
+h(that)d(compiler)g(optimization)i(m)m(ust)e(b)s(e)f(turned)f(on)i
+(\(e.g.,)j(b)m(y)d(using)f(the)0 1799 y(-O1)f(or)g(-O2)g(\015ags)g(in)g
+(gcc\))h(when)e(building)g(programs)h(that)g(use)g(these)g(fast)g(b)m
+(yte-sw)m(apping)h(algorithms)f(in)0 1912 y(order)d(to)h(reap)f(the)h
+(full)f(b)s(ene\014t)g(of)g(the)h(SSSE3)e(and)h(SSE2)g(instructions;)h
+(without)f(optimization,)j(the)e(co)s(de)0 2025 y(ma)m(y)f(actually)h
+(run)d(slo)m(w)m(er)i(than)f(when)g(using)g(more)g(traditional)i(b)m
+(yte-sw)m(apping)f(tec)m(hniques.)0 2185 y(2.)54 b(When)34
+b(dealing)h(with)g(a)g(FITS)e(primary)h(arra)m(y)h(or)g(IMA)m(GE)g
+(extension,)i(it)e(is)f(more)h(e\016cien)m(t)h(to)f(read)g(or)0
+2298 y(write)c(large)g(c)m(h)m(unks)f(of)g(the)h(image)g(at)h(a)e(time)
+h(\(at)h(least)f(3)g(FITS)f(blo)s(c)m(ks)g(=)g(8640)i(b)m(ytes\))f(so)g
+(that)g(the)f(direct)0 2411 y(IO)j(mec)m(hanism)h(will)f(b)s(e)g(used)g
+(as)g(describ)s(ed)g(in)g(the)g(previous)g(section.)51
+b(Smaller)34 b(c)m(h)m(unks)f(of)g(data)h(are)g(read)0
+2524 y(or)d(written)g(via)h(the)f(IO)f(bu\013ers,)g(whic)m(h)h(is)g
+(somewhat)g(less)g(e\016cien)m(t)i(b)s(ecause)e(of)g(the)g(extra)h(cop)
+m(y)f(op)s(eration)0 2636 y(and)26 b(additional)h(b)s(o)s(okk)m(eeping)
+g(steps)g(that)g(are)g(required.)39 b(In)26 b(principle)g(it)h(is)g
+(more)f(e\016cien)m(t)i(to)g(read)e(or)h(write)0 2749
+y(as)i(big)g(an)g(arra)m(y)h(of)f(image)h(pixels)f(at)h(one)f(time)g
+(as)h(p)s(ossible,)f(ho)m(w)m(ev)m(er,)h(if)f(the)h(arra)m(y)f(b)s
+(ecomes)g(so)g(large)h(that)0 2862 y(the)i(op)s(erating)g(system)f
+(cannot)h(store)g(it)g(all)h(in)e(RAM,)h(then)f(the)h(p)s(erformance)f
+(ma)m(y)h(b)s(e)f(degraded)g(b)s(ecause)0 2975 y(of)g(the)f(increased)h
+(sw)m(apping)f(of)g(virtual)h(memory)f(to)h(disk.)0 3135
+y(3.)51 b(When)33 b(dealing)i(with)e(FITS)g(tables,)j(the)e(most)g(imp)
+s(ortan)m(t)g(e\016ciency)g(factor)h(in)e(the)h(soft)m(w)m(are)h
+(design)f(is)0 3248 y(to)j(read)f(or)g(write)g(the)g(data)h(in)f(the)g
+(FITS)g(\014le)g(in)g(a)g(single)h(pass)f(through)f(the)h(\014le.)58
+b(An)36 b(example)h(of)f(p)s(o)s(or)0 3361 y(program)g(design)h(w)m
+(ould)f(b)s(e)g(to)h(read)g(a)f(large,)k(3-column)d(table)g(b)m(y)g
+(sequen)m(tially)h(reading)f(the)f(en)m(tire)i(\014rst)0
+3474 y(column,)25 b(then)f(going)h(bac)m(k)f(to)h(read)e(the)h(2nd)g
+(column,)h(and)e(\014nally)h(the)g(3rd)f(column;)j(this)e(ob)m(viously)
+g(requires)0 3587 y(3)j(passes)g(through)g(the)g(\014le)g(whic)m(h)g
+(could)g(triple)g(the)h(execution)g(time)g(of)f(an)g(IO)f(limited)i
+(program.)40 b(F)-8 b(or)27 b(small)0 3700 y(tables)k(this)f(is)h(not)f
+(imp)s(ortan)m(t,)h(but)f(when)f(reading)h(m)m(ulti-megab)m(yte)j
+(sized)e(tables)g(these)g(ine\016ciencies)h(can)0 3813
+y(b)s(ecome)d(signi\014can)m(t.)41 b(The)28 b(more)h(e\016cien)m(t)h
+(pro)s(cedure)d(in)i(this)f(case)i(is)e(to)i(read)e(or)h(write)g(only)f
+(as)h(man)m(y)g(ro)m(ws)0 3926 y(of)j(the)g(table)g(as)g(will)g(\014t)g
+(in)m(to)g(the)g(a)m(v)-5 b(ailable)34 b(in)m(ternal)e(IO)f(bu\013ers,)
+h(then)f(access)i(all)f(the)g(necessary)g(columns)0 4039
+y(of)f(data)h(within)e(that)i(range)f(of)g(ro)m(ws.)43
+b(Then)29 b(after)j(the)f(program)g(is)g(completely)h(\014nished)e
+(with)g(the)i(data)f(in)0 4152 y(those)i(ro)m(ws)e(it)i(can)f(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)f(\014t)
+g(in)g(the)g(bu\013ers,)f(con)m(tin)m(uing)i(in)f(this)0
+4264 y(w)m(a)m(y)c(un)m(til)f(the)f(en)m(tire)i(\014le)f(has)f(b)s(een)
+g(pro)s(cessed.)39 b(By)27 b(using)f(this)h(pro)s(cedure)e(of)i
+(accessing)h(all)g(the)e(columns)h(of)0 4377 y(a)j(table)g(in)f
+(parallel)h(rather)f(than)g(sequen)m(tially)-8 b(,)32
+b(eac)m(h)e(blo)s(c)m(k)g(of)g(the)f(FITS)g(\014le)g(will)g(only)h(b)s
+(e)e(read)i(or)f(written)0 4490 y(once.)0 4650 y(The)g(optimal)h(n)m
+(um)m(b)s(er)e(of)i(ro)m(ws)f(to)i(read)e(or)g(write)h(at)g(one)g(time)
+g(in)f(a)h(giv)m(en)g(table)h(dep)s(ends)c(on)j(the)f(width)g(of)0
+4763 y(the)c(table)h(ro)m(w)f(and)f(on)h(the)g(n)m(um)m(b)s(er)e(of)i
+(IO)g(bu\013ers)e(that)j(ha)m(v)m(e)g(b)s(een)e(allo)s(cated)j(in)e
+(CFITSIO.)e(The)h(CFITSIO)0 4876 y(Iterator)h(routine)f(will)g
+(automatically)j(use)c(the)h(optimal-sized)i(bu\013er,)e(but)g(there)g
+(is)g(also)g(a)h(CFITSIO)d(routine)0 4989 y(that)31 b(will)g(return)f
+(the)h(optimal)h(n)m(um)m(b)s(er)d(of)i(ro)m(ws)g(for)f(a)h(giv)m(en)h
+(table:)43 b(\014ts)p 2629 4989 V 32 w(get)p 2781 4989
+V 34 w(ro)m(wsize.)g(It)31 b(is)g(not)g(critical)h(to)0
+5102 y(use)h(exactly)j(the)e(v)-5 b(alue)34 b(of)g(nro)m(ws)f(returned)
+f(b)m(y)i(this)g(routine,)g(as)g(long)h(as)f(one)g(do)s(es)f(not)h
+(exceed)h(it.)51 b(Using)0 5215 y(a)37 b(v)m(ery)g(small)g(v)-5
+b(alue)37 b(ho)m(w)m(ev)m(er)h(can)f(also)g(lead)g(to)h(p)s(o)s(or)d(p)
+s(erformance)h(b)s(ecause)g(of)h(the)g(o)m(v)m(erhead)h(from)e(the)0
+5328 y(larger)31 b(n)m(um)m(b)s(er)e(of)i(subroutine)e(calls.)0
+5488 y(The)36 b(optimal)h(n)m(um)m(b)s(er)e(of)h(ro)m(ws)g(returned)f
+(b)m(y)i(\014ts)p 1829 5488 V 32 w(get)p 1981 5488 V
+34 w(ro)m(wsize)g(is)g(v)-5 b(alid)36 b(only)g(as)h(long)g(as)f(the)h
+(application)0 5601 y(program)27 b(is)g(only)g(reading)h(or)f(writing)g
+(data)h(in)f(the)g(sp)s(eci\014ed)f(table.)41 b(An)m(y)27
+b(other)g(calls)i(to)f(access)g(data)g(in)f(the)0 5714
+y(table)i(header)f(w)m(ould)f(cause)i(additional)g(blo)s(c)m(ks)f(of)g
+(data)g(to)h(b)s(e)e(loaded)i(in)m(to)g(the)f(IO)f(bu\013ers)g
+(displacing)h(data)p eop end
+%%Page: 162 170
+TeXDict begin 162 169 bop 0 299 a Fj(162)1876 b Fh(CHAPTER)30
+b(13.)112 b(OPTIMIZING)29 b(PR)m(OGRAMS)0 555 y Fj(from)34
+b(the)h(original)h(table,)h(and)d(should)f(b)s(e)h(a)m(v)m(oided)i
+(during)e(the)h(critical)h(p)s(erio)s(d)e(while)g(the)h(table)h(is)e(b)
+s(eing)0 668 y(read)c(or)h(written.)0 828 y(4.)39 b(Use)25
+b(the)g(CFITSIO)e(Iterator)j(routine.)39 b(This)24 b(routine)h(pro)m
+(vides)f(a)i(more)e(`ob)5 b(ject)26 b(orien)m(ted')g(w)m(a)m(y)g(of)f
+(reading)0 941 y(and)34 b(writing)g(FITS)g(\014les)g(whic)m(h)h
+(automatically)i(uses)d(the)g(most)h(appropriate)g(data)g(bu\013er)e
+(size)i(to)h(ac)m(hiev)m(e)0 1054 y(the)31 b(maxim)m(um)f(I/O)g
+(throughput.)0 1214 y(5.)39 b(Use)24 b(binary)f(table)h(extensions)g
+(rather)f(than)h(ASCI)s(I)e(table)i(extensions)g(for)f(b)s(etter)h
+(e\016ciency)h(when)d(dealing)0 1327 y(with)37 b(tabular)h(data.)62
+b(The)37 b(I/O)g(to)h(ASCI)s(I)e(tables)i(is)g(slo)m(w)m(er)g(b)s
+(ecause)g(of)f(the)h(o)m(v)m(erhead)h(in)e(formatting)h(or)0
+1440 y(parsing)32 b(the)g(ASCI)s(I)f(data)i(\014elds)f(and)g(b)s
+(ecause)g(ASCI)s(I)f(tables)i(are)g(ab)s(out)f(t)m(wice)i(as)f(large)g
+(as)g(binary)e(tables)0 1553 y(that)g(ha)m(v)m(e)h(the)e(same)h
+(information)g(con)m(ten)m(t.)0 1713 y(6.)64 b(Design)39
+b(soft)m(w)m(are)g(so)g(that)f(it)h(reads)f(the)g(FITS)f(header)h(k)m
+(eyw)m(ords)g(in)g(the)g(same)h(order)e(in)h(whic)m(h)g(they)0
+1826 y(o)s(ccur)28 b(in)h(the)g(\014le.)40 b(When)28
+b(reading)h(k)m(eyw)m(ords,)h(CFITSIO)d(searc)m(hes)i(forw)m(ard)g
+(starting)g(from)f(the)h(p)s(osition)g(of)0 1939 y(the)g(last)i(k)m
+(eyw)m(ord)e(that)h(w)m(as)g(read.)40 b(If)29 b(it)g(reac)m(hes)i(the)e
+(end)g(of)g(the)h(header)f(without)g(\014nding)f(the)h(k)m(eyw)m(ord,)h
+(it)0 2052 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)h(the)g(searc)m(h)g(do)m(wn)f(to)h(the)
+g(p)s(osition)f(where)g(it)0 2165 y(started.)41 b(In)30
+b(practice,)i(as)e(long)h(as)g(the)f(en)m(tire)i(FITS)d(header)h(can)h
+(\014t)f(at)h(one)g(time)g(in)f(the)g(a)m(v)-5 b(ailable)33
+b(in)m(ternal)0 2278 y(IO)23 b(bu\013ers,)i(then)e(the)i(header)e(k)m
+(eyw)m(ord)i(access)g(will)f(b)s(e)g(relativ)m(ely)i(fast)e(and)g(it)g
+(mak)m(es)h(little)h(di\013erence)e(whic)m(h)0 2391 y(order)30
+b(they)g(are)h(accessed.)0 2551 y(7.)40 b(Av)m(oid)29
+b(the)e(use)h(of)f(scaling)i(\(b)m(y)f(using)f(the)h(BSCALE)e(and)h
+(BZER)m(O)h(or)f(TSCAL)g(and)g(TZER)m(O)f(k)m(eyw)m(ords\))0
+2664 y(in)35 b(FITS)f(\014les)g(since)i(the)f(scaling)h(op)s(erations)f
+(add)f(to)i(the)f(pro)s(cessing)f(time)i(needed)e(to)i(read)f(or)g
+(write)g(the)0 2777 y(data.)k(In)24 b(some)h(cases)h(it)f(ma)m(y)g(b)s
+(e)f(more)g(e\016cien)m(t)i(to)g(temp)s(orarily)e(turn)g(o\013)h(the)f
+(scaling)i(\(using)e(\014ts)p 3490 2777 28 4 v 33 w(set)p
+3634 2777 V 33 w(bscale)0 2889 y(or)30 b(\014ts)p 238
+2889 V 33 w(set)p 382 2889 V 33 w(tscale\))j(and)c(then)h(read)h(or)f
+(write)h(the)f(ra)m(w)h(unscaled)f(v)-5 b(alues)31 b(in)f(the)g(FITS)g
+(\014le.)0 3050 y(8.)77 b(Av)m(oid)43 b(using)f(the)h(`implicit)g(data)
+h(t)m(yp)s(e)e(con)m(v)m(ersion')i(capabilit)m(y)g(in)e(CFITSIO.)f(F)-8
+b(or)44 b(instance,)i(when)0 3163 y(reading)28 b(a)g(FITS)f(image)i
+(with)e(BITPIX)h(=)f(-32)i(\(32-bit)g(\015oating)g(p)s(oin)m(t)f
+(pixels\),)h(read)e(the)h(data)g(in)m(to)h(a)f(single)0
+3275 y(precision)40 b(\015oating)h(p)s(oin)m(t)f(data)h(arra)m(y)f(in)g
+(the)g(program.)69 b(F)-8 b(orcing)41 b(CFITSIO)e(to)i(con)m(v)m(ert)g
+(the)f(data)h(to)g(a)0 3388 y(di\013eren)m(t)31 b(data)g(t)m(yp)s(e)f
+(can)h(slo)m(w)g(the)g(program.)0 3548 y(9.)57 b(Where)36
+b(feasible,)i(design)e(FITS)f(binary)g(tables)h(using)f(v)m(ector)j
+(column)d(elemen)m(ts)i(so)f(that)g(the)g(data)h(are)0
+3661 y(written)30 b(as)g(a)g(con)m(tiguous)h(set)f(of)g(b)m(ytes,)g
+(rather)g(than)f(as)h(single)g(elemen)m(ts)h(in)f(m)m(ultiple)g(ro)m
+(ws.)41 b(F)-8 b(or)30 b(example,)0 3774 y(it)36 b(is)g(faster)g(to)g
+(access)h(the)f(data)h(in)e(a)h(table)h(that)f(con)m(tains)h(a)f
+(single)g(ro)m(w)g(and)f(2)h(columns)f(with)h(TF)m(ORM)0
+3887 y(k)m(eyw)m(ords)d(equal)h(to)g('10000E')h(and)e('10000J',)j(than)
+d(it)g(is)g(to)h(access)g(the)g(same)f(amoun)m(t)h(of)f(data)h(in)f(a)g
+(table)0 4000 y(with)40 b(10000)j(ro)m(ws)d(whic)m(h)h(has)f(columns)g
+(with)g(the)h(TF)m(ORM)g(k)m(eyw)m(ords)g(equal)g(to)g('1E')h(and)e
+('1J'.)h(In)f(the)0 4113 y(former)27 b(case)i(the)f(10000)i(\015oating)
+f(p)s(oin)m(t)f(v)-5 b(alues)28 b(in)g(the)g(\014rst)f(column)h(are)g
+(all)h(written)f(in)f(a)h(con)m(tiguous)h(blo)s(c)m(k)0
+4226 y(of)d(the)f(\014le)h(whic)m(h)f(can)h(b)s(e)f(read)g(or)g
+(written)h(quic)m(kly)-8 b(,)28 b(whereas)d(in)g(the)h(second)f(case)i
+(eac)m(h)g(\015oating)f(p)s(oin)m(t)f(v)-5 b(alue)0 4339
+y(in)34 b(the)g(\014rst)f(column)g(is)h(in)m(terlea)m(v)m(ed)j(with)c
+(the)h(in)m(teger)i(v)-5 b(alue)34 b(in)g(the)g(second)g(column)f(of)h
+(the)g(same)h(ro)m(w)f(so)0 4452 y(CFITSIO)29 b(has)h(to)h(explicitly)h
+(mo)m(v)m(e)g(to)f(the)g(p)s(osition)f(of)h(eac)m(h)g(elemen)m(t)h(to)f
+(b)s(e)f(read)g(or)g(written.)0 4612 y(10.)45 b(Av)m(oid)33
+b(the)f(use)f(of)h(v)-5 b(ariable)32 b(length)g(v)m(ector)h(columns)f
+(in)f(binary)g(tables,)i(since)f(an)m(y)g(reading)f(or)h(writing)0
+4725 y(of)h(these)g(data)g(requires)f(that)h(CFITSIO)f(\014rst)f(lo)s
+(ok)j(up)d(or)i(compute)g(the)f(starting)i(address)e(of)g(eac)m(h)i(ro)
+m(w)f(of)0 4838 y(data)e(in)f(the)h(heap.)40 b(In)30
+b(practice,)i(this)e(is)g(probably)g(not)h(a)f(signi\014can)m(t)i
+(e\016ciency)f(issue.)0 4998 y(11.)73 b(When)40 b(cop)m(ying)i(data)g
+(from)e(one)h(FITS)f(table)i(to)f(another,)j(it)e(is)e(faster)i(to)f
+(transfer)g(the)f(ra)m(w)h(b)m(ytes)0 5111 y(instead)28
+b(of)h(reading)f(then)g(writing)g(eac)m(h)h(column)f(of)g(the)g(table.)
+41 b(The)28 b(CFITSIO)e(routines)i(\014ts)p 3349 5111
+V 33 w(read)p 3554 5111 V 32 w(tblb)m(ytes)0 5224 y(and)36
+b(\014ts)p 310 5224 V 32 w(write)p 544 5224 V 33 w(tblb)m(ytes)i(will)f
+(p)s(erform)e(lo)m(w-lev)m(el)k(reads)e(or)f(writes)h(of)g(an)m(y)g
+(con)m(tiguous)g(range)g(of)g(b)m(ytes)g(in)0 5337 y(a)d(table)g
+(extension.)51 b(These)33 b(routines)h(can)f(b)s(e)g(used)g(to)h(read)f
+(or)h(write)g(a)f(whole)h(ro)m(w)g(\(or)g(m)m(ultiple)g(ro)m(ws)f(for)0
+5450 y(ev)m(en)e(greater)h(e\016ciency\))h(of)e(a)g(table)h(with)e(a)h
+(single)h(function)e(call.)43 b(These)31 b(routines)g(are)g(fast)g(b)s
+(ecause)g(they)0 5562 y(b)m(ypass)36 b(all)h(the)g(usual)f(data)h
+(scaling,)i(error)d(c)m(hec)m(king)i(and)e(mac)m(hine)h(dep)s(enden)m
+(t)e(data)i(con)m(v)m(ersion)h(that)f(is)0 5675 y(normally)g(done)g(b)m
+(y)f(CFITSIO,)g(and)g(they)h(allo)m(w)h(the)g(program)e(to)i(write)f
+(the)g(data)g(to)h(the)f(output)f(\014le)h(in)p eop end
+%%Page: 163 171
+TeXDict begin 163 170 bop 0 299 a Fh(13.2.)73 b(OPTIMIZA)-8
+b(TION)29 b(STRA)-8 b(TEGIES)2186 b Fj(163)0 555 y(exactly)30
+b(the)e(same)h(b)m(yte)g(order.)40 b(F)-8 b(or)29 b(these)f(same)h
+(reasons,)g(these)g(routines)f(can)g(corrupt)g(the)g(FITS)g(data)h
+(\014le)0 668 y(if)36 b(used)e(incorrectly)j(b)s(ecause)f(no)f(v)-5
+b(alidation)37 b(or)f(mac)m(hine)g(dep)s(enden)m(t)e(con)m(v)m(ersion)j
+(is)f(p)s(erformed)e(b)m(y)h(these)0 781 y(routines.)55
+b(These)35 b(routines)g(are)h(only)f(recommended)g(for)g(optimizing)h
+(critical)h(pieces)f(of)g(co)s(de)f(and)g(should)0 894
+y(only)e(b)s(e)g(used)g(b)m(y)g(programmers)g(who)g(thoroughly)g
+(understand)e(the)j(in)m(ternal)g(format)g(of)f(the)h(FITS)e(tables)0
+1007 y(they)f(are)f(reading)h(or)f(writing.)0 1167 y(12.)41
+b(Another)30 b(strategy)g(for)g(impro)m(ving)f(the)h(sp)s(eed)e(of)i
+(writing)g(a)f(FITS)g(table,)i(similar)f(to)g(the)f(previous)g(one,)0
+1280 y(is)j(to)g(directly)h(construct)f(the)f(en)m(tire)i(b)m(yte)f
+(stream)g(for)g(a)g(whole)g(table)g(ro)m(w)g(\(or)g(m)m(ultiple)h(ro)m
+(ws\))f(within)f(the)0 1393 y(application)g(program)e(and)g(then)h
+(write)g(it)g(to)g(the)g(FITS)f(\014le)h(with)f(\014ts)p
+2520 1393 28 4 v 32 w(write)p 2754 1393 V 33 w(tblb)m(ytes.)41
+b(This)29 b(a)m(v)m(oids)i(all)g(the)0 1506 y(o)m(v)m(erhead)f
+(normally)g(presen)m(t)f(in)g(the)h(column-orien)m(ted)g(CFITSIO)e
+(write)h(routines.)40 b(This)29 b(tec)m(hnique)h(should)0
+1619 y(only)35 b(b)s(e)e(used)h(for)g(critical)i(applications)g(b)s
+(ecause)e(it)h(mak)m(es)h(the)e(co)s(de)h(more)f(di\016cult)h(to)g
+(understand)e(and)0 1732 y(main)m(tain,)38 b(and)d(it)h(mak)m(es)g(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
+1844 y(b)s(efore)30 b(writing)g(to)h(the)g(FITS)f(\014le?\).)0
+2005 y(13.)40 b(Finally)-8 b(,)29 b(external)e(factors)g(suc)m(h)e(as)i
+(the)f(sp)s(eed)f(of)i(the)f(data)h(storage)g(device,)h(the)f(size)g
+(of)f(the)g(data)h(cac)m(he,)0 2118 y(the)34 b(amoun)m(t)h(of)f(disk)g
+(fragmen)m(tation,)j(and)c(the)i(amoun)m(t)f(of)h(RAM)f(a)m(v)-5
+b(ailable)37 b(on)d(the)g(system)g(can)h(all)g(ha)m(v)m(e)0
+2230 y(a)k(signi\014can)m(t)g(impact)g(on)f(o)m(v)m(erall)j(I/O)d
+(e\016ciency)-8 b(.)66 b(F)-8 b(or)39 b(critical)h(applications,)i(the)
+c(en)m(tire)i(hardw)m(are)e(and)0 2343 y(soft)m(w)m(are)32
+b(system)e(should)g(b)s(e)f(review)m(ed)i(to)h(iden)m(tify)e(an)m(y)h
+(p)s(oten)m(tial)h(I/O)e(b)s(ottlenec)m(ks.)p eop end
+%%Page: 164 172
+TeXDict begin 164 171 bop 0 299 a Fj(164)1876 b Fh(CHAPTER)30
+b(13.)112 b(OPTIMIZING)29 b(PR)m(OGRAMS)p eop end
+%%Page: 165 173
+TeXDict begin 165 172 bop 0 1225 a Fg(App)5 b(endix)64
+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)245 b(88)50 2267 y(\014ts)p
+177 2267 V 32 w(ascii)p 380 2267 V 34 w(tform)579 b(66)50
+2380 y(\014ts)p 177 2380 V 32 w(binary)p 465 2380 V 32
+w(tform)496 b(66)50 2493 y(\014ts)p 177 2493 V 32 w(calculator)617
+b(57)50 2606 y(\014ts)p 177 2606 V 32 w(calculator)p
+596 2606 V 35 w(rng)450 b(57)50 2719 y(\014ts)p 177 2719
+V 32 w(calc)p 359 2719 V 35 w(binning)520 b(58)50 2832
+y(\014ts)p 177 2832 V 32 w(calc)p 359 2832 V 35 w(ro)m(ws)639
+b(56)50 2945 y(\014ts)p 177 2945 V 32 w(c)m(hange)p 478
+2945 V 34 w(group)473 b(86)50 3057 y(\014ts)p 177 3057
+V 32 w(clear)p 395 3057 V 34 w(errmark)467 b(30)50 3170
+y(\014ts)p 177 3170 V 32 w(clear)p 395 3170 V 34 w(errmsg)515
+b(30)50 3283 y(\014ts)p 177 3283 V 32 w(close)p 395 3283
+V 34 w(\014le)668 b(33)50 3396 y(\014ts)p 177 3396 V
+32 w(compact)p 541 3396 V 34 w(group)410 b(87)50 3509
+y(\014ts)p 177 3509 V 32 w(compare)p 542 3509 V 34 w(str)530
+b(63)50 3622 y(\014ts)p 177 3622 V 32 w(compress)p 569
+3622 V 33 w(heap)379 b(111)50 3735 y(\014ts)p 177 3735
+V 32 w(con)m(v)m(ert)p 498 3735 V 35 w(hdr2str)244 b(37,)31
+b(82)50 3848 y(\014ts)p 177 3848 V 32 w(cop)m(y)p 390
+3848 V 34 w(cell2image)383 b(41)50 3961 y(\014ts)p 177
+3961 V 32 w(cop)m(y)p 390 3961 V 34 w(col)679 b(53)50
+4074 y(\014ts)p 177 4074 V 32 w(cop)m(y)p 390 4074 V
+34 w(data)613 b(96)50 4187 y(\014ts)p 177 4187 V 32 w(cop)m(y)p
+390 4187 V 34 w(\014le)673 b(34)50 4299 y(\014ts)p 177
+4299 V 32 w(cop)m(y)p 390 4299 V 34 w(group)561 b(87)50
+4412 y(\014ts)p 177 4412 V 32 w(cop)m(y)p 390 4412 V
+34 w(hdu)636 b(34)50 4525 y(\014ts)p 177 4525 V 32 w(cop)m(y)p
+390 4525 V 34 w(header)526 b(34)50 4638 y(\014ts)p 177
+4638 V 32 w(cop)m(y)p 390 4638 V 34 w(image2cell)383
+b(41)50 4751 y(\014ts)p 177 4751 V 32 w(cop)m(y)p 390
+4751 V 34 w(image)p 655 4751 V 34 w(section)252 b(44)50
+4864 y(\014ts)p 177 4864 V 32 w(cop)m(y)p 390 4864 V
+34 w(k)m(ey)611 b(101)50 4977 y(\014ts)p 177 4977 V 32
+w(cop)m(y)p 390 4977 V 34 w(mem)m(b)s(er)470 b(89)50
+5090 y(\014ts)p 177 5090 V 32 w(cop)m(y)p 390 5090 V
+34 w(pixlist2image)268 b(58)50 5203 y(\014ts)p 177 5203
+V 32 w(cop)m(y)p 390 5203 V 34 w(ro)m(ws)609 b(53)50
+5316 y(\014ts)p 177 5316 V 32 w(create)p 445 5316 V 35
+w(disk\014le)457 b(32)50 5429 y(\014ts)p 177 5429 V 32
+w(create)p 445 5429 V 35 w(\014le)617 b(32)50 5541 y(\014ts)p
+177 5541 V 32 w(create)p 445 5541 V 35 w(group)505 b(86)50
+5654 y(\014ts)p 177 5654 V 32 w(create)p 445 5654 V 35
+w(hdu)580 b(95)1419 2154 y(\014ts)p 1546 2154 V 32 w(create)p
+1814 2154 V 35 w(img)565 b(41)1419 2267 y(\014ts)p 1546
+2267 V 32 w(create)p 1814 2267 V 35 w(mem\014le)403 b(92)1419
+2380 y(\014ts)p 1546 2380 V 32 w(create)p 1814 2380 V
+35 w(tbl)600 b(49)1419 2493 y(\014ts)p 1546 2493 V 32
+w(create)p 1814 2493 V 35 w(template)364 b(92)1419 2606
+y(\014ts)p 1546 2606 V 32 w(date2str)659 b(61)1419 2719
+y(\014ts)p 1546 2719 V 32 w(deco)s(de)p 1848 2719 V 33
+w(c)m(hksum)380 b(61)1419 2832 y(\014ts)p 1546 2832 V
+32 w(deco)s(de)p 1848 2832 V 33 w(tdim)492 b(51)1419
+2945 y(\014ts)p 1546 2945 V 32 w(delete)p 1809 2945 V
+34 w(col)607 b(52)1419 3057 y(\014ts)p 1546 3057 V 32
+w(delete)p 1809 3057 V 34 w(\014le)601 b(33)1419 3170
+y(\014ts)p 1546 3170 V 32 w(delete)p 1809 3170 V 34 w(hdu)564
+b(35)1419 3283 y(\014ts)p 1546 3283 V 32 w(delete)p 1809
+3283 V 34 w(k)m(ey)584 b(39)1419 3396 y(\014ts)p 1546
+3396 V 32 w(delete)p 1809 3396 V 34 w(record)469 b(39)1419
+3509 y(\014ts)p 1546 3509 V 32 w(delete)p 1809 3509 V
+34 w(ro)m(wlist)452 b(52)1419 3622 y(\014ts)p 1546 3622
+V 32 w(delete)p 1809 3622 V 34 w(ro)m(wrange)356 b(52)1419
+3735 y(\014ts)p 1546 3735 V 32 w(delete)p 1809 3735 V
+34 w(ro)m(ws)537 b(52)1419 3848 y(\014ts)p 1546 3848
+V 32 w(delete)p 1809 3848 V 34 w(str)610 b(39)1419 3961
+y(\014ts)p 1546 3961 V 32 w(enco)s(de)p 1848 3961 V 33
+w(c)m(hksum)380 b(61)1419 4074 y(\014ts)p 1546 4074 V
+32 w(\014le)p 1694 4074 V 33 w(exists)613 b(94)1419 4187
+y(\014ts)p 1546 4187 V 32 w(\014le)p 1694 4187 V 33 w(mo)s(de)618
+b(33)1419 4299 y(\014ts)p 1546 4299 V 32 w(\014le)p 1694
+4299 V 33 w(name)j(33)1419 4412 y(\014ts)p 1546 4412
+V 32 w(\014nd)p 1731 4412 V 32 w(\014rst)p 1921 4412
+V 32 w(ro)m(w)463 b(56)1419 4525 y(\014ts)p 1546 4525
+V 32 w(\014nd)p 1731 4525 V 32 w(nextk)m(ey)490 b(37)1419
+4638 y(\014ts)p 1546 4638 V 32 w(\014nd)p 1731 4638 V
+32 w(ro)m(ws)617 b(56)1419 4751 y(\014ts)p 1546 4751
+V 32 w(\015ush)p 1767 4751 V 32 w(bu\013er)530 b(94)1419
+4864 y(\014ts)p 1546 4864 V 32 w(\015ush)p 1767 4864
+V 32 w(\014le)645 b(94)1419 4977 y(\014ts)p 1546 4977
+V 32 w(free)p 1722 4977 V 33 w(memory)438 b(103)1419
+5090 y(\014ts)p 1546 5090 V 32 w(get)p 1698 5090 V 34
+w(acolparms)383 b(110)1419 5203 y(\014ts)p 1546 5203
+V 32 w(get)p 1698 5203 V 34 w(b)s(colparms)374 b(110)1419
+5316 y(\014ts)p 1546 5316 V 32 w(get)p 1698 5316 V 34
+w(c)m(hksum)529 b(60)1419 5429 y(\014ts)p 1546 5429 V
+32 w(get)p 1698 5429 V 34 w(col)p 1842 5429 V 34 w(displa)m(y)p
+2154 5429 V 33 w(width)145 b(51)1419 5541 y(\014ts)p
+1546 5541 V 32 w(get)p 1698 5541 V 34 w(colname)506 b(49)1419
+5654 y(\014ts)p 1546 5654 V 32 w(get)p 1698 5654 V 34
+w(coln)m(um)543 b(49)2765 2154 y(\014ts)p 2892 2154 V
+33 w(get)p 3045 2154 V 34 w(colt)m(yp)s(e)650 b(50)2765
+2267 y(\014ts)p 2892 2267 V 33 w(get)p 3045 2267 V 34
+w(compression)p 3560 2267 V 32 w(t)m(yp)s(e)247 b(46)2765
+2380 y(\014ts)p 2892 2380 V 33 w(get)p 3045 2380 V 34
+w(eqcolt)m(yp)s(e)562 b(50)2765 2493 y(\014ts)p 2892
+2493 V 33 w(get)p 3045 2493 V 34 w(errstatus)584 b(29)2765
+2606 y(\014ts)p 2892 2606 V 33 w(get)p 3045 2606 V 34
+w(hdrp)s(os)661 b(97)2765 2719 y(\014ts)p 2892 2719 V
+33 w(get)p 3045 2719 V 34 w(hdrspace)584 b(35)2765 2832
+y(\014ts)p 2892 2832 V 33 w(get)p 3045 2832 V 34 w(hdu)p
+3232 2832 V 31 w(n)m(um)575 b(34)2765 2945 y(\014ts)p
+2892 2945 V 33 w(get)p 3045 2945 V 34 w(hdu)p 3232 2945
+V 31 w(t)m(yp)s(e)h(34)2765 3057 y(\014ts)p 2892 3057
+V 33 w(get)p 3045 3057 V 34 w(hduaddr)598 b(95)2765 3170
+y(\014ts)p 2892 3170 V 33 w(get)p 3045 3170 V 34 w(hduaddrll)548
+b(95)2765 3283 y(\014ts)p 2892 3283 V 33 w(get)p 3045
+3283 V 34 w(img)p 3225 3283 V 33 w(dim)603 b(41)2765
+3396 y(\014ts)p 2892 3396 V 33 w(get)p 3045 3396 V 34
+w(img)p 3225 3396 V 33 w(equivt)m(yp)s(e)369 b(40)2765
+3509 y(\014ts)p 2892 3509 V 33 w(get)p 3045 3509 V 34
+w(img)p 3225 3509 V 33 w(param)502 b(41)2765 3622 y(\014ts)p
+2892 3622 V 33 w(get)p 3045 3622 V 34 w(img)p 3225 3622
+V 33 w(size)614 b(41)2765 3735 y(\014ts)p 2892 3735 V
+33 w(get)p 3045 3735 V 34 w(img)p 3225 3735 V 33 w(t)m(yp)s(e)581
+b(40)2765 3848 y(\014ts)p 2892 3848 V 33 w(get)p 3045
+3848 V 34 w(in)m(tt)m(yp)s(e)652 b(65)2765 3961 y(\014ts)p
+2892 3961 V 33 w(get)p 3045 3961 V 34 w(k)m(eyclass)619
+b(65)2765 4074 y(\014ts)p 2892 4074 V 33 w(get)p 3045
+4074 V 34 w(k)m(eyname)589 b(64)2765 4187 y(\014ts)p
+2892 4187 V 33 w(get)p 3045 4187 V 34 w(k)m(eyt)m(yp)s(e)627
+b(64)2765 4299 y(\014ts)p 2892 4299 V 33 w(get)p 3045
+4299 V 34 w(noise)p 3276 4299 V 33 w(bits)557 b(46)2765
+4412 y(\014ts)p 2892 4412 V 33 w(get)p 3045 4412 V 34
+w(n)m(um)p 3254 4412 V 32 w(cols)581 b(49)2765 4525 y(\014ts)p
+2892 4525 V 33 w(get)p 3045 4525 V 34 w(n)m(um)p 3254
+4525 V 32 w(groups)463 b(89)2765 4638 y(\014ts)p 2892
+4638 V 33 w(get)p 3045 4638 V 34 w(n)m(um)p 3254 4638
+V 32 w(hdus)538 b(34)2765 4751 y(\014ts)p 2892 4751 V
+33 w(get)p 3045 4751 V 34 w(n)m(um)p 3254 4751 V 32 w(mem)m(b)s(ers)372
+b(88)2765 4864 y(\014ts)p 2892 4864 V 33 w(get)p 3045
+4864 V 34 w(n)m(um)p 3254 4864 V 32 w(ro)m(ws)547 b(49)2765
+4977 y(\014ts)p 2892 4977 V 33 w(get)p 3045 4977 V 34
+w(ro)m(wsize)603 b(111)2765 5090 y(\014ts)p 2892 5090
+V 33 w(get)p 3045 5090 V 34 w(system)p 3350 5090 V 33
+w(time)454 b(61)2765 5203 y(\014ts)p 2892 5203 V 33 w(get)p
+3045 5203 V 34 w(tile)p 3204 5203 V 34 w(dim)623 b(46)2765
+5316 y(\014ts)p 2892 5316 V 33 w(get)p 3045 5316 V 34
+w(tb)s(col)735 b(66)2765 5429 y(\014ts)p 2892 5429 V
+33 w(get)p 3045 5429 V 34 w(v)m(ersion)656 b(62)2765
+5541 y(\014ts)p 2892 5541 V 33 w(hdr2str)651 b(37,)32
+b(82)2765 5654 y(\014ts)p 2892 5654 V 33 w(insert)p 3148
+5654 V 32 w(atbl)677 b(96)1882 5942 y(165)p eop end
+%%Page: 166 174
+TeXDict begin 166 173 bop 0 299 a Fj(166)2084 b Fh(APPENDIX)31
+b(A.)61 b(INDEX)31 b(OF)f(R)m(OUTINES)50 543 y Fj(\014ts)p
+177 543 28 4 v 32 w(insert)p 432 543 V 33 w(btbl)541
+b(96)50 656 y(\014ts)p 177 656 V 32 w(insert)p 432 656
+V 33 w(col)593 b(52)50 769 y(\014ts)p 177 769 V 32 w(insert)p
+432 769 V 33 w(cols)557 b(52)50 882 y(\014ts)p 177 882
+V 32 w(insert)p 432 882 V 33 w(group)475 b(86)50 995
+y(\014ts)p 177 995 V 32 w(insert)p 432 995 V 33 w(img)557
+b(95)50 1107 y(\014ts)p 177 1107 V 32 w(insert)p 432
+1107 V 33 w(k)m(ey)p 598 1107 V 34 w(n)m(ull)342 b(102)50
+1220 y(\014ts)p 177 1220 V 32 w(insert)p 432 1220 V 33
+w(k)m(ey)p 598 1220 V 34 w(TYP)295 b(102)50 1333 y(\014ts)p
+177 1333 V 32 w(insert)p 432 1333 V 33 w(record)410 b(102)50
+1446 y(\014ts)p 177 1446 V 32 w(insert)p 432 1446 V 33
+w(ro)m(ws)523 b(52)50 1559 y(\014ts)p 177 1559 V 32 w(is)p
+270 1559 V 33 w(reen)m(tran)m(t)502 b(71)50 1672 y(\014ts)p
+177 1672 V 32 w(iterate)p 465 1672 V 35 w(data)492 b(79)50
+1785 y(\014ts)p 177 1785 V 32 w(mak)m(e)p 415 1785 V
+34 w(hist)572 b(59)50 1898 y(\014ts)p 177 1898 V 32 w(mak)m(e)p
+415 1898 V 34 w(k)m(eyn)535 b(64)50 2011 y(\014ts)p 177
+2011 V 32 w(mak)m(e)p 415 2011 V 34 w(nk)m(ey)g(64)50
+2124 y(\014ts)p 177 2124 V 32 w(merge)p 446 2124 V 34
+w(groups)424 b(87)50 2237 y(\014ts)p 177 2237 V 32 w(mo)s(dify)p
+485 2237 V 32 w(card)434 b(104)50 2349 y(\014ts)p 177
+2349 V 32 w(mo)s(dify)p 485 2349 V 32 w(commen)m(t)291
+b(39)50 2462 y(\014ts)p 177 2462 V 32 w(mo)s(dify)p 485
+2462 V 32 w(k)m(ey)p 650 2462 V 34 w(n)m(ull)f(105)50
+2575 y(\014ts)p 177 2575 V 32 w(mo)s(dify)p 485 2575
+V 32 w(k)m(ey)p 650 2575 V 34 w(TYP)243 b(104)50 2688
+y(\014ts)p 177 2688 V 32 w(mo)s(dify)p 485 2688 V 32
+w(name)439 b(39)50 2801 y(\014ts)p 177 2801 V 32 w(mo)s(dify)p
+485 2801 V 32 w(record)358 b(104)50 2914 y(\014ts)p 177
+2914 V 32 w(mo)s(dify)p 485 2914 V 32 w(v)m(ector)p 758
+2914 V 35 w(len)259 b(53)50 3027 y(\014ts)p 177 3027
+V 32 w(mo)m(v)-5 b(abs)p 502 3027 V 33 w(hdu)480 b(33)50
+3140 y(\014ts)p 177 3140 V 32 w(mo)m(vnam)p 547 3140
+V 33 w(hdu)435 b(33)50 3253 y(\014ts)p 177 3253 V 32
+w(mo)m(vrel)p 476 3253 V 34 w(hdu)505 b(33)50 3366 y(\014ts)p
+177 3366 V 32 w(n)m(ull)p 358 3366 V 33 w(c)m(hec)m(k)564
+b(64)50 3479 y(\014ts)p 177 3479 V 32 w(op)s(en)p 399
+3479 V 32 w(data)d(30)50 3591 y(\014ts)p 177 3591 V 32
+w(op)s(en)p 399 3591 V 32 w(disk\014le)461 b(30)50 3704
+y(\014ts)p 177 3704 V 32 w(op)s(en)p 399 3704 V 32 w(\014le)621
+b(30)50 3817 y(\014ts)p 177 3817 V 32 w(op)s(en)p 399
+3817 V 32 w(image)506 b(30)50 3930 y(\014ts)p 177 3930
+V 32 w(op)s(en)p 399 3930 V 32 w(table)541 b(30)50 4043
+y(\014ts)p 177 4043 V 32 w(op)s(en)p 399 4043 V 32 w(group)509
+b(88)50 4156 y(\014ts)p 177 4156 V 32 w(op)s(en)p 399
+4156 V 32 w(mem)m(b)s(er)418 b(89)50 4269 y(\014ts)p
+177 4269 V 32 w(op)s(en)p 399 4269 V 32 w(mem\014le)429
+b(91)50 4382 y(\014ts)p 177 4382 V 32 w(parse)p 417 4382
+V 33 w(extn)m(um)420 b(93)50 4495 y(\014ts)p 177 4495
+V 32 w(parse)p 417 4495 V 33 w(input)p 663 4495 V 32
+w(\014lename)145 b(93)50 4608 y(\014ts)p 177 4608 V 32
+w(parse)p 417 4608 V 33 w(input)p 663 4608 V 32 w(url)361
+b(93)50 4721 y(\014ts)p 177 4721 V 32 w(parse)p 417 4721
+V 33 w(range)501 b(71)50 4833 y(\014ts)p 177 4833 V 32
+w(parse)p 417 4833 V 33 w(ro)s(otname)342 b(94)50 4946
+y(\014ts)p 177 4946 V 32 w(parse)p 417 4946 V 33 w(template)371
+b(67)50 5059 y(\014ts)p 177 5059 V 32 w(parse)p 417 5059
+V 33 w(v)-5 b(alue)514 b(64)50 5172 y(\014ts)p 177 5172
+V 32 w(pix)p 333 5172 V 33 w(to)p 446 5172 V 33 w(w)m(orld)469
+b(83)50 5285 y(\014ts)p 177 5285 V 32 w(read)p 381 5285
+V 33 w(2d)p 510 5285 V 33 w(TYP)384 b(110)50 5398 y(\014ts)p
+177 5398 V 32 w(read)p 381 5398 V 33 w(3d)p 510 5398
+V 33 w(TYP)g(110)50 5511 y(\014ts)p 177 5511 V 32 w(read)p
+381 5511 V 33 w(atblhdr)460 b(99)50 5624 y(\014ts)p 177
+5624 V 32 w(read)p 381 5624 V 33 w(btblhdr)454 b(99)50
+5737 y(\014ts)p 177 5737 V 32 w(read)p 381 5737 V 33
+w(card)582 b(36)50 5850 y(\014ts)p 177 5850 V 32 w(read)p
+381 5850 V 33 w(col)644 b(55)1374 543 y(\014ts)p 1501
+543 V 32 w(read)p 1705 543 V 33 w(col)p 1848 543 V 34
+w(bit)p 1993 543 V 639 w(116)1374 656 y(\014ts)p 1501
+656 V 32 w(read)p 1705 656 V 33 w(col)p 1848 656 V 34
+w(TYP)554 b(114)1374 769 y(\014ts)p 1501 769 V 32 w(read)p
+1705 769 V 33 w(coln)m(ull)680 b(55)1374 882 y(\014ts)p
+1501 882 V 32 w(read)p 1705 882 V 33 w(coln)m(ull)p 1997
+882 V 34 w(TYP)405 b(114)1374 995 y(\014ts)p 1501 995
+V 32 w(read)p 1705 995 V 33 w(descript)580 b(116)1374
+1107 y(\014ts)p 1501 1107 V 32 w(read)p 1705 1107 V 33
+w(descripts)544 b(116)1374 1220 y(\014ts)p 1501 1220
+V 32 w(read)p 1705 1220 V 33 w(errmsg)670 b(30)1374 1333
+y(\014ts)p 1501 1333 V 32 w(read)p 1705 1333 V 33 w(ext)816
+b(96)1374 1446 y(\014ts)p 1501 1446 V 32 w(read)p 1705
+1446 V 33 w(grppar)p 2002 1446 V 32 w(TYP)402 b(109)1374
+1559 y(\014ts)p 1501 1559 V 32 w(read)p 1705 1559 V 33
+w(img)748 b(109)1374 1672 y(\014ts)p 1501 1672 V 32 w(read)p
+1705 1672 V 33 w(img)p 1884 1672 V 33 w(co)s(ord)540
+b(83)1374 1785 y(\014ts)p 1501 1785 V 32 w(read)p 1705
+1785 V 33 w(img)p 1884 1785 V 33 w(TYP)519 b(109)1374
+1898 y(\014ts)p 1501 1898 V 32 w(read)p 1705 1898 V 33
+w(imghdr)655 b(99)1374 2011 y(\014ts)p 1501 2011 V 32
+w(read)p 1705 2011 V 33 w(imgn)m(ull)599 b(109)1374 2124
+y(\014ts)p 1501 2124 V 32 w(read)p 1705 2124 V 33 w(imgn)m(ull)p
+2033 2124 V 33 w(TYP)370 b(109)1374 2237 y(\014ts)p 1501
+2237 V 32 w(read)p 1705 2237 V 33 w(k)m(ey)806 b(36)1374
+2349 y(\014ts)p 1501 2349 V 32 w(read)p 1705 2349 V 33
+w(k)m(ey)p 1871 2349 V 33 w(longstr)455 b(103)1374 2462
+y(\014ts)p 1501 2462 V 32 w(read)p 1705 2462 V 33 w(k)m(ey)p
+1871 2462 V 33 w(triple)516 b(104)1374 2575 y(\014ts)p
+1501 2575 V 32 w(read)p 1705 2575 V 33 w(k)m(ey)p 1871
+2575 V 33 w(unit)611 b(37)1374 2688 y(\014ts)p 1501 2688
+V 32 w(read)p 1705 2688 V 33 w(k)m(ey)p 1871 2688 V 33
+w(TYP)532 b(103)1374 2801 y(\014ts)p 1501 2801 V 32 w(read)p
+1705 2801 V 33 w(k)m(eyn)755 b(36)1374 2914 y(\014ts)p
+1501 2914 V 32 w(read)p 1705 2914 V 33 w(k)m(eys)p 1907
+2914 V 33 w(TYP)496 b(103)1374 3027 y(\014ts)p 1501 3027
+V 32 w(read)p 1705 3027 V 33 w(k)m(eyw)m(ord)611 b(36)1374
+3140 y(\014ts)p 1501 3140 V 32 w(read)p 1705 3140 V 33
+w(pix)815 b(43)1374 3253 y(\014ts)p 1501 3253 V 32 w(read)p
+1705 3253 V 33 w(pixn)m(ull)666 b(43)1374 3366 y(\014ts)p
+1501 3366 V 32 w(read)p 1705 3366 V 33 w(record)691 b(36)1374
+3479 y(\014ts)p 1501 3479 V 32 w(read)p 1705 3479 V 33
+w(str)832 b(36)1374 3591 y(\014ts)p 1501 3591 V 32 w(read)p
+1705 3591 V 33 w(subset)p 1987 3591 V 32 w(TYP)250 b(110)32
+b(115)1374 3704 y(\014ts)p 1501 3704 V 32 w(read)p 1705
+3704 V 33 w(subsetn)m(ull)p 2136 3704 V 32 w(TYP)101
+b(110)32 b(115)1374 3817 y(\014ts)p 1501 3817 V 32 w(read)p
+1705 3817 V 33 w(tbl)p 1849 3817 V 33 w(co)s(ord)575
+b(83)1374 3930 y(\014ts)p 1501 3930 V 32 w(read)p 1705
+3930 V 33 w(tblb)m(ytes)h(112)1374 4043 y(\014ts)p 1501
+4043 V 32 w(read)p 1705 4043 V 33 w(tdim)752 b(51)1374
+4156 y(\014ts)p 1501 4156 V 32 w(read)p 1705 4156 V 33
+w(w)m(cstab)669 b(82)1374 4269 y(\014ts)p 1501 4269 V
+32 w(rebin)p 1736 4269 V 32 w(w)m(cs)770 b(59)1374 4382
+y(\014ts)p 1501 4382 V 32 w(remo)m(v)m(e)p 1812 4382
+V 34 w(group)603 b(87)1374 4495 y(\014ts)p 1501 4495
+V 32 w(remo)m(v)m(e)p 1812 4495 V 34 w(mem)m(b)s(er)512
+b(90)1374 4608 y(\014ts)p 1501 4608 V 32 w(reop)s(en)p
+1799 4608 V 32 w(\014le)730 b(92)1374 4721 y(\014ts)p
+1501 4721 V 32 w(rep)s(ort)p 1779 4721 V 32 w(error)673
+b(30)1374 4833 y(\014ts)p 1501 4833 V 32 w(resize)p 1750
+4833 V 34 w(img)747 b(96)1374 4946 y(\014ts)p 1501 4946
+V 32 w(rms)p 1681 4946 V 32 w(\015oat)788 b(71)1374 5059
+y(\014ts)p 1501 5059 V 32 w(rms)p 1681 5059 V 32 w(short)761
+b(71)1374 5172 y(\014ts)p 1501 5172 V 32 w(select)p 1749
+5172 V 35 w(ro)m(ws)713 b(56)1374 5285 y(\014ts)p 1501
+5285 V 32 w(set)p 1644 5285 V 34 w(atbln)m(ull)649 b(106)1374
+5398 y(\014ts)p 1501 5398 V 32 w(set)p 1644 5398 V 34
+w(bscale)717 b(106)1374 5511 y(\014ts)p 1501 5511 V 32
+w(set)p 1644 5511 V 34 w(btbln)m(ull)643 b(106)1374 5624
+y(\014ts)p 1501 5624 V 32 w(set)p 1644 5624 V 34 w(compression)p
+2159 5624 V 32 w(t)m(yp)s(e)312 b(46)1374 5737 y(\014ts)p
+1501 5737 V 32 w(set)p 1644 5737 V 34 w(hdrsize)720 b(97)1374
+5850 y(\014ts)p 1501 5850 V 32 w(set)p 1644 5850 V 34
+w(hdustruc)648 b(97)2883 543 y(\014ts)p 3010 543 V 33
+w(set)p 3154 543 V 33 w(imgn)m(ull)408 b(106)2883 656
+y(\014ts)p 3010 656 V 33 w(set)p 3154 656 V 33 w(noise)p
+3384 656 V 33 w(bits)372 b(46)2883 769 y(\014ts)p 3010
+769 V 33 w(set)p 3154 769 V 33 w(tile)p 3312 769 V 34
+w(dim)438 b(46)2883 882 y(\014ts)p 3010 882 V 33 w(set)p
+3154 882 V 33 w(tscale)482 b(106)2883 995 y(\014ts)p
+3010 995 V 33 w(split)p 3215 995 V 32 w(names)441 b(63)2883
+1107 y(\014ts)p 3010 1107 V 33 w(str2date)570 b(61)2883
+1220 y(\014ts)p 3010 1220 V 33 w(str2time)565 b(61)2883
+1333 y(\014ts)p 3010 1333 V 33 w(test)p 3189 1333 V 33
+w(expr)539 b(57)2883 1446 y(\014ts)p 3010 1446 V 33 w(test)p
+3189 1446 V 33 w(heap)481 b(111)2883 1559 y(\014ts)p
+3010 1559 V 33 w(test)p 3189 1559 V 33 w(k)m(eyw)m(ord)386
+b(63)2883 1672 y(\014ts)p 3010 1672 V 33 w(test)p 3189
+1672 V 33 w(record)466 b(63)2883 1785 y(\014ts)p 3010
+1785 V 33 w(time2str)565 b(61)2883 1898 y(\014ts)p 3010
+1898 V 33 w(transfer)p 3350 1898 V 32 w(mem)m(b)s(er)235
+b(89)2883 2011 y(\014ts)p 3010 2011 V 33 w(translate)p
+3391 2011 V 33 w(k)m(eyw)m(ord)184 b(69)2883 2124 y(\014ts)p
+3010 2124 V 33 w(up)s(date)p 3319 2124 V 31 w(card)414
+b(39)2883 2237 y(\014ts)p 3010 2237 V 33 w(up)s(date)p
+3319 2237 V 31 w(c)m(hksum)287 b(60)2883 2349 y(\014ts)p
+3010 2349 V 33 w(up)s(date)p 3319 2349 V 31 w(k)m(ey)453
+b(38)2883 2462 y(\014ts)p 3010 2462 V 33 w(up)s(date)p
+3319 2462 V 31 w(k)m(ey)p 3483 2462 V 34 w(longstr)100
+b(105)2883 2575 y(\014ts)p 3010 2575 V 33 w(up)s(date)p
+3319 2575 V 31 w(k)m(ey)p 3483 2575 V 34 w(n)m(ull)270
+b(38)2883 2688 y(\014ts)p 3010 2688 V 33 w(up)s(date)p
+3319 2688 V 31 w(k)m(ey)p 3483 2688 V 34 w(TYP)177 b(105)2883
+2801 y(\014ts)p 3010 2801 V 33 w(upp)s(ercase)500 b(63)2883
+2914 y(\014ts)p 3010 2914 V 33 w(url)p 3155 2914 V 32
+w(t)m(yp)s(e)575 b(33)2883 3027 y(\014ts)p 3010 3027
+V 33 w(v)m(erify)p 3265 3027 V 33 w(c)m(hksum)339 b(60)2883
+3140 y(\014ts)p 3010 3140 V 33 w(v)m(erify)p 3265 3140
+V 33 w(group)410 b(88)2883 3253 y(\014ts)p 3010 3253
+V 33 w(w)m(orld)p 3263 3253 V 32 w(to)p 3375 3253 V 34
+w(pix)403 b(83)2883 3366 y(\014ts)p 3010 3366 V 33 w(write)p
+3245 3366 V 33 w(2d)p 3374 3366 V 32 w(TYP)288 b(109)2883
+3479 y(\014ts)p 3010 3479 V 33 w(write)p 3245 3479 V
+33 w(3d)p 3374 3479 V 32 w(TYP)g(109)2883 3591 y(\014ts)p
+3010 3591 V 33 w(write)p 3245 3591 V 33 w(atblhdr)364
+b(98)2883 3704 y(\014ts)p 3010 3704 V 33 w(write)p 3245
+3704 V 33 w(btblhdr)358 b(99)2883 3817 y(\014ts)p 3010
+3817 V 33 w(write)p 3245 3817 V 33 w(c)m(hksum)h(60)2883
+3930 y(\014ts)p 3010 3930 V 33 w(write)p 3245 3930 V
+33 w(col)548 b(54)2883 4043 y(\014ts)p 3010 4043 V 33
+w(write)p 3245 4043 V 33 w(col)p 3388 4043 V 33 w(bit)358
+b(113)2883 4156 y(\014ts)p 3010 4156 V 33 w(write)p 3245
+4156 V 33 w(col)p 3388 4156 V 33 w(TYP)273 b(112)2883
+4269 y(\014ts)p 3010 4269 V 33 w(write)p 3245 4269 V
+33 w(col)p 3388 4269 V 33 w(n)m(ull)366 b(54)2883 4382
+y(\014ts)p 3010 4382 V 33 w(write)p 3245 4382 V 33 w(coln)m(ull)399
+b(54)2883 4495 y(\014ts)p 3010 4495 V 33 w(write)p 3245
+4495 V 33 w(coln)m(ull)p 3537 4495 V 33 w(TYP)124 b(112)2883
+4608 y(\014ts)p 3010 4608 V 33 w(write)p 3245 4608 V
+33 w(commen)m(t)298 b(38)2883 4721 y(\014ts)p 3010 4721
+V 33 w(write)p 3245 4721 V 33 w(date)487 b(38)2883 4833
+y(\014ts)p 3010 4833 V 33 w(write)p 3245 4833 V 33 w(descript)298
+b(113)2883 4946 y(\014ts)p 3010 4946 V 33 w(write)p 3245
+4946 V 33 w(errmark)341 b(30)2883 5059 y(\014ts)p 3010
+5059 V 33 w(write)p 3245 5059 V 33 w(errmsg)389 b(62)2883
+5172 y(\014ts)p 3010 5172 V 33 w(write)p 3245 5172 V
+33 w(ext)535 b(96)2883 5285 y(\014ts)p 3010 5285 V 33
+w(write)p 3245 5285 V 33 w(exthdr)397 b(98)2883 5398
+y(\014ts)p 3010 5398 V 33 w(write)p 3245 5398 V 33 w(grphdr)388
+b(98)2883 5511 y(\014ts)p 3010 5511 V 33 w(write)p 3245
+5511 V 33 w(grppar)p 3542 5511 V 31 w(TYP)121 b(108)2883
+5624 y(\014ts)p 3010 5624 V 33 w(write)p 3245 5624 V
+33 w(hdu)505 b(34)2883 5737 y(\014ts)p 3010 5737 V 33
+w(write)p 3245 5737 V 33 w(history)382 b(38)2883 5850
+y(\014ts)p 3010 5850 V 33 w(write)p 3245 5850 V 33 w(img)466
+b(108)p eop end
+%%Page: 167 175
+TeXDict begin 167 174 bop 3764 299 a Fj(167)50 543 y(\014ts)p
+177 543 28 4 v 32 w(write)p 411 543 V 33 w(img)p 590
+543 V 33 w(n)m(ull)300 b(108)50 656 y(\014ts)p 177 656
+V 32 w(write)p 411 656 V 33 w(img)p 590 656 V 33 w(TYP)253
+b(108)50 769 y(\014ts)p 177 769 V 32 w(write)p 411 769
+V 33 w(imghdr)389 b(98)50 882 y(\014ts)p 177 882 V 32
+w(write)p 411 882 V 33 w(imgn)m(ull)333 b(108)50 995
+y(\014ts)p 177 995 V 32 w(write)p 411 995 V 33 w(imgn)m(ull)p
+739 995 V 33 w(TYP)104 b(108)50 1107 y(\014ts)p 177 1107
+V 32 w(write)p 411 1107 V 33 w(k)m(ey)540 b(38)50 1220
+y(\014ts)p 177 1220 V 32 w(write)p 411 1220 V 33 w(k)m(ey)p
+577 1220 V 34 w(longstr)188 b(100)50 1333 y(\014ts)p
+177 1333 V 32 w(write)p 411 1333 V 33 w(k)m(ey)p 577
+1333 V 34 w(longw)m(arn)100 b(100)50 1446 y(\014ts)p
+177 1446 V 32 w(write)p 411 1446 V 33 w(k)m(ey)p 577
+1446 V 34 w(n)m(ull)357 b(38)50 1559 y(\014ts)p 177 1559
+V 32 w(write)p 411 1559 V 33 w(k)m(ey)p 577 1559 V 34
+w(template)114 b(101)50 1672 y(\014ts)p 177 1672 V 32
+w(write)p 411 1672 V 33 w(k)m(ey)p 577 1672 V 34 w(triple)249
+b(101)50 1785 y(\014ts)p 177 1785 V 32 w(write)p 411
+1785 V 33 w(k)m(ey)p 577 1785 V 34 w(unit)344 b(39)50
+1898 y(\014ts)p 177 1898 V 32 w(write)p 411 1898 V 33
+w(k)m(ey)p 577 1898 V 34 w(TYP)265 b(100)50 2011 y(\014ts)p
+177 2011 V 32 w(write)p 411 2011 V 33 w(k)m(eys)p 613
+2011 V 34 w(TYP)229 b(101)50 2124 y(\014ts)p 177 2124
+V 32 w(write)p 411 2124 V 33 w(k)m(eys)p 613 2124 V 34
+w(histo)278 b(59)50 2237 y(\014ts)p 177 2237 V 32 w(write)p
+411 2237 V 33 w(n)m(ull)p 593 2237 V 33 w(img)345 b(43)50
+2349 y(\014ts)p 177 2349 V 32 w(write)p 411 2349 V 33
+w(n)m(ullro)m(ws)f(54)50 2462 y(\014ts)p 177 2462 V 32
+w(write)p 411 2462 V 33 w(pix)549 b(42)50 2575 y(\014ts)p
+177 2575 V 32 w(write)p 411 2575 V 33 w(pixn)m(ull)400
+b(42)50 2688 y(\014ts)p 177 2688 V 32 w(write)p 411 2688
+V 33 w(record)425 b(39)50 2801 y(\014ts)p 177 2801 V
+32 w(write)p 411 2801 V 33 w(subset)f(42)50 2914 y(\014ts)p
+177 2914 V 32 w(write)p 411 2914 V 33 w(subset)p 693
+2914 V 32 w(TYP)151 b(109)50 3027 y(\014ts)p 177 3027
+V 32 w(write)p 411 3027 V 33 w(tblb)m(ytes)310 b(112)50
+3140 y(\014ts)p 177 3140 V 32 w(write)p 411 3140 V 33
+w(tdim)486 b(51)50 3253 y(\014ts)p 177 3253 V 32 w(write)p
+411 3253 V 33 w(theap)406 b(111)p eop end
+%%Page: 168 176
+TeXDict begin 168 175 bop 0 299 a Fj(168)2084 b Fh(APPENDIX)31
+b(A.)61 b(INDEX)31 b(OF)f(R)m(OUTINES)50 543 y Fj(\013asfm)276
+b(66)50 656 y(\013bnfm)255 b(66)50 769 y(\013calc)311
+b(57)50 882 y(\013calc)p 258 882 28 4 v 34 w(rng)145
+b(57)50 995 y(\013clos)315 b(33)50 1107 y(\013cmph)197
+b(111)50 1220 y(\013cmps)258 b(63)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)302 b(53)50 1785 y(\013cp)s(dt)281
+b(96)50 1898 y(\013cp\015)319 b(34)50 2011 y(\013cphd)268
+b(34)50 2124 y(\013cpimg)224 b(44)50 2237 y(\013cpky)k(101)50
+2349 y(\013cprw)268 b(53)50 2462 y(\013crhd)283 b(95)50
+2575 y(\013crim)h(41)50 2688 y(\013cro)m(w)277 b(56)50
+2801 y(\013crtb)299 b(49)50 2914 y(\013dcol)h(52)50 3027
+y(\013delt)310 b(33)50 3140 y(\013dhdu)257 b(35)50 3253
+y(\013dk)m(ey)277 b(39)50 3366 y(\013dkinit)226 b(32)50
+3479 y(\013dk)m(op)s(en)175 b(30)50 3591 y(\013dopn)263
+b(30)50 3704 y(\013drec)294 b(39)50 3817 y(\013dro)m(w)266
+b(52)50 3930 y(\013drrg)293 b(52)50 4043 y(\013drws)272
+b(52)50 4156 y(\013dstr)303 b(39)50 4269 y(\013dsum)247
+b(61)50 4382 y(\013dt2s)294 b(61)50 4495 y(\013dtdm)248
+b(51)50 4608 y(\013dt)m(yp)279 b(64)50 4721 y(\013eqt)m(y)293
+b(50)50 4833 y(\013esum)258 b(61)50 4946 y(\013exest)k(94)50
+5059 y(\013extn)287 b(93)50 5172 y(\013\013rw)306 b(56)50
+5285 y(\013\015md)283 b(33)50 5398 y(\013\015nm)g(33)50
+5511 y(\013\015sh)323 b(94)50 5624 y(\013\015us)g(94)50
+5737 y(\013free)271 b(103)50 5850 y(\013fro)m(w)289 b(56)785
+543 y(\013g2d)p 984 543 V 191 w(110)785 656 y(\013g3d)p
+984 656 V 191 w(110)785 769 y(\013gab)s(c)193 b(66)785
+882 y(\013gacl)177 b(110)785 995 y(\013gb)s(cl)168 b(110)785
+1107 y(\013gcdw)175 b(51)785 1220 y(\013gcf)264 b(55)785
+1333 y(\013gcf)p 956 1333 V 219 w(114)785 1446 y(\013gc)m(ks)211
+b(60)785 1559 y(\013gcnn)190 b(49)785 1672 y(\013gcno)196
+b(49)785 1785 y(\013gcrd)205 b(36)785 1898 y(\013gcv)244
+b(55)785 2011 y(\013gcv)p 976 2011 V 199 w(114)785 2124
+y(\013gcx)199 b(116)785 2237 y(\013gdes)160 b(116)785
+2349 y(\013gdess)124 b(116)785 2462 y(\013gerr)220 b(29)785
+2575 y(\013gextn)158 b(96)785 2688 y(\013ggp)p 984 2688
+V 191 w(109)785 2801 y(\013ghad)185 b(95)785 2914 y(\013gh)m(bn)d(99)
+785 3027 y(\013ghdn)d(34)785 3140 y(\013ghdt)195 b(34)785
+3253 y(\013ghpr)f(99)785 3366 y(\013ghps)g(97)785 3479
+y(\013ghsp)g(35)785 3591 y(\013gh)m(tb)k(99)785 3704
+y(\013gics)231 b(83)785 3817 y(\013gidm)180 b(41)785
+3930 y(\013gidt)221 b(40)785 4043 y(\013giet)232 b(40)785
+4156 y(\013gipr)220 b(41)785 4269 y(\013gisz)231 b(41)785
+4382 y(\013gk)m(cl)222 b(65)785 4495 y(\013gk)m(ey)199
+b(36)785 4608 y(\013gkls)178 b(103)785 4721 y(\013gkn)p
+987 4721 V 188 w(103)785 4833 y(\013gknm)157 b(64)785
+4946 y(\013gky)236 b(36)785 5059 y(\013gkyn)185 b(36)785
+5172 y(\013gkyt)156 b(104)785 5285 y(\013gky)p 984 5285
+V 191 w(103)785 5398 y(\013gmcp)165 b(89)785 5511 y(\013gmng)160
+b(89)785 5624 y(\013gmop)g(89)785 5737 y(\013gmrm)144
+b(90)785 5850 y(\013gmsg)175 b(30)1436 543 y(\013gm)m(tf)368
+b(89)1436 656 y(\013gncl)388 b(49)1436 769 y(\013gnrw)351
+b(49)1436 882 y(\013gnxk)357 b(37)1436 995 y(\013gpf)380
+b(109)1436 1107 y(\013gpf)p 1618 1107 V 380 w(109)1436
+1220 y(\013gp)m(v)363 b(109)1436 1333 y(\013gp)m(v)p
+1635 1333 V 363 w(109)1436 1446 y(\013gp)m(xv)d(43)1436
+1559 y(\013gp)m(xf)380 b(43)1436 1672 y(\013grec)388
+b(36)1436 1785 y(\013grsz)347 b(111)1436 1898 y(\013gsdt)382
+b(61)1436 2011 y(\013gsf)p 1603 2011 V 228 w(110)32 b(115)1436
+2124 y(\013gstm)357 b(61)1436 2237 y(\013gstr)397 b(36)1436
+2349 y(\013gsv)p 1623 2349 V 208 w(110)32 b(115)1436
+2462 y(\013gtam)348 b(88)1436 2575 y(\013gtbb)322 b(112)1436
+2688 y(\013gtc)m(h)381 b(86)1436 2801 y(\013gtcl)404
+b(50)1436 2914 y(\013gtcm)353 b(87)1436 3027 y(\013gtcp)378
+b(87)1436 3140 y(\013gtcr)393 b(86)1436 3253 y(\013gtcs)g(83)1436
+3366 y(\013gtdm)342 b(51)1436 3479 y(\013gthd)367 b(67)1436
+3591 y(\013gtis)408 b(86)1436 3704 y(\013gtmg)348 b(87)1436
+3817 y(\013gtnm)342 b(88)1436 3930 y(\013gtop)373 b(88)1436
+4043 y(\013gtrm)357 b(87)1436 4156 y(\013gtvf)393 b(88)1436
+4269 y(\013gun)m(t)370 b(37)1436 4382 y(\013hdef)379
+b(97)1436 4495 y(\016bin)399 b(96)1436 4608 y(\016cls)425
+b(52)1436 4721 y(\016col)416 b(52)1436 4833 y(\016\014le)410
+b(93)1436 4946 y(\016img)380 b(95)1436 5059 y(\016kls)372
+b(102)1436 5172 y(\016kyu)334 b(102)1436 5285 y(\016ky)p
+1613 5285 V 385 w(102)1436 5398 y(\016mem)g(92)1436 5511
+y(\016nit)415 b(32)1436 5624 y(\016n)m(tt)m(yp)312 b(65)1436
+5737 y(\016opn)379 b(30)1436 5850 y(\016rec)365 b(102)2259
+543 y(\016ro)m(w)226 b(52)2259 656 y(\016tab)239 b(96)2259
+769 y(\016ter)259 b(79)2259 882 y(\016url)f(93)2259 995
+y(\013k)m(eyn)209 b(64)2259 1107 y(\013mahd)170 b(33)2259
+1220 y(\013mcom)156 b(39)2259 1333 y(\013mcrd)144 b(104)2259
+1446 y(\013mkls)162 b(104)2259 1559 y(\013mkyu)124 b(105)2259
+1672 y(\013mky)p 2489 1672 V 175 w(104)2259 1785 y(\013mnam)145
+b(39)2259 1898 y(\013mnhd)164 b(33)2259 2011 y(\013mrec)155
+b(104)2259 2124 y(\013mrhd)179 b(33)2259 2237 y(\013m)m(v)m(ec)195
+b(53)2259 2349 y(\013nc)m(hk)206 b(64)2259 2462 y(\013nk)m(ey)j(64)2259
+2575 y(\013omem)156 b(91)2259 2688 y(\013op)s(en)203
+b(30)2259 2801 y(\013p2d)p 2464 2801 V 200 w(109)2259
+2914 y(\013p3d)p 2464 2914 V 200 w(109)2259 3027 y(\013p)s(c)m(ks)218
+b(60)2259 3140 y(\013p)s(cl)274 b(54)2259 3253 y(\013p)s(cls)192
+b(112)2259 3366 y(\013p)s(cl)p 2436 3366 V 228 w(113)2259
+3479 y(\013p)s(clu)223 b(54)2259 3591 y(\013p)s(cn)248
+b(54)2259 3704 y(\013p)s(cn)p 2462 3704 V 202 w(112)2259
+3817 y(\013p)s(com)178 b(38)2259 3930 y(\013p)s(dat)208
+b(38)2259 4043 y(\013p)s(des)166 b(113)2259 4156 y(\013p)s(extn)f(96)
+2259 4269 y(\013pgp)p 2464 4269 V 200 w(108)2259 4382
+y(\013ph)m(bn)192 b(99)2259 4495 y(\013phext)168 b(98)2259
+4608 y(\013phis)230 b(38)2259 4721 y(\013phpr)204 b(98)2259
+4833 y(\013phps)g(98)2259 4946 y(\013ph)m(tb)k(98)2259
+5059 y(\013pkls)187 b(100)2259 5172 y(\013pkn)p 2467
+5172 V 197 w(101)2259 5285 y(\013pktp)162 b(101)2259
+5398 y(\013pky)246 b(38)2259 5511 y(\013pkyt)165 b(101)2259
+5624 y(\013pkyu)195 b(38)2259 5737 y(\013pky)p 2464 5737
+V 200 w(100)2259 5850 y(\013plsw)169 b(100)2926 543 y(\013pmrk)199
+b(30)2926 656 y(\013pmsg)j(62)2926 769 y(\013pn)m(ul)190
+b(106)2926 882 y(\013ppn)212 b(108)2926 995 y(\013ppn)p
+3137 995 V 212 w(108)2926 1107 y(\013ppr)227 b(108)2926
+1220 y(\013pprn)221 b(43)2926 1333 y(\013ppru)176 b(108)2926
+1446 y(\013ppr)p 3122 1446 V 227 w(108)2926 1559 y(\013pp)m(x)263
+b(42)2926 1672 y(\013pp)m(xn)212 b(42)2926 1785 y(\013prec)243
+b(39)2926 1898 y(\013prwu)206 b(54)2926 2011 y(\013pscl)213
+b(106)2926 2124 y(\013pss)287 b(42)2926 2237 y(\013pss)p
+3107 2237 V 242 w(109)2926 2349 y(\013psv)m(c)238 b(64)2926
+2462 y(\013ptbb)177 b(112)2926 2575 y(\013ptdm)197 b(51)2926
+2688 y(\013pthp)177 b(111)2926 2801 y(\013pun)m(t)225
+b(39)2926 2914 y(\013rdef)255 b(97)2926 3027 y(\013reop)s(en)144
+b(92)2926 3140 y(\013rprt)252 b(30)2926 3253 y(\013rsim)237
+b(96)2926 3366 y(\013rtnm)212 b(94)2926 3479 y(\013rwrg)227
+b(71)2926 3591 y(\013s2dt)243 b(61)2926 3704 y(\013s2tm)218
+b(61)2926 3817 y(\013sn)m(ul)205 b(106)2926 3930 y(\013sro)m(w)230
+b(56)2926 4043 y(\013texp)236 b(57)2926 4156 y(\013thdu)222
+b(34)2926 4269 y(\013theap)143 b(111)2926 4382 y(\013tk)m(ey)242
+b(63)2926 4495 y(\013tm2s)218 b(61)2926 4608 y(\013tn)m(ul)206
+b(106)2926 4721 y(\013topn)228 b(30)2926 4833 y(\013tplt)264
+b(92)2926 4946 y(\013trec)259 b(63)2926 5059 y(\013tscl)229
+b(106)2926 5172 y(\013ucrd)j(39)2926 5285 y(\013ukls)205
+b(105)2926 5398 y(\013uky)263 b(38)2926 5511 y(\013ukyu)212
+b(38)2926 5624 y(\013uky)p 3131 5624 V 218 w(105)2926
+5737 y(\013up)s(c)m(h)217 b(63)2926 5850 y(\013up)s(c)m(k)j(60)p
+eop end
+%%Page: 169 177
+TeXDict begin 169 176 bop 3764 299 a Fj(169)50 543 y(\013urlt)205
+b(33)50 656 y(\013v)m(c)m(ks)186 b(60)50 769 y(\013v)m(ers)195
+b(62)50 882 y(\013wldp)159 b(83)50 995 y(\013wrhdu)97
+b(34)50 1107 y(\013xyp)m(x)160 b(83)p eop end
+%%Page: 170 178
+TeXDict begin 170 177 bop 0 299 a Fj(170)2084 b Fh(APPENDIX)31
+b(A.)61 b(INDEX)31 b(OF)f(R)m(OUTINES)p eop end
+%%Page: 171 179
+TeXDict begin 171 178 bop 0 1225 a Fg(App)5 b(endix)64
+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(HCOMPRESS_1,)g(or)i(PLIO_1)0 5454 y(coordtype-)e(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(171)p eop end
+%%Page: 172 180
+TeXDict begin 172 179 bop 0 299 a Fj(172)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
+end
+%%Page: 173 181
+TeXDict begin 173 180 bop 3764 299 a Fj(173)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(HDU)g(type:)f(IMAGE_HDU)g(\(0\),)g(ASCII_TBL)f(\(1\),)i
+(BINARY_TBL)e(\(2\),)i(ANY_HDU)f(\(-1\))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 end
+%%Page: 174 182
+TeXDict begin 174 181 bop 0 299 a Fj(174)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(nbytes)142
+b(-)47 b(number)f(of)h(bytes)g(or)g(characters)e(to)i(read)g(or)g
+(write)0 2475 y(nchars)142 b(-)47 b(number)f(of)h(characters)e(to)i
+(read)g(or)g(write)0 2588 y(nelements-)e(number)h(of)h(data)g(elements)
+e(to)j(read)e(or)h(write)0 2700 y(newfptr)94 b(-)47 b(returned)f
+(pointer)f(to)j(the)e(reopened)g(file)0 2813 y(newveclen-)f(new)i
+(value)f(for)h(the)g(column)f(vector)g(repeat)g(parameter)0
+2926 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 3039 y(nfound)142 b(-)47 b(number)f(of)h
+(keywords)f(found)g(\(highest)g(keyword)g(number\))0
+3152 y(nkeys)190 b(-)47 b(number)f(of)h(keywords)f(in)h(the)g(sequence)
+0 3265 y(ninc)238 b(-)47 b(number)f(of)h(names)g(in)g(the)g(inclusion)e
+(list)0 3378 y(nmembers)h(-)h(Number)f(of)h(grouping)f(table)g(members)
+g(\(NAXIS2)g(value\).)0 3491 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
+3604 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 3717 y(noisebits-)e
+(number)h(of)h(bits)g(to)g(ignore)f(when)h(compressing)e(floating)g
+(point)h(images)0 3830 y(nrows)190 b(-)47 b(number)f(of)h(rows)g(in)g
+(the)g(table)0 3942 y(nstart)142 b(-)47 b(first)f(integer)g(value)0
+4055 y(nullarray-)f(set)i(to)g(TRUE)g(\(=1\))f(if)i(corresponding)c
+(data)i(element)g(is)h(undefined)0 4168 y(nulval)142
+b(-)47 b(numerical)e(value)i(to)g(represent)e(undefined)g(pixels)0
+4281 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 4394 y(numval)142
+b(-)47 b(numerical)e(data)i(value,)f(of)h(the)g(appropriate)e(data)h
+(type)0 4507 y(offset)142 b(-)47 b(byte)g(offset)f(in)h(the)g(heap)f
+(or)i(data)e(unit)h(to)g(the)g(first)f(element)g(of)h(the)g(vector)0
+4620 y(openfptr)f(-)h(pointer)f(to)h(a)g(currently)f(open)g(FITS)h
+(file)0 4733 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
+4846 y(descriptor)0 4959 y(outcolnum-)f(output)h(column)g(number;)g
+(range)g(=)i(1)f(to)g(TFIELDS)f(+)i(1)0 5072 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 5185 y(to)h(opening)f(the)h
+(file)0 5297 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
+5410 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 5523 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 5636 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)p eop end
+%%Page: 175 183
+TeXDict begin 175 182 bop 3764 299 a Fj(175)0 555 y Fe(rmopt)190
+b(-)47 b(grouping)f(table)g(remove)g(option)g(parameter.)f(Allowed)h
+(values)g(are:)525 668 y(OPT_RM_GPT,)f(OPT_RM_ENTRY,)f(OPT_RM_MBR,)h
+(and)i(OPT_RM_ALL.)0 781 y(rootname)f(-)h(root)g(filename,)e(minus)h
+(any)h(extension)e(or)j(filtering)d(specifications)0
+894 y(rot)286 b(-)47 b(celestial)e(coordinate)g(rotation)h(angle)g
+(\(degrees\))0 1007 y(rowlen)142 b(-)47 b(length)f(of)h(a)h(table)e
+(row,)h(in)g(characters)e(or)i(bytes)0 1120 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 1233 y(rownum)142 b(-)47 b(number)f(of)h(the)g(row)g
+(\(first)f(row)h(=)h(1\))0 1346 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 1458
+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 1571 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 1684 y(second)142 b(-)47 b(second)f(within)g
+(minute)g(\(0)h(-)h(60.9999999999\))c(\(leap)i(second!\))0
+1797 y(section)94 b(-)47 b(section)f(of)h(image)f(to)i(be)f(copied)f
+(\(e.g.)g(21:80,101:200\))0 1910 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 2023 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
+2136 y(status)142 b(-)47 b(returned)f(error)g(status)g(code)h(\(0)g(=)g
+(OK\))0 2249 y(sum)286 b(-)47 b(32)g(bit)g(unsigned)f(checksum)f(value)
+0 2362 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
+2475 y(tdisp)190 b(-)47 b(Fortran)f(style)g(display)g(format)g(for)h
+(the)g(table)f(column)0 2588 y(tdimstr)94 b(-)47 b(the)g(value)f(of)h
+(the)g(TDIMn)g(keyword)0 2700 y(templt)142 b(-)47 b(template)f(string)g
+(used)g(in)h(comparison)e(\(null-terminated\))0 2813
+y(tfields)94 b(-)47 b(number)f(of)h(fields)f(\(columns\))g(in)h(the)g
+(table)0 2926 y(tfopt)190 b(-)47 b(grouping)f(table)g(member)g
+(transfer)g(option)g(parameter.)f(Allowed)g(values)i(are:)525
+3039 y(OPT_MCP_ADD,)d(and)j(OPT_MCP_MOV.)0 3152 y(tform)190
+b(-)47 b(format)f(of)h(the)g(column)f(\(null-terminated\);)d(allowed)j
+(values)g(are:)525 3265 y(ASCII)g(tables:)94 b(Iw,)47
+b(Aw,)g(Fww.dd,)f(Eww.dd,)f(or)j(Dww.dd)525 3378 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
+3491 y(where)f('w'=width)g(of)h(the)g(field,)f('d'=no.)g(of)h
+(decimals,)e('r'=repeat)g(count.)525 3604 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 3717 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
+3830 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 3942 y(16-bit)f(and)h(unsigned)f
+(32-bit)g(integer,)f(respectively.)0 4168 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 4281 y(relative)f(to)h(the)g(beginning)e(of)i(the)g
+(binary)f(table)g(data)0 4394 y(tilesize)g(-)h(array)f(of)i(length)e
+(NAXIS)g(that)h(specifies)e(the)i(dimensions)e(of)525
+4507 y(the)i(image)f(compression)f(tiles)0 4620 y(ttype)190
+b(-)47 b(label)f(or)i(name)e(for)h(table)f(column)h
+(\(null-terminated\))0 4733 y(tunit)190 b(-)47 b(physical)f(unit)g(for)
+h(table)f(column)h(\(null-terminated\))0 4846 y(typechar)f(-)h
+(symbolic)f(code)g(of)h(the)g(table)g(column)f(data)g(type)0
+4959 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 5072 y(the)i(value)f(indicates)g(a)h
+(variable)f(length)g(array)g(column.)764 5185 y(Datatype)618
+b(typecode)189 b(Mnemonic)764 5297 y(bit,)46 b(X)907
+b(1)381 b(TBIT)764 5410 y(byte,)46 b(B)811 b(11)381 b(TBYTE)764
+5523 y(logical,)45 b(L)668 b(14)381 b(TLOGICAL)764 5636
+y(ASCII)46 b(character,)f(A)286 b(16)381 b(TSTRING)p
+eop end
+%%Page: 176 184
+TeXDict begin 176 183 bop 0 299 a Fj(176)1822 b Fh(APPENDIX)31
+b(B.)61 b(P)-8 b(ARAMETER)30 b(DEFINITIONS)764 555 y
+Fe(short)46 b(integer,)g(I)381 b(21)g(TSHORT)764 668
+y(integer,)45 b(J)668 b(41)381 b(TINT32BIT)46 b(\(same)g(as)h(TLONG\))
+764 781 y(long)f(long)h(integer,)e(K)191 b(81)381 b(TLONGLONG)764
+894 y(real,)46 b(E)811 b(42)381 b(TFLOAT)764 1007 y(double)46
+b(precision,)f(D)238 b(82)381 b(TDOUBLE)764 1120 y(complex,)45
+b(C)668 b(83)381 b(TCOMPLEX)764 1233 y(double)46 b(complex,)f(M)286
+b(163)381 b(TDBLCOMPLEX)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 end
+%%Page: 177 185
+TeXDict begin 177 184 bop 0 1225 a Fg(App)5 b(endix)64
+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)h(table)g(lists)g(all)g(the)f(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)h(mnemonics)e
+(\(de\014ned)g(in)h(the)g(\014le)g(\014tsio.h\))h(rather)e(than)h(the)g
+(actual)h(in)m(teger)h(status)0 2406 y(v)-5 b(alues)31
+b(to)g(impro)m(v)m(e)g(the)g(readabilit)m(y)g(of)g(their)f(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(177)p eop end
+%%Page: 178 186
+TeXDict begin 178 185 bop 0 299 a Fj(178)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_INDEX_KEY)235 b(206)190
+b(illegal)46 b(indexed)g(keyword)f(name)i(\(e.g.)f('TFORM1000'\))48
+2023 y(BAD_KEYCHAR)331 b(207)190 b(illegal)46 b(character)f(in)i
+(keyword)f(name)h(or)g(card)48 2136 y(BAD_ORDER)427 b(208)190
+b(required)45 b(keywords)h(out)h(of)g(order)48 2249 y(NOT_POS_INT)331
+b(209)190 b(keyword)46 b(value)g(is)h(not)g(a)h(positive)d(integer)48
+2362 y(NO_END)571 b(210)190 b(couldn't)45 b(find)i(END)g(keyword)48
+2475 y(BAD_BITPIX)379 b(211)190 b(illegal)46 b(BITPIX)g(keyword)g
+(value)48 2588 y(BAD_NAXIS)427 b(212)190 b(illegal)46
+b(NAXIS)g(keyword)g(value)48 2700 y(BAD_NAXES)427 b(213)190
+b(illegal)46 b(NAXISn)g(keyword)g(value)48 2813 y(BAD_PCOUNT)379
+b(214)190 b(illegal)46 b(PCOUNT)g(keyword)g(value)48
+2926 y(BAD_GCOUNT)379 b(215)190 b(illegal)46 b(GCOUNT)g(keyword)g
+(value)48 3039 y(BAD_TFIELDS)331 b(216)190 b(illegal)46
+b(TFIELDS)g(keyword)f(value)48 3152 y(NEG_WIDTH)427 b(217)190
+b(negative)45 b(table)i(row)g(size)48 3265 y(NEG_ROWS)475
+b(218)190 b(negative)45 b(number)i(of)g(rows)f(in)i(table)48
+3378 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 3491 y(BAD_SIMPLE)379 b(220)190
+b(illegal)46 b(value)g(of)h(SIMPLE)f(keyword)48 3604
+y(NO_SIMPLE)427 b(221)190 b(Primary)46 b(array)g(doesn't)g(start)g
+(with)h(SIMPLE)48 3717 y(NO_BITPIX)427 b(222)190 b(Second)46
+b(keyword)g(not)h(BITPIX)48 3830 y(NO_NAXIS)475 b(223)190
+b(Third)46 b(keyword)g(not)h(NAXIS)48 3942 y(NO_NAXES)475
+b(224)190 b(Couldn't)45 b(find)i(all)g(the)g(NAXISn)f(keywords)48
+4055 y(NO_XTENSION)331 b(225)190 b(HDU)47 b(doesn't)f(start)g(with)h
+(XTENSION)e(keyword)48 4168 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
+4281 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 4394 y(NO_PCOUNT)427 b(228)190
+b(couldn't)45 b(find)i(PCOUNT)f(keyword)48 4507 y(NO_GCOUNT)427
+b(229)190 b(couldn't)45 b(find)i(GCOUNT)f(keyword)48
+4620 y(NO_TFIELDS)379 b(230)190 b(couldn't)45 b(find)i(TFIELDS)f
+(keyword)48 4733 y(NO_TBCOL)475 b(231)190 b(couldn't)45
+b(find)i(TBCOLn)f(keyword)48 4846 y(NO_TFORM)475 b(232)190
+b(couldn't)45 b(find)i(TFORMn)f(keyword)48 4959 y(NOT_IMAGE)427
+b(233)190 b(the)47 b(CHDU)f(is)i(not)f(an)g(IMAGE)f(extension)48
+5072 y(BAD_TBCOL)427 b(234)190 b(TBCOLn)46 b(keyword)g(value)g(<)i(0)f
+(or)g(>)h(rowlength)48 5185 y(NOT_TABLE)427 b(235)190
+b(the)47 b(CHDU)f(is)i(not)f(a)g(table)48 5297 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
+5410 y(COL_NOT_UNIQUE)187 b(237)j(more)47 b(than)f(1)i(column)e(name)g
+(matches)g(template)48 5523 y(BAD_ROW_WIDTH)235 b(241)190
+b(sum)47 b(of)g(column)f(widths)g(not)h(=)h(NAXIS1)48
+5636 y(UNKNOWN_EXT)331 b(251)190 b(unrecognizable)44
+b(FITS)i(extension)g(type)p eop end
+%%Page: 179 187
+TeXDict begin 179 186 bop 3764 299 a Fj(179)48 555 y
+Fe(UNKNOWN_REC)331 b(252)190 b(unknown)46 b(record;)g(1st)g(keyword)g
+(not)h(SIMPLE)f(or)h(XTENSION)48 668 y(END_JUNK)475 b(253)190
+b(END)47 b(keyword)f(is)h(not)g(blank)48 781 y(BAD_HEADER_FILL)139
+b(254)190 b(Header)46 b(fill)h(area)f(contains)g(non-blank)f(chars)48
+894 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 1007 y(BAD_TFORM)427
+b(261)190 b(illegal)46 b(TFORM)g(format)g(code)48 1120
+y(BAD_TFORM_DTYPE)139 b(262)190 b(unrecognizable)44 b(TFORM)i(data)h
+(type)f(code)48 1233 y(BAD_TDIM)475 b(263)190 b(illegal)46
+b(TDIMn)g(keyword)g(value)48 1346 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 1571 y(BAD_HDU_NUM)331 b(301)190 b(HDU)47 b(number)f(<)h(1)48
+1684 y(BAD_COL_NUM)331 b(302)190 b(column)46 b(number)g(<)i(1)f(or)g(>)
+h(tfields)48 1797 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
+1910 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 2023 y(BAD_ROW_NUM)331
+b(307)190 b(illegal)46 b(starting)f(row)i(number)f(in)h(table)48
+2136 y(BAD_ELEM_NUM)283 b(308)190 b(illegal)46 b(starting)f(element)h
+(number)g(in)h(vector)48 2249 y(NOT_ASCII_COL)235 b(309)190
+b(this)47 b(is)g(not)g(an)g(ASCII)f(string)g(column)48
+2362 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 2475 y(BAD_ATABLE_FORMAT)d(311)190
+b(ASCII)46 b(table)h(column)f(has)h(wrong)f(format)48
+2588 y(BAD_BTABLE_FORMAT)d(312)190 b(Binary)46 b(table)g(column)g(has)h
+(wrong)g(format)48 2700 y(NO_NULL)523 b(314)190 b(null)47
+b(value)f(has)h(not)g(been)f(defined)48 2813 y(NOT_VARI_LEN)283
+b(317)190 b(this)47 b(is)g(not)g(a)g(variable)f(length)g(column)48
+2926 y(BAD_DIMEN)427 b(320)190 b(illegal)46 b(number)g(of)h(dimensions)
+e(in)i(array)48 3039 y(BAD_PIX_NUM)331 b(321)190 b(first)46
+b(pixel)h(number)f(greater)g(than)g(last)h(pixel)48 3152
+y(ZERO_SCALE)379 b(322)190 b(illegal)46 b(BSCALE)g(or)h(TSCALn)f
+(keyword)g(=)h(0)48 3265 y(NEG_AXIS)475 b(323)190 b(illegal)46
+b(axis)g(length)g(<)i(1)48 3491 y(NOT_GROUP_TABLE)330
+b(340)142 b(Grouping)46 b(function)f(error)48 3604 y
+(HDU_ALREADY_MEMBER)186 b(341)48 3717 y(MEMBER_NOT_FOUND)282
+b(342)48 3830 y(GROUP_NOT_FOUND)330 b(343)48 3942 y(BAD_GROUP_ID)474
+b(344)48 4055 y(TOO_MANY_HDUS_TRACKED)42 b(345)48 4168
+y(HDU_ALREADY_TRACKED)138 b(346)48 4281 y(BAD_OPTION)570
+b(347)48 4394 y(IDENTICAL_POINTERS)186 b(348)48 4507
+y(BAD_GROUP_ATTACH)282 b(349)48 4620 y(BAD_GROUP_DETACH)g(350)48
+4846 y(NGP_NO_MEMORY)426 b(360)238 b(malloc)46 b(failed)48
+4959 y(NGP_READ_ERR)474 b(361)238 b(read)46 b(error)h(from)f(file)48
+5072 y(NGP_NUL_PTR)522 b(362)238 b(null)46 b(pointer)g(passed)g(as)h
+(an)g(argument.)1575 5185 y(Passing)f(null)g(pointer)g(as)h(a)h(name)f
+(of)1575 5297 y(template)f(file)g(raises)g(this)h(error)48
+5410 y(NGP_EMPTY_CURLINE)234 b(363)k(line)46 b(read)h(seems)f(to)h(be)h
+(empty)e(\(used)1575 5523 y(internally\))48 5636 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)p eop end
+%%Page: 180 188
+TeXDict begin 180 187 bop 0 299 a Fj(180)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)1575 555 y Fe(line)47 b(twice\))48 668 y(NGP_INC_NESTING)330
+b(365)238 b(too)46 b(deep)h(include)f(file)h(nesting)e(\(infinite)1575
+781 y(loop,)h(template)g(includes)f(itself)i(?\))48 894
+y(NGP_ERR_FOPEN)426 b(366)238 b(fopen\(\))45 b(failed,)h(cannot)g(open)
+h(template)e(file)48 1007 y(NGP_EOF)714 b(367)238 b(end)46
+b(of)i(file)e(encountered)f(and)i(not)g(expected)48 1120
+y(NGP_BAD_ARG)522 b(368)238 b(bad)46 b(arguments)g(passed.)g(Usually)f
+(means)1575 1233 y(internal)h(parser)g(error.)g(Should)g(not)h(happen)
+48 1346 y(NGP_TOKEN_NOT_EXPECT)90 b(369)238 b(token)46
+b(not)h(expected)e(here)48 1571 y(BAD_I2C)523 b(401)190
+b(bad)47 b(int)g(to)g(formatted)e(string)h(conversion)48
+1684 y(BAD_F2C)523 b(402)190 b(bad)47 b(float)f(to)h(formatted)f
+(string)g(conversion)48 1797 y(BAD_INTKEY)379 b(403)190
+b(can't)46 b(interpret)g(keyword)f(value)i(as)g(integer)48
+1910 y(BAD_LOGICALKEY)187 b(404)j(can't)46 b(interpret)g(keyword)f
+(value)i(as)g(logical)48 2023 y(BAD_FLOATKEY)283 b(405)190
+b(can't)46 b(interpret)g(keyword)f(value)i(as)g(float)48
+2136 y(BAD_DOUBLEKEY)235 b(406)190 b(can't)46 b(interpret)g(keyword)f
+(value)i(as)g(double)48 2249 y(BAD_C2I)523 b(407)190
+b(bad)47 b(formatted)e(string)h(to)h(int)g(conversion)48
+2362 y(BAD_C2F)523 b(408)190 b(bad)47 b(formatted)e(string)h(to)h
+(float)g(conversion)48 2475 y(BAD_C2D)523 b(409)190 b(bad)47
+b(formatted)e(string)h(to)h(double)f(conversion)48 2588
+y(BAD_DATATYPE)283 b(410)190 b(illegal)46 b(datatype)f(code)i(value)48
+2700 y(BAD_DECIM)427 b(411)190 b(bad)47 b(number)f(of)h(decimal)f
+(places)g(specified)48 2813 y(NUM_OVERFLOW)283 b(412)190
+b(overflow)45 b(during)i(data)f(type)h(conversion)48
+2926 y(DATA_COMPRESSION_ERR)137 b(413)95 b(error)46 b(compressing)f
+(image)48 3039 y(DATA_DECOMPRESSION_ERR)c(414)95 b(error)46
+b(uncompressing)f(image)48 3265 y(BAD_DATE)475 b(420)190
+b(error)46 b(in)h(date)g(or)g(time)g(conversion)48 3491
+y(PARSE_SYNTAX_ERR)91 b(431)190 b(syntax)46 b(error)g(in)i(parser)e
+(expression)48 3604 y(PARSE_BAD_TYPE)187 b(432)j(expression)45
+b(did)i(not)g(evaluate)e(to)i(desired)f(type)48 3717
+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 3830 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 3942 y(PARSE_BAD_COL)235 b(435)190 b(bad)47 b(data)f(encounter)g
+(while)g(parsing)g(column)48 4055 y(PARSE_BAD_OUTPUT)91
+b(436)190 b(Output)46 b(file)h(not)g(of)g(proper)f(type)48
+4281 y(ANGLE_TOO_BIG)235 b(501)190 b(celestial)45 b(angle)i(too)f
+(large)h(for)g(projection)48 4394 y(BAD_WCS_VAL)331 b(502)190
+b(bad)47 b(celestial)e(coordinate)g(or)i(pixel)g(value)48
+4507 y(WCS_ERROR)427 b(503)190 b(error)46 b(in)h(celestial)f
+(coordinate)f(calculation)48 4620 y(BAD_WCS_PROJ)283
+b(504)190 b(unsupported)45 b(type)h(of)h(celestial)f(projection)48
+4733 y(NO_WCS_KEY)379 b(505)190 b(celestial)45 b(coordinate)g(keywords)
+h(not)h(found)48 4846 y(APPROX_WCS_KEY)187 b(506)j(approximate)45
+b(wcs)i(keyword)e(values)h(were)h(returned)p eop end
+%%Trailer
+
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/vendor/cfitsio/cfitsio.tex b/vendor/cfitsio/cfitsio.tex
new file mode 100644
index 00000000..f3985f38
--- /dev/null
+++ b/vendor/cfitsio/cfitsio.tex
@@ -0,0 +1,10644 @@
+\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 3.3 \\}
+\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 April 2012\\}
+\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: William.D.Pence@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{Acknowledgments}
+
+The development of the many 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. Also, in 2009, Bruce O'Neel
+was the key developer of the thread-safe version of CFITSIO.
+
+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.
+
+Giuliano Taffoni and Andrea Barisani, at INAF, University of Trieste,
+Italy, implemented the I/O driver routines for accessing FITS files
+on the computational grids using the gridftp protocol.
+
+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.
+
+Martin Reinecke (Max Planck Institute, Garching)) provided the modifications to
+cfortran.h that are necessary to support 64-bit integer values when calling
+C routines from fortran programs. The cfortran.h macros were originally developed
+by Burkhard Burow (CERN).
+
+Julian Taylor (ESO, Garching) provided the fast byte-swapping algorithms
+that use the SSE2 and SSSE3 machine instructions available on x86\_64 CPUs.
+
+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,
+Rob Seaman, 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.
+
+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."
+
+\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 (not up-to-date):
+
+\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] [--enable-reentrant]
+ [--enable-sse2] [--enable-ssse3]
+ > 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 optional --enable-reentrant flag will attempt to configure CFITSIO
+so that it can be used in multi-threaded programs. See the "Using CFITSIO in Multi-threaded Environments" section, below, for more
+
+The optional --enable-sse2 and --enable-ssse3 flags will cause configure to
+attempt to build CFITSIO using faster byte-swapping algorithms.
+See the "Optimizing Programs" chapter of this manual for
+more information about these options.
+
+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.
+
+It may not be possible to statically 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\_3xxx\_borland.zip and cfitsiodll\_3xxx\_vcc.zip, where
+'3xxx' 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 or v5.5 compiler
+using older DOS commands.
+
+
+\subsection{Macintosh PCs}
+
+When building on Mac OS-X, users should follow the Unix instructions,
+above. See the README.MacOS file for instructions on building a Universal
+Binary that supports both Intel and PowerPC CPUs.
+
+
+\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{Using CFITSIO in Multi-threaded Environments}
+
+CFITSIO can be used either with the
+POSIX pthreads interface or the OpenMP interface for multi-threaded
+parallel programs. When used in a multi-threaded environment,
+the CFITSIO library *must* be built using
+the -D\_REENTRANT compiler directive. This can be done using the following
+build commands:
+
+\begin{verbatim}
+ >./configure --enable-reentrant
+ > make
+\end{verbatim}
+A function called fits\_is\_reentrant is available to test
+whether or not CFITSIO was compiled with the -D\_REENTRANT
+directive. When this feature is enabled, multiple threads can
+call any of the CFITSIO routines
+to simultaneously read or write separate
+FITS files. Multiple threads can also read data from
+the same FITS file simultaneously, as long as the file
+was opened independently by each thread. This relies on
+the operating system to correctly deal with reading the
+same file by multiple processes. Different threads should
+not share the same 'fitsfile' pointer to read an opened
+FITS file, unless locks are placed around the calls to
+the CFITSIO reading routines.
+Different threads should never try to write to the same
+FITS file.
+
+
+\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. Six different primary
+data types are supported: Unsigned 8-bit bytes, 16-bit, 32-bit, and 64-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, 64, -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 further 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 LONGLONG_IMG 64 /* 64-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 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 TLONG 41 /* signed long, */
+ #define TLONGLONG 81 /* 64-bit long signed integer 'K' */
+ #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 */
+
+ The following data type code is only for use with fits\_get\_coltype
+ #define TINT32BIT 41 /* signed 32-bit int, 'J' */
+
+
+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
+ #define HCOMPRESS_1 41
+\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. Implicit 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 old PC compilers,
+but otherwise it is nearly always 4 bytes long. Some 64-bit
+machines, like the Alpha/OSF, define the `short', `int',
+and `long' integer data types to be 2, 4, and 8 bytes long,
+respectively.
+
+Because there is no universal C compiler standard for the name of the
+8-byte integer datatype, the fitsio.h include file typedef's
+'LONGLONG' to be equivalent to an
+appropriate 8-byte integer data type on each supported platform.
+For maximum software portability it is recommended that
+this LONGLONG datatype be used to define 8-byte integer variables
+rather than using the native data type name on a particular
+platform. On most
+32-bit Unix and Mac OS-X operating systems LONGLONG is equivalent to the
+intrinsic 'long long' 8-byte integer datatype. On 64-bit systems (which currently
+includes Alpha OSF/1, 64-bit Sun Solaris, 64-bit SGI MIPS, and 64-bit
+Itanium and Opteron PC systems), LONGLONG is simply typedef'ed to be
+equivalent to 'long'. Microsoft Visual C++ Version 6.0 does not define
+a 'long long' data type, so LONGLONG is typedef'ed to be equivalent to
+the '\_\_int64' data type on 32-bit windows systems when using Visual C++.
+
+A related issue that affects the portability of software is how to print
+out the value of a 'LONGLONG' variable with printf. Developers may
+find it convenient to use the following preprocessing statements
+in their C programs to handle this in a machine-portable manner:
+
+
+\begin{verbatim}
+#if defined(_MSC_VER) /* Microsoft Visual C++ */
+ printf("%I64d", longlongvalue);
+
+#elif (USE_LL_SUFFIX == 1)
+ printf("%lld", longlongvalue);
+
+#else
+ printf("%ld", longlongvalue);
+#endif
+\end{verbatim}
+
+Similarly, the name of the C utility routine that converts a character
+string of digits into a 8-byte integer value is platform dependent:
+
+
+\begin{verbatim}
+#if defined(_MSC_VER) /* Microsoft Visual C++ */
+ /* VC++ 6.0 does not seem to have an 8-byte conversion routine */
+
+#elif (USE_LL_SUFFIX == 1)
+ longlongvalue = atoll(*string);
+
+#else
+ longlongvalue = atol(*string);
+#endif
+\end{verbatim}
+
+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. This is also not
+supported when reading floating-point images that have been compressed
+with the FITS tiled image compression convention that is discussed in
+section 5.6; the pixels values in tile compressed images are
+represented by scaled integers, and a reserved integer value
+(not a NaN) is used to represent undefined pixels.
+
+
+\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. (CFITSIO also
+supports the experimental 'Q' datatype, which is identical to the 'P' type
+except that is supports is a 64-bit address space and hence much larger
+data structures). 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 row of data 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 and the new data will be
+written to a new area of the heap. The fits\_compress\_heap routine
+is provided to compress the heap and recover any unused space.
+To avoid having to deal with this issue, it is recommended
+that rows in a variable length field should only be written once.
+An exception to
+this general rule occurs when setting elements of an array as
+undefined. It is allowed to 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. 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 of course 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.
+
+Some restriction apply: a FITS file cannot be opened the first time
+with READONLY access, and then opened a second time with READWRITE access,
+because this may be phyically impossible (e.g., if the file resides
+on read-only media such as a CDROM). Also, in multi-threaded environoments,
+one should never open the same file with write access in different threads.
+
+
+\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.
+
+2. It used to be common for computer systems to only support disk files up
+to 2**31 bytes = 2.1 GB in size, but most systems now support larger files.
+CFITSIO can optionally read and write these so-called 'large files' that
+are greater than 2.1 GB on
+platforms where they are supported, but this
+usually requires that special compiler option flags be specified to turn
+on this option. On linux and solaris systems the compiler flags are
+'-D\_LARGEFILE\_SOURCE' and `-D\_FILE\_OFFSET\_BITS=64'. These flags
+may also work on other platforms but this has not been tested. Starting
+with version 3.0 of CFITSIO, the default Makefile that is distributed
+with CFITSIO will include these 2 compiler flags when building on Solaris
+and Linux PC systems. Users on other platforms will need to add these
+compiler flags manually if they want to support large files. In most
+cases it appears that it is not necessary to include these compiler
+flags when compiling application code that call the CFITSIO library
+routines.
+
+When CFITSIO is built with large file support (e.g., on Solaris and
+Linux PC system by default) then it can read and write FITS data files
+on disk that have any of these conditions:
+
+\begin{itemize}
+\item
+FITS files larger than 2.1 GB in size
+\item
+FITS images containing greater than 2.1 G pixels
+\item
+FITS images that have one dimension with more than 2.1 G pixels
+(as given by one of the NAXISn keyword)
+\item
+FITS tables containing more than 2.1E09 rows (given by the NAXIS2 keyword),
+or with rows that are more than 2.1 GB wide (given by the NAXIS1 keyword)
+\item
+FITS binary tables with a variable-length array heap that is larger
+than 2.1 GB (given by the PCOUNT keyword)
+\end{itemize}
+
+The current maximum FITS file size supported by CFITSIO
+is about 6 terabytes (containing
+2**31 FITS blocks, each 2880 bytes in size). Currently, support for large
+files in CFITSIO has been tested on the Linux, Solaris, and IBM AIX
+operating systems.
+
+Note that when writing application programs that are intended to support
+large files it is important to use 64-bit integer variables
+to store quantities such as the dimensions of images, or the number of
+rows in a table. These programs must also call the special versions
+of some of the CFITSIO routines that have been adapted to
+support 64-bit integers. The names of these routines end in
+'ll' ('el' 'el') to distinguish them from the 32-bit integer
+version (e.g., fits\_get\_num\_rowsll).
+
+
+\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 greater than 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. This returns the
+number of completely defined HDUs in the file. If a new HDU has just been added to
+the FITS file, then that last HDU will only be counted if it has been closed,
+or if data has been written to the HDU.
+ The current HDU remains unchanged by this routine. \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 ] Write the current HDU in the input FITS file to the
+ output FILE stream (e.g., to stdout). \label{ffwrhdu}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_hdu / ffwrhdu
+ (fitsfile *infptr, FILE *stream, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] 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[9 ] 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 searches. 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, TLONGLONG, 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, with any
+ trailing blank characters stripped off. The fourth routine returns
+ the (next) header record that contains the literal string of characters
+ specified by the 'string' argument.
+
+ 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)
+
+ int fits_read_str / ffgstr
+ (fitsfile *fptr, char *string, > 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 (with trailing blanks truncated),
+ while the second routine parses the record and returns the name,
+ value, and comment fields as separate (blank truncated)
+ 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. These routine allocates memory for the returned
+ character array, so the calling program must free the memory when
+ finished. The cleanest way to do this is to
+ call the fits\_free\_memory routine.
+
+ There are 2 related routines: fits\_hdr2str simply concatenates all
+ the existing keywords in the header; fits\_convert\_hdr2str is similar,
+ except that if the CHDU is a tile compressed image (stored in a binary
+ table) then it will first convert that header back to that of the corresponding
+ normal FITS image before concatenating the keywords.
+
+ 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 **exclist parameter. \label{ffhdr2str}
+\end{description}
+
+\begin{verbatim}
+ int fits_hdr2str / ffhdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+
+ int fits_convert_hdr2str / ffcnvthdr2str
+ (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, TLONGLONG, 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. The third routine deletes the (next) keyword that contains
+ the literal character string specified by the 'string'
+ argument.\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)
+
+ int fits_delete_str / ffdstr
+ (fitsfile *fptr, char *string, > 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 often 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), LONGLONG\_IMG (64),
+ 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_sizell / ffgiszll
+ (fitsfile *fptr, int maxdim, > LONGLONG *naxes, int *status)
+
+ int fits_get_img_param / ffgipr
+ (fitsfile *fptr, int maxdim, > int *bitpix, int *naxis, long *naxes,
+ int *status)
+
+ int fits_get_img_paramll / ffgiprll
+ (fitsfile *fptr, int maxdim, > int *bitpix, int *naxis, LONGLONG *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)
+
+ int fits_create_imgll / ffcrimll
+ ( fitsfile *fptr, int bitpix, int naxis, LONGLONG *naxes, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[4 ] Copy an n-dimensional image in a particular row and column of a
+ binary table (in a vector column)
+ to or from a primary array or image extension.
+
+ The 'cell2image' routine
+ will append a new image extension (or primary array) to the output file.
+ Any WCS keywords associated with the input column image will be translated
+ into the appropriate form for an image extension. Any other keywords
+ in the table header that are not specifically related to defining the
+ binary table structure or to other columns in the table
+ will also be copied to the header of the output image.
+
+ The 'image2cell' routine will copy the input image into the specified row
+ and column of the current binary table in the output file. The binary table
+ HDU must exist before calling this routine, but it
+ may be empty, with no rows or columns of data. The specified column
+ (and row) will be created if it does not already exist. The 'copykeyflag'
+ parameter controls which keywords are copied from the input
+ image to the header of the output table: 0 = no keywords will be copied,
+ 1 = all keywords will be copied (except those keywords that would be invalid in
+ the table header), and 2 = copy only the WCS keywords. \label{copycell}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_cell2image
+ (fitsfile *infptr, fitsfile *outfptr, char *colname, long rownum,
+ > int *status)
+
+ int fits_copy_image2cell
+ (fitsfile *infptr, fitsfile *outfptr, char *colname, long rownum,
+ int copykeyflag > int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[5 ] 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[6 ] 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 pair of routines
+ simply writes the array of pixels to the FITS file (doing data type
+ conversion if necessary) whereas the second routines 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, LONGLONG nelements,
+ DTYPE *array, int *status);
+
+ int fits_write_pixll / ffppxll
+ (fitsfile *fptr, int datatype, LONGLONG *fpixel, LONGLONG nelements,
+ DTYPE *array, int *status);
+
+ int fits_write_pixnull / ffppxn
+ (fitsfile *fptr, int datatype, long *fpixel, LONGLONG nelements,
+ DTYPE *array, DTYPE *nulval, > int *status);
+
+ int fits_write_pixnullll / ffppxnll
+ (fitsfile *fptr, int datatype, LONGLONG *fpixel, LONGLONG nelements,
+ DTYPE *array, DTYPE *nulval, > int *status);
+\end{verbatim}
+
+\begin{description}
+\item[7 ] 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, LONGLONG firstelem, LONGLONG nelements, > int *status)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] 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[9 ] 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 2 routines 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 2 routines are 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, LONGLONG nelements,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_pixll / ffgpxvll
+ (fitsfile *fptr, int datatype, LONGLONG *fpixel, LONGLONG nelements,
+ DTYPE *nulval, > DTYPE *array, int *anynul, int *status)
+
+ int fits_read_pixnull / ffgpxf
+ (fitsfile *fptr, int datatype, long *fpixel, LONGLONG nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+
+ int fits_read_pixnullll / ffgpxfll
+ (fitsfile *fptr, int datatype, LONGLONG *fpixel, LONGLONG nelements,
+ > DTYPE *array, char *nullarray, int *anynul, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Copy a rectangular section of an image and write it to a new
+ FITS primary image or image extension. The new image HDU is appended
+ to the end of the output file; all the keywords in the input image
+ will be copied to the output image. The common WCS keywords will
+ be updated if necessary to correspond to the coordinates of the section.
+ The format of the section expression is
+ same as specifying an image section using the extended file name
+ syntax (see "Image Section" in Chapter 10).
+ (Examples: "1:100,1:200", "1:100:2, 1:*:2", "*, -*").
+ \label{ffcpimg}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_image_section / ffcpimg
+ (fitsfile *infptr, fitsfile *outfptr, char *section, int *status)
+\end{verbatim}
+
+
+\section{Image Compression}
+
+CFITSIO transparently supports the 2 methods of image compression described
+below.
+
+1) The entire FITS file may be externally compressed with the gzip or Unix
+compress utility programs, 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 since all the
+I/O is performed in memory; the main limitation with this technique is that
+there must be enough available memory (or swap space) to hold the entire
+uncompressed FITS file.
+
+2) CFITSIO also supports the FITS tiled image compression convention in
+which the image is subdivided into a grid of rectangular tiles, and each
+tile of pixels is individually compressed. The details of this FITS
+compression convention are described at the FITS Support Office web site at
+http://fits.gsfc.nasa.gov/fits\_registry.html Basically, the compressed
+image tiles are stored in rows of a variable length array column in a FITS
+binary table, however CFITSIO recognizes that this 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
+than simply compressing the image using gzip or compress because it
+approximates the floating point values with scaled integers which can then
+be compressed more efficiently.
+
+Currently CFITSIO supports 3 general purpose compression algorithms plus
+one other special-purpose compression technique that is designed for data
+masks with positive integer pixel values. The 3 general purpose algorithms
+are GZIP, Rice, and HCOMPRESS, and the special purpose algorithm is the
+IRAF pixel list compression technique (PLIO). In principle, any number of
+other compression algorithms could also be supported by the FITS tiled
+image compression convention.
+
+The FITS image can be subdivided into any desired rectangular grid of
+compression tiles. With the GZIP, Rice, and PLIO algorithms, the default
+is to take each row of the image as a tile. The HCOMPRESS algorithm is
+inherently 2-dimensional in nature, so the default in this case is to take
+16 rows of the image per tile. In most cases it makes little difference what
+tiling pattern is used, so the default tiles are usually adequate. In the
+case of very small images, it could be more efficient to compress the whole
+image as a single tile. Note that the image dimensions are not required to
+be an integer multiple of the tile dimensions; if not, then the tiles at the
+edges of the image will be smaller than the other tiles.
+
+The 4 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. In
+addition, the HCOMPRESS algorithm supports a 'lossy' compression mode that
+will produce
+larger amount of image compression. This is achieved by specifying a non-zero
+value for the HCOMPRESS ``scale''
+parameter. Since the amount of compression that is achieved depends directly
+on the RMS noise in the image, it is usually more convention
+to specify the HCOMPRESS scale factor relative to the RMS noise.
+Setting s = 2.5 means use a scale factor that is 2.5 times the calculated RMS noise
+in the image tile. In some cases
+it may be desirable to specify the exact scaling to be used,
+instead of specifying it relative to the calculated noise value. This may
+be done by specifying the negative of desired scale value (typically
+in the range -2 to -100).
+
+Very high compression factors (of 100 or more) can be
+achieved by using large HCOMPRESS scale values, however, this can produce undesirable
+``blocky'' artifacts in the compressed image. A variation of the HCOMPRESS
+algorithm (called HSCOMPRESS) can be used in this case to apply a small
+amount of smoothing of the image when it is uncompressed to help cover up
+these artifacts. This smoothing is purely cosmetic and does not cause any
+significant change to the image pixel values.
+
+Floating point FITS images (which have BITPIX = -32 or -64) usually contain
+too much ``noise'' in the least significant bits of the mantissa of the
+pixel values to be effectively compressed with any lossless algorithm.
+Consequently, floating point images are first quantized into scaled integer
+pixel values (and thus throwing away much of the noise) before being
+compressed with the specified algorithm (either GZIP, Rice, or HCOMPRESS).
+This technique produces much higher compression factors than
+simply using the GZIP utility to externally compress the whole FITS file, but it also
+means that the original floating value pixel values are not exactly
+preserved. When done properly, this integer scaling technique will only
+discard the insignificant noise while still preserving all the real
+information in the image. The amount of precision that is retained in the
+pixel values is controlled by the "quantization level" parameter, q. Larger
+values of q will result in compressed images whose pixels more closely match
+the floating point pixel values, but at the same time the amount of
+compression that is achieved will be reduced. Users should experiment with
+different values for this parameter to determine the optimal value that
+preserves all the useful information in the image, without needlessly
+preserving all the ``noise'' which will hurt the compression efficiency.
+
+The default value for the quantization scale factor is 16., which means that
+scaled integer pixel values will be quantized such that the difference
+between adjacent integer values will be 1/16th of the noise level in the
+image background. CFITSIO uses an optimized algorithm to accurately estimate
+the noise in the image. As an example, if the RMS noise in the background
+pixels of an image = 32.0, then the spacing between adjacent scaled
+integer pixel values will equal 2.0 by default. Note that the RMS noise is
+independently calculated for each tile of the image, so the resulting
+integer scaling factor may fluctuate slightly for each tile. In some cases
+it may be desirable to specify the exact quantization level to be used,
+instead of specifying it relative to the calculated noise value. This may
+be done by specifying the negative of desired quantization level for the
+value of q. In the previous example, one could specify q = -2.0 so that the
+quantized integer levels differ by 2.0. Larger negative values for q means
+that the levels are more coarsely spaced, and will produce higher
+compression factors.
+
+There are 2 methods for specifying all the parameters needed to write a FITS
+image in the tile compressed format. The parameters may either be specified
+at run time as part of the file name of the output compressed FITS file, or
+the writing program may call a set of helper CFITSIO subroutines that are provided
+for specifying the parameter values, as described below:
+
+1) At run time, 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 by enclosing the compression
+parameters in square brackets following the root disk file name
+in the following format:
+
+\begin{verbatim}
+ [compress NAME T1,T2; q QLEVEL, s HSCALE]
+\end{verbatim}
+where
+
+\begin{verbatim}
+ NAME = algorithm name: GZIP, Rice, HCOMPRESS, HSCOMPRSS or PLIO
+ may be abbreviated to the first letter (or HS for HSCOMPRESS)
+ T1,T2 = tile dimension (e.g. 100,100 for square tiles 100 pixels wide)
+ QLEVEL = quantization level for floating point FITS images
+ HSCALE = HCOMPRESS scale factor; default = 0 which is lossless.
+\end{verbatim}
+
+Here are a few examples of this extended syntax:
+
+
+\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 HCOMP]
+
+ myfile.fit[compress R 100,100] - use Rice and 100 x 100 pixel tiles
+
+ myfile.fit[compress R; q 10.0] - quantization level = (RMS-noise) / 10.
+ myfile.fit[compress HS; s 2.0] - HSCOMPRESS (with smoothing)
+ and scale = 2.0 * RMS-noise
+\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 routines for specifying
+the various compression parameters and similar 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_quantize_level(fitsfile *fptr, float qlevel, int *status)
+ int fits_set_hcomp_scale(fitsfile *fptr, float scale, int *status)
+ int fits_set_hcomp_smooth(fitsfile *fptr, int smooth, int *status)
+ Set smooth = 1 to apply smoothing when uncompressing the image
+
+ 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_quantize_level(fitsfile *fptr, float *level, int *status)
+ int fits_get_hcomp_scale(fitsfile *fptr, float *scale, int *status)
+ int fits_get_hcomp_smooth(fitsfile *fptr, int *smooth, int *status)
+\end{verbatim}
+4 symbolic constants are defined for use as the value of the
+`comptype' parameter: GZIP\_1, RICE\_1, HCOMPRESS\_1 or PLIO\_1.
+Entering NULL for
+comptype will turn off the tile-compression and cause normal FITS
+images to be written.
+
+
+No special action is required by software when read tile-compressed images because
+all the CFITSIO routines that read normal uncompressed FITS images also
+transparently 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.
+
+
+The following 2 routines are available for compressing or
+or decompressing an image:
+
+\begin{verbatim}
+ int fits_img_compress(fitsfile *infptr, fitsfile *outfptr, int *status);
+ int fits_img_decompress (fitsfile *infptr, fitsfile *outfptr, int *status);
+\end{verbatim}
+Before calling the compression routine, the compression parameters must
+first be defined in one of the 2 way described in the previous paragraphs.
+There is also a routine to determine if the current HDU contains
+a tile compressed image (it returns 1 or 0):
+
+\begin{verbatim}
+ int fits_is_compressed_image(fitsfile *fptr, int *status);
+\end{verbatim}
+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; q 10.0]'
+
+ This will use the Rice compression algorithm, 100 X 100 pixel
+ tiles, and quantization level = RMSnoise / 10.0 (assuming the
+ input image has a floating point data type).
+
+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 often
+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. \label{ffcrtb}
+\end{description}
+
+\begin{verbatim}
+ int fits_create_tbl / ffcrtb
+ (fitsfile *fptr, int tbltype, LONGLONG 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_rowsll / ffgnrwll
+ (fitsfile *fptr, > LONGLONG *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.
+ \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
+ CFITSIO 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 TDIMn
+ keyword may also be used to specify the unit string length; The pair
+ of keywords TFORMn = '60A' and TDIMn = '(12,5)' would have the
+ same effect as TFORMn = '60A12'). The number
+ of substrings 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_coltypell / ffgtclll
+ (fitsfile *fptr, int colnum, > int *typecode, LONGLONG *repeat,
+ LONGLONG *width, int *status)
+
+ int fits_get_eqcoltype / ffeqty
+ (fitsfile *fptr, int colnum, > int *typecode, long *repeat,
+ long *width, int *status)
+
+ int fits_get_eqcoltypell / ffeqtyll
+ (fitsfile *fptr, int colnum, > int *typecode, LONGLONG *repeat,
+ LONGLONG *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)
+
+ int fits_read_tdimll / ffgtdmll
+ (fitsfile *fptr, int colnum, int maxdim, > int *naxis,
+ LONGLONG *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)
+
+ int fits_decode_tdimll / ffdtdmll
+ (fitsfile *fptr, char *tdimstr, int colnum, int maxdim, > int *naxis,
+ LONGLONG *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 multidimensional 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)
+
+ int fits_write_tdimll / ffptdmll
+ (fitsfile *fptr, int colnum, int naxis, LONGLONG *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. Note that it is *not* necessary to insert rows in a table before
+ writing data to those rows (indeed, it would be inefficient to do so).
+ Instead one may simply write data to any row of the table, whether that
+ row of data already exists or not.
+
+ 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, LONGLONG firstrow, LONGLONG nrows, > int *status)
+
+ int fits_delete_rows / ffdrow
+ (fitsfile *fptr, LONGLONG firstrow, LONGLONG 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)
+
+ int fits_delete_rowlistll / ffdrwsll
+ (fitsfile *fptr, LONGLONG *rowlist, LONGLONG 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 ] Copy 'nrows' consecutive rows from one table to another, beginning
+ with row 'firstrow'. These rows will be appended to any existing
+ rows in the output table.
+ Note that the first row in a table is at row = 1. \label{ffcprw}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_rows / ffcprw
+ (fitsfile *infptr, fitsfile *outfptr, LONGLONG firstrow,
+ LONGLONG nrows, > int *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. \label{ffmvec}
+\end{description}
+
+\begin{verbatim}
+ int fits_modify_vector_len / ffmvec
+ (fitsfile *fptr, int colnum, LONGLONG 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 array in 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 it is *not* necessary to insert rows in a table before
+writing data to those rows (indeed, it would be inefficient to do so).
+Instead, one may simply write data to any row of the table, whether that
+row of data already exists or not.
+
+Individual bits in a binary table 'X' or 'B' column may be read/written
+to/from a *char array by specifying the TBIT datatype. The *char
+array will be interpreted as an array of logical TRUE (1) or FALSE (0)
+values that correspond to the value of each bit in the FITS 'X' or 'B' column.
+Alternatively, the values in a binary table 'X' column may be read/written
+8 bits at a time to/from an array of 8-bit integers by specifying the
+TBYTE datatype.
+
+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 third routine
+ simply writes undefined pixel values to the column. The fourth routine
+ fills every column in the table with null values, in the specified
+ rows (ignoring any columns that do not have a defined null value).
+ \label{ffpcl} \label{ffpcn} \label{ffpclu}
+
+\begin{verbatim}
+ int fits_write_col / ffpcl
+ (fitsfile *fptr, int datatype, int colnum, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG nelements, DTYPE *array, > int *status)
+
+ int fits_write_colnull / ffpcn
+ (fitsfile *fptr, int datatype, int colnum, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG nelements, DTYPE *array, DTYPE *nulval,
+ > int *status)
+
+ int fits_write_col_null / ffpclu
+ (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelements, > int *status)
+
+ int fits_write_nullrows / ffprwu
+ (fitsfile *fptr, LONGLONG firstrow, LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelements, DTYPE *nulval, DTYPE *array, int *anynul, int *status)
+
+ int fits_read_colnull / ffgcf
+ (fitsfile *fptr, int datatype, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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.
+ Upon return,
+ *n\_good\_rows contains the number of rows that evaluate to TRUE. \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 output
+table is not empty, then this routine will append the new
+selected rows after the existing rows. 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 dimension and type information
+on the result. The returned dimensions correspond to a single row entry
+of the requested expression, and are equivalent to the result of fits\_read\_tdim().
+Note that strings are considered to be one element regardless of string length.
+If maxdim == 0, then naxes is optional. \label{fftexp}
+\end{description}
+
+\begin{verbatim}
+ int fits_test_expr / fftexp
+ (fitsfile *fptr, char *expr, int maxdim > int *datatype, long *nelem, int *naxis,
+ long *naxes, int *status)
+\end{verbatim}
+
+
+\subsection{Column Binning or Histogramming Routines}
+
+The following routines may be useful when performing histogramming operations on
+column(s) of a table to generate an image in a primary array or image extension.
+
+
+\begin{description}
+\item[1 ] Calculate the histogramming parameters (min, max, and bin size
+for each axis of the histogram, based on a variety of possible input parameters.
+If the input names of the columns to be binned are null, then the routine will first
+look for the CPREF = "NAME1, NAME2, ..." keyword which lists the preferred
+columns. If not present, then the routine will assume the column names X, Y, Z, and T
+for up to 4 axes (as specified by the NAXIS parameter).
+
+MININ and MAXIN are input arrays that give the minimum and maximum value for
+the histogram, along each axis. Alternatively, the name of keywords that give
+the min, max, and binsize may be give with the MINNAME, MAXNAME, and BINNAME
+array parameters. If the value = DOUBLENULLVALUE and no keyword names are
+given, then the routine will use the TLMINn and TLMAXn keywords, if present, or the
+actual min and/or max values in the column.
+
+BINSIZEIN is an array giving the binsize along each axis.
+If the value =
+DOUBLENULLVALUE, and a keyword name is not specified with BINNAME,
+then this routine will first look for the TDBINn keyword, or else will
+use a binsize = 1, or a binsize that produces 10 histogram bins, which ever
+is smaller.
+ \label{calcbinning}
+\end{description}
+
+\begin{verbatim}
+ int fits_calc_binning
+ Input parameters:
+ (fitsfile *fptr, /* IO - pointer to table to be binned */
+ int naxis, /* I - number of axes/columns in the binned image */
+ char colname[4][FLEN_VALUE], /* I - optional column names */
+ double *minin, /* I - optional lower bound value for each axis */
+ double *maxin, /* I - optional upper bound value, for each axis */
+ double *binsizein, /* I - optional 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 */
+ Output parameters:
+ int *colnum, /* O - column numbers, to be binned */
+ long *naxes, /* O - number of bins in each histogram axis */
+ float *amin, /* O - lower bound of the histogram axes */
+ float *amax, /* O - upper bound of the histogram axes */
+ float *binsize, /* O - width of histogram bins/pixels on each axis */
+ int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[2 ] Copy the relevant keywords from the header of the table that is being
+binned, to the the header of the output histogram image. This will not
+copy the table structure keywords (e.g., NAXIS, TFORMn, TTYPEn, etc.) nor
+will it copy the keywords that apply to other columns of the table that are
+not used to create the histogram. This routine will translate the names of
+the World Coordinate System (WCS) keywords for the binned columns into the
+form that is need for a FITS image (e.g., the TCTYPn table keyword will
+be translated to the CTYPEn image keyword).
+ \label{copypixlist2image}
+\end{description}
+
+\begin{verbatim}
+ int fits_copy_pixlist2image
+ (fitsfile *infptr, /* I - pointer to input HDU */
+ fitsfile *outfptr, /* I - pointer to output HDU */
+ int firstkey, /* I - first HDU keyword to start with */
+ int naxis, /* I - number of axes in the image */
+ int *colnum, /* I - numbers of the columns to be binned */
+ int *status) /* IO - error status */
+\end{verbatim}
+
+
+\begin{description}
+\item[3 ] Write a set of default WCS keywords to the histogram header, IF the
+WCS keywords do not already exist. This will create a linear WCS where
+the coordinate types are equal to the original column names.
+ \label{writekeyshisto}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_keys_histo
+ (fitsfile *fptr, /* I - pointer to table to be binned */
+ fitsfile *histptr, /* I - pointer to output histogram image HDU */
+ int naxis, /* I - number of axes in the histogram image */
+ int *colnum, /* I - column numbers of the binned columns */
+ int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[4 ] Update the WCS keywords in a histogram image header that give the location
+of the reference pixel (CRPIXn), and the pixel size (CDELTn), in the binned
+image.
+ \label{rebinwcs}
+\end{description}
+
+\begin{verbatim}
+ int fits_rebin_wcs
+ (fitsfile *fptr, /* I - pointer to table to be binned */
+ int naxis, /* I - number of axes in the histogram image */
+ float *amin, /* I - first pixel include in each axis */
+ float *binsize, /* I - binning factor for each axis */
+ int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[5 ] Bin the values in the input table columns, and write the histogram
+array to the output FITS image (histptr).
+ \label{makehist}
+\end{description}
+
+\begin{verbatim}
+ int fits_make_hist
+ (fitsfile *fptr, /* I - pointer to table with X and Y cols; */
+ fitsfile *histptr, /* I - pointer to output FITS image */
+ int bitpix, /* I - datatype for image: 16, 32, -32, etc */
+ int naxis, /* I - number of axes in the histogram image */
+ long *naxes, /* I - size of axes in the histogram image */
+ int *colnum, /* I - column numbers (array length = naxis) */
+ float *amin, /* I - minimum histogram value, for each axis */
+ float *amax, /* I - maximum histogram value, for each axis */
+ float *binsize, /* I - bin size along each axis */
+ float weight, /* I - binning weighting factor (FLOATNULLVALUE */
+ /* for no weighting) */
+ int wtcolnum, /* I - keyword or col for weight (or NULL) */
+ int recip, /* I - use reciprocal of the weight? 0 or 1 */
+ 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)
+\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. The '\#' character will match any consecutive string
+ of decimal digits (0 - 9). 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] Determine the integer data type of an integer keyword value string.
+ The returned datatype value is the minimum integer datatype (starting
+ from top of the following list and working down) required
+ to store the integer value:
+\end{description}
+
+\begin{verbatim}
+ Data Type Range
+ TSBYTE: -128 to 127
+ TBYTE: 128 to 255
+ TSHORT: -32768 to 32767
+ TUSHORT: 32768 to 65535
+ TINT -2147483648 to 2147483647
+ TUINT 2147483648 to 4294967295
+ TLONGLONG -9223372036854775808 to 9223372036854775807
+\end{verbatim}
+
+\begin{description}
+\item[ ] The *neg parameter returns 1 if the input value is
+ negative and returns 0 if it is non-negative.\label{ffinttyp}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_inttype / ffinttyp
+ (char *value, > int *datatype, int *neg, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[14] 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 WCS keywords defined in the the WCS papers, including:
+ 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, DATE-OBS
+ 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[15] 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)
+
+ int fits_binary_tformll / ffbnfmll
+ (char *tform, > int *typecode, LONGLONG *repeat, long *width,
+ int *status)
+\end{verbatim}
+
+\begin{description}
+\item[16] 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[17] 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[18] 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.
+ If the value token is a character string that contains 1 or more
+ embedded blank space characters or slash ('/') characters then the
+ entire character string must be enclosed in single quotes.
+\end{description}
+
+
+\begin{description}
+\item[- ] The COMMENT token is optional, but if present must be separated from
+ the VALUE token by a blank space or 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[19] Translate a keyword name into a new name, based on a set of patterns.
+This routine is useful for translating keywords in cases such as
+adding or deleting columns in
+a table, or copying a column from one table to another, or extracting
+an array from a cell in a binary table column into an image extension. In
+these cases, it is necessary to translate the names of the keywords associated
+with the original table column(s) into the appropriate keyword name in the final
+file. For example, if column 2 is deleted from a table,
+then the value of 'n' in all the
+TFORMn and TTYPEn keywords for columns 3 and higher must be decremented
+by 1. Even more complex translations are sometimes needed to convert the
+WCS keywords when extracting an image out of a table column cell into
+a separate image extension.
+
+The user passes an array of patterns to be matched. Input pattern
+number i is pattern[i][0], and output pattern number i is
+pattern[i][1]. Keywords are matched against the input patterns. If a
+match is found then the keyword is re-written according to the output
+pattern.
+
+Order is important. The first match is accepted. The fastest match
+will be made when templates with the same first character are grouped
+together.
+
+Several characters have special meanings:
+
+\begin{verbatim}
+ i,j - single digits, preserved in output template
+ n - column number of one or more digits, preserved in output template
+ m - generic number of one or more digits, preserved in output template
+ a - coordinate designator, preserved in output template
+ # - number of one or more digits
+ ? - any character
+ * - only allowed in first character position, to match all
+ keywords; only useful as last pattern in the list
+\end{verbatim}
+i, j, n, and m are returned by the routine.
+
+For example, the input pattern "iCTYPn" will match "1CTYP5" (if n\_value
+is 5); the output pattern "CTYPEi" will be re-written as "CTYPE1".
+Notice that "i" is preserved.
+
+The following output patterns are special:
+
+ "-" - do not copy a keyword that matches the corresponding input pattern
+
+ "+" - copy the input unchanged
+
+The inrec string could be just the 8-char keyword name, or the entire
+80-char header record. Characters 9 - 80 in the input string simply get
+appended to the translated keyword name.
+
+If n\_range = 0, then only keywords with 'n' equal to n\_value will be
+considered as a pattern match. If n\_range = +1, then all values of
+'n' greater than or equal to n\_value will be a match, and if -1,
+then values of 'n' less than or equal to n\_value will match.\label{translatekey}
+\end{description}
+
+\begin{verbatim}
+int fits_translate_keyword(
+ char *inrec, /* I - input string */
+ char *outrec, /* O - output converted string, or */
+ /* a null string if input does not */
+ /* match any of the patterns */
+ char *patterns[][2],/* I - pointer to input / output string */
+ /* templates */
+ int npat, /* I - number of templates passed */
+ int n_value, /* I - base 'n' template value of interest */
+ int n_offset, /* I - offset to be applied to the 'n' */
+ /* value in the output string */
+ int n_range, /* I - controls range of 'n' template */
+ /* values of interest (-1,0, or +1) */
+ int *pat_num, /* O - matched pattern number (0 based) or -1 */
+ int *i, /* O - value of i, if any, else 0 */
+ int *j, /* O - value of j, if any, else 0 */
+ int *m, /* O - value of m, if any, else 0 */
+ int *n, /* O - value of n, if any, else 0 */
+ int *status) /* IO - error status */
+\end{verbatim}
+
+\begin{description}
+\item[ ] Here is an example of some of the patterns used to convert the keywords associated
+with an image in a cell of a table column into the keywords appropriate for
+an IMAGE extension:
+\end{description}
+
+\begin{verbatim}
+ char *patterns[][2] = {{"TSCALn", "BSCALE" }, /* Standard FITS keywords */
+ {"TZEROn", "BZERO" },
+ {"TUNITn", "BUNIT" },
+ {"TNULLn", "BLANK" },
+ {"TDMINn", "DATAMIN" },
+ {"TDMAXn", "DATAMAX" },
+ {"iCTYPn", "CTYPEi" }, /* Coordinate labels */
+ {"iCTYna", "CTYPEia" },
+ {"iCUNIn", "CUNITi" }, /* Coordinate units */
+ {"iCUNna", "CUNITia" },
+ {"iCRVLn", "CRVALi" }, /* WCS keywords */
+ {"iCRVna", "CRVALia" },
+ {"iCDLTn", "CDELTi" },
+ {"iCDEna", "CDELTia" },
+ {"iCRPXn", "CRPIXi" },
+ {"iCRPna", "CRPIXia" },
+ {"ijPCna", "PCi_ja" },
+ {"ijCDna", "CDi_ja" },
+ {"iVn_ma", "PVi_ma" },
+ {"iSn_ma", "PSi_ma" },
+ {"iCRDna", "CRDERia" },
+ {"iCSYna", "CSYERia" },
+ {"iCROTn", "CROTAi" },
+ {"WCAXna", "WCSAXESa"},
+ {"WCSNna", "WCSNAMEa"}};
+\end{verbatim}
+
+\begin{description}
+\item[20] Translate the keywords in the input HDU into the keywords that are
+appropriate for the output HDU. This is a driver routine that calls
+the previously described routine.
+\end{description}
+
+\begin{verbatim}
+int fits_translate_keywords(
+ fitsfile *infptr, /* I - pointer to input HDU */
+ fitsfile *outfptr, /* I - pointer to output HDU */
+ int firstkey, /* I - first HDU record number to start with */
+ char *patterns[][2],/* I - pointer to input / output keyword templates */
+ int npat, /* I - number of templates passed */
+ int n_value, /* I - base 'n' template value of interest */
+ int n_offset, /* I - offset to be applied to the 'n' */
+ /* value in the output string */
+ int n_range, /* I - controls range of 'n' template */
+ /* values of interest (-1,0, or +1) */
+ int *status) /* IO - error status */
+\end{verbatim}
+
+
+\begin{description}
+\item[21] 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, LONGLONG maxrows, int maxranges, >
+ int *numranges, long *rangemin, long *rangemax, int *status)
+
+ int fits_parse_rangell / ffrwrgll(char *rowlist, LONGLONG maxrows, int maxranges, >
+ int *numranges, LONGLONG *rangemin, LONGLONG *rangemax, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[22] 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[23] 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}
+
+\begin{description}
+\item[24] Estimate the root-mean-squared (RMS) noise in an image.
+These routines are mainly for use with the Hcompress image compression
+algorithm. They return an estimate of the RMS noise in the background
+pixels of the image. This robust algorithm (written by Richard
+White, STScI) first attempts to estimate the RMS value
+as 1.68 times the median of the absolute differences between successive
+pixels in the image. If the median = 0, then the
+algorithm falls back to computing the RMS of the difference between successive
+pixels, after several N-sigma rejection cycles to remove
+extreme values. The input parameters are: the array of image pixel values
+(either float or short values), the number of values in the array,
+the value that is used to represent null pixels (enter a very
+large number if there are no null pixels). \label{imageRMS}
+\end{description}
+
+\begin{verbatim}
+ int fits_rms_float (float fdata[], int npix, float in_null_value,
+ > double *rms, int *status)
+ int fits_rms_short (short fdata[], int npix, short in_null_value,
+ > double *rms, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[25] Was CFITSIO compiled with the -D\_REENTRANT directive
+so that it may be safely used in multi-threaded environments?
+The following function returns 1 if yes, 0 if no. Note, however,
+that even if the -D\_REENTRANT directive was specified, this does
+not guarantee that the CFITSIO routines are thread-safe, because
+some compilers may not support this feature.\label{reentrant}
+\end{description}
+
+\begin{verbatim}
+int fits_is_reentrant(void)
+\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 repeatedly 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{ World 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 a few 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 keywords contained in the FITS file headers.
+One convenient way to pass this information to the external 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., the 'wcspih' routine in the WCSLIB
+library and the 'astFitsChan' and 'astPutCards' functions in the 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.
+
+ There are 2 related routines: fits\_hdr2str simply concatenates all
+ the existing keywords in the header; fits\_convert\_hdr2str is similar,
+ except that if the CHDU is a tile compressed image (stored in a binary
+ table) then it will first convert that header back to that of a
+ normal FITS image before concatenating the keywords.
+
+ 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 **exclist parameter. \label{hdr2str}
+\end{description}
+
+\begin{verbatim}
+ int fits_hdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+
+ int fits_convert_hdr2str / ffcnvthdr2str
+ (fitsfile *fptr, int nocomments, char **exclist, int nexc,
+ > char **header, int *nkeys, int *status)
+\end{verbatim}
+
+
+\begin{description}
+\item[2 ] The following CFITSIO routine is specifically designed for use
+in conjunction with the WCSLIB library. It is not expected that
+applications programmers will call this routine directly, but it
+is documented here for completeness. This routine extracts arrays
+from a binary table that contain WCS information using the -TAB table
+lookup convention. See the documentation provided with the WCSLIB
+ library for more information. \label{wcstab}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_wcstab
+ (fitsfile *fptr, int nwtb, wtbarr *wtb, 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.
+
+ The first routine (ffgics) returns
+ the primary WCS, whereas the second routine returns the particular
+ version of the WCS specified by the 'version' parameter, which much
+ be a character ranging from 'A' to 'Z' (or a blank character, which is
+ equivalent to calling ffgics).
+
+ 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)
+
+ int fits_read_img_coord_version / ffgicsa
+ (fitsfile *fptr, char version, > 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://fits.gsfc.nasa.gov/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. Note that values of the memptr and memsize pointers will be updated
+by CFITSIO if the location or size of the FITS file in memory
+should change as a result of allocating more memory. \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. Note that values of the memptr and memsize pointers will be updated
+by CFITSIO if the location or size of the FITS file in memory
+should change as a result of allocating more memory. \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, namely:
+\begin{itemize}
+\item
+the file type (file://, ftp://, http://, etc),
+\item
+the base input file name,
+\item
+the name of the output file that the input file is to be copied to prior
+to opening,
+\item
+the HDU or extension specification,
+\item
+the filtering specifier,
+\item
+the binning specifier,
+\item
+the column specifier,
+\item
+and the
+image pixel filtering specifier.
+\end{itemize}
+A null pointer (0) may be be specified for any of the output string arguments
+that are not needed. Null strings will be returned for any components that are not
+present in the input file name. The calling routine must allocate sufficient
+memory to hold the returned character strings. Allocating the string lengths
+equal to FLEN\_FILENAME is guaranteed to be safe.
+These routines are mainly for internal use
+by other CFITSIO routines. \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)
+
+ int fits_parse_input_filename / ffifile
+ (char *filename, > char *filetype, char *infile, char *outfile, char
+ *extspec, char *filter, char *binspec, char *colspec, char *pixspec,
+ 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. The calling routine must allocate sufficient
+memory to hold the returned rootname character string. Allocating the length
+equal to FLEN\_FILENAME is guaranteed to be safe.
+ \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. \label{ffghad}
+\end{description}
+
+\begin{verbatim}
+ int fits_get_hduaddr / ffghad (only supports files up to 2.1 GB in size)
+ (fitsfile *fptr, > long *headstart, long *datastart, long *dataend,
+ int *status)
+
+ int fits_get_hduaddrll / ffghadll (supports large files)
+ (fitsfile *fptr, > LONGLONG *headstart, LONGLONG *datastart,
+ LONGLONG *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)
+
+ int fits_insert_imgll / ffiimgll
+ (fitsfile *fptr, int bitpix, int naxis, LONGLONG *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. Under normal circumstances,
+ the nrows
+ paramenter should have a value of 0; CFITSIO will automatically update
+ the number of rows as data is written to the table. 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, LONGLONG rowlen, LONGLONG nrows, int tfields, char *ttype[],
+ long *tbcol, char *tform[], char *tunit[], char *extname, > int *status)
+
+ int fits_insert_btbl / ffibin
+ (fitsfile *fptr, LONGLONG 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)
+
+ int fits_resize_imgll / ffrsimll
+ (fitsfile *fptr, int bitpix, int naxis, LONGLONG *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 ] Read or write a specified number of bytes starting at the specified byte
+ offset from the start of the extension data unit. These low
+ level routine are intended mainly for accessing the data in
+ non-standard, conforming extensions, and should not be used for standard
+ IMAGE, TABLE, or BINTABLE extensions. \label{ffgextn}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_ext / ffgextn
+ (fitsfile *fptr, LONGLONG offset, LONGLONG nbytes, void *buffer)
+ int fits_write_ext / ffpextn
+ (fitsfile *fptr, LONGLONG offset, LONGLONG nbytes, void *buffer)
+\end{verbatim}
+
+\begin{description}
+\item[8 ] 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 required extension header keywords into the CHU.
+ These routines are not required, and instead the appropriate
+ header may be constructed by writing each individual keyword in the
+ proper sequence.
+
+ 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. The general fits\_write\_exthdr routine
+ may be used to write the header of any conforming FITS
+ extension. \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_imghdrll / ffphpsll
+ (fitsfile *fptr, int bitpix, int naxis, LONGLONG *naxes, > int *status)
+
+ int fits_write_grphdr / ffphpr
+ (fitsfile *fptr, int simple, int bitpix, int naxis, long *naxes,
+ LONGLONG pcount, LONGLONG gcount, int extend, > int *status)
+
+ int fits_write_grphdrll / ffphprll
+ (fitsfile *fptr, int simple, int bitpix, int naxis, LONGLONG *naxes,
+ LONGLONG pcount, LONGLONG gcount, int extend, > int *status)
+
+ int fits_write_exthdr /ffphext
+ (fitsfile *fptr, char *xtension, int bitpix, int naxis, long *naxes,
+ LONGLONG pcount, LONGLONG gcount, > 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, LONGLONG rowlen, LONGLONG 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, LONGLONG nrows, int tfields, char **ttype,
+ char **tform, char **tunit, char *extname, LONGLONG 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_imghdrll / ffghprll
+ (fitsfile *fptr, int maxdim, > int *simple, int *bitpix, int *naxis,
+ LONGLONG *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, LONGLONG *tbcol, char **tform, char **tunit,
+ char *extname, int *status)
+
+ int fits_read_atblhdrll / ffghtbll
+ (fitsfile *fptr,int maxdim, > LONGLONG *rowlen, LONGLONG *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)
+
+ int fits_read_btblhdrll / ffghbnll
+ (fitsfile *fptr, int maxdim, > LONGLONG *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, > int *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 or
+ call fits_free_memory.
+
+ int fits_read_key_longstr / ffgkls
+ (fitsfile *fptr, char *keyname, > char **longstr, char *comment,
+ int *status)
+
+ int fits_free_memory / fffree
+ (char *longstr, int *status);
+
+ int fits_read_key_[log, lng, flt, dbl, cmp, dblcmp] / ffgky[ljedcm]
+ (fitsfile *fptr, char *keyname, > DTYPE *numval, char *comment,
+ int *status)
+
+ int fits_read_key_lnglng / ffgkyjj
+ (fitsfile *fptr, char *keyname, > LONGLONG *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, LONGLONG 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, LONGLONG 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 specifically
+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, LONGLONG firstelem, LONGLONG 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, LONGLONG firstelem, LONGLONG nelements,
+ DTYPE *array, > int *status);
+
+ int fits_write_imgnull / ffppn
+ (fitsfile *fptr, int datatype, LONGLONG firstelem, LONGLONG 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, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstelem, LONGLONG 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, LONGLONG dim1, LONGLONG naxis1,
+ LONGLONG 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, LONGLONG dim1, LONGLONG dim2, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG 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, LONGLONG dim1, LONGLONG naxis1,
+ LONGLONG 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, LONGLONG dim1,
+ LONGLONG dim2, LONGLONG naxis1, LONGLONG naxis2, LONGLONG 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)
+
+ int fits_get_bcolparmsll / ffgbclll
+ (fitsfile *fptr, int colnum, > char *ttype, char *tunit,
+ char *typechar, LONGLONG *repeat, double *scale, double *zero,
+ LONGLONG *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, > LONGLONG *heapsize, LONGLONG *unused, LONGLONG *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, LONGLONG firstrow, LONGLONG firstchar, LONGLONG nchars,
+ > unsigned char *values, int *status)
+
+ int fits_write_tblbytes / ffptbb
+ (fitsfile *fptr, LONGLONG firstrow, LONGLONG firstchar, LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG 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. \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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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. \label{ffpcns}
+\end{description}
+
+\begin{verbatim}
+ int fits_write_colnull_str / ffpcns
+ (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG 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, LONGLONG rownum, LONGLONG repeat,
+ LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG 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, LONGLONG firstrow, LONGLONG firstbit,
+ LONGLONG 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, LONGLONG firstrow, LONGLONG, 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 pair of routine returns a single descriptor whereas the second
+ pair of routine
+ returns the descriptors for a range of rows in the table. The only
+ difference between the 2 routines in each pair is that one returns
+ the parameters as 'long' integers, whereas the other returns the values
+ as 64-bit 'LONGLONG' integers.
+ \label{ffgdes}
+\end{description}
+
+\begin{verbatim}
+ int fits_read_descript / ffgdes
+ (fitsfile *fptr, int colnum, LONGLONG rownum, > long *repeat,
+ long *offset, int *status)
+
+ int fits_read_descriptll / ffgdesll
+ (fitsfile *fptr, int colnum, LONGLONG rownum, > LONGLONG *repeat,
+ LONGLONG *offset, int *status)
+
+ int fits_read_descripts / ffgdess
+ (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG nrows
+ > long *repeat, long *offset, int *status)
+
+ int fits_read_descriptsll / ffgdessll
+ (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG nrows
+ > LONGLONG *repeat, LONGLONG *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. See also the stream:// driver which provides a
+more efficient, but more restricted method of reading or writing to
+the stdin or stdout streams.
+
+\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][pixFilter]
+
+When opening an existing table HDU:
+ filetype://BaseFilename(outName)[HDUlocation][colFilter][rowFilter][binSpec]
+\end{verbatim}
+The filetype, BaseFilename, outName, HDUlocation, ImageSection, and pixFilter
+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
+ supports username:password just like the ftp driver.
+ Proxy HTTP servers are supported using the http_proxy
+ environment variable (see following note).
+ stream:// - special driver to read an input FITS file from the stdin
+ stream, and/or write an output FITS file to the stdout
+ stream. This driver is fragile and has limited
+ functionality (see the following note).
+ gsiftp:// - access files on a computational grid using the gridftp
+ protocol in the Globus toolkit (see following note).
+ root:// - uses the CERN root protocol for writing as well as
+ reading files over the network (see following note).
+ shmem:// - opens or creates a file which persists in the computer's
+ shared memory (see following note).
+ 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 stream filetype driver}
+
+The stream driver can be used to efficiently read a FITS file from the stdin
+file stream or write a FITS to the stdout file stream. However, because these
+input and output streams must be accessed sequentially, the FITS file reading or
+writing application must also read and write the file sequentially, at least
+within the tolerances described below.
+
+CFITSIO supports 2 different methods for accessing FITS files on the stdin and
+stdout streams. The original method, which is invoked by specifying a dash
+character, "-", as the name of the file when opening or creating it, works by
+storing a complete copy of the entire FITS file in memory. In this case, when
+reading from stdin, CFITSIO will copy the entire stream into memory before doing
+any processing of the file. Similarly, when writing to stdout, CFITSIO will
+create a copy of the entire FITS file in memory, before finally flushing it out
+to the stdout stream when the FITS file is closed. Buffering the entire FITS
+file in this way allows the application to randomly access any part of the FITS
+file, in any order, but it also requires that the user have sufficient available
+memory (or virtual memory) to store the entire file, which may not be possible
+in the case of very large files.
+
+The newer stream filetype provides a more memory-efficient method of accessing
+FITS files on the stdin or stdout streams. Instead of storing a copy of the
+entire FITS file in memory, CFITSIO only uses a set of internal buffer which by
+default can store 40 FITS blocks, or about 100K bytes of the FITS file. The
+application program must process the FITS file sequentially from beginning to
+end, within this 100K buffer. Generally speaking the application program must
+conform to the following restrictions:
+
+\begin{itemize}
+\item
+The program must finish reading or writing the header keywords
+before reading or writing any data in the HDU.
+\item
+The HDU can contain at most about 1400 header keywords. This is the
+maximum that can fit in the nominal 40 FITS block buffer. In principle,
+this limit could be increased by recompiling CFITSIO with a larger
+buffer limit, which is set by the NIOBUF parameter in fitsio2.h.
+\item
+The program must read or write the data in a sequential manner from the
+beginning to the end of the HDU. Note that CFITSIO's internal
+100K buffer allows a little latitude in meeting this requirement.
+\item
+The program cannot move back to a previous HDU in the FITS file.
+\item
+Reading or writing of variable length array columns in binary tables is not
+supported on streams, because this requires moving back and forth between the
+fixed-length portion of the binary table and the following heap area where the
+arrays are actually stored.
+\item
+Reading or writing of tile-compressed images is not supported on streams,
+because the images are internally stored using variable length arrays.
+\end{itemize}
+
+
+\subsection{Notes about the gsiftp filetype}
+
+DEPENDENCIES: Globus toolkit (2.4.3 or higher) (GT) should be installed.
+There are two different ways to install GT:
+
+1) goto the globus toolkit web page www.globus.org and follow the
+ download and compilation instructions;
+
+2) goto the Virtual Data Toolkit web page http://vdt.cs.wisc.edu/
+ and follow the instructions (STRONGLY SUGGESTED);
+
+Once a globus client has been installed in your system with a specific flavour
+it is possible to compile and install the CFITSIO libraries.
+Specific configuration flags must be used:
+
+1) --with-gsiftp[[=PATH]] Enable Globus Toolkit gsiftp protocol support
+ PATH=GLOBUS\_LOCATION i.e. the location of your globus installation
+
+2) --with-gsiftp-flavour[[=PATH] defines the specific Globus flavour
+ ex. gcc32
+
+Both the flags must be used and it is mandatory to set both the PATH and the
+flavour.
+
+USAGE: To access files on a gridftp server it is necessary to use a gsiftp prefix:
+
+example: gsiftp://remote\_server\_fqhn/directory/filename
+
+The gridftp driver uses a local buffer on a temporary file the file is located
+in the /tmp directory. If you have special permissions on /tmp or you do not have a /tmp
+directory, it is possible to force another location setting the GSIFTP\_TMPFILE environment
+variable (ex. export GSIFTP\_TMPFILE=/your/location/yourtmpfile).
+
+Grid FTP supports multi channel transfer. By default a single channel transmission is
+available. However, it is possible to modify this behavior setting the GSIFTP\_STREAMS
+environment variable (ex. export GSIFTP\_STREAMS=8).
+
+
+
+\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.
+
+An optional pound sign character ("\#") may be appended to the extension
+name or number to signify that any other extensions in the file should
+be ignored during any subsequent file filtering operations. For example,
+when doing row filtering operations on a table extension, CFITSIO normally
+creates a copy of the filtered table in memory, along with a verbatim
+copy of all the other extensions in the input FITS file. If the pound
+sign is appended to the table extension name, then only that extension,
+and none of the other extensions in the file, will by copied to memory,
+as in the following example:
+
+\begin{verbatim}
+ myfile.fit[events#][TIME > 10000]
+\end{verbatim}
+
+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. (If a `\#' character is appended to the name or number of the
+image HDU, as in "myfile.fits[1\#][1:200,1:200]", then the other
+HDUs in the input file will not be copied into memory).
+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{Image Transform Filters}
+
+CFITSIO can apply a user-specified mathematical function to the value
+of every pixel in a FITS image, thus creating a new virtual image
+in computer memory that is then opened and read by the application
+program. The original FITS image is not modified by this process.
+
+The image transformation specifier is appended to the input
+FITS file name and is enclosed in square brackets. It begins with the
+letters 'PIX' to distinguish it from other types of FITS file filters
+that are recognized by CFITSIO. The image transforming function may
+use any of the mathematical operators listed in the following
+'Row Filtering Specification' section of this document.
+Some examples of image transform filters are:
+
+\begin{verbatim}
+ [pix X * 2.0] - multiply each pixel by 2.0
+ [pix sqrt(X)] - take the square root of each pixel
+ [pix X + #ZEROPT - add the value of the ZEROPT keyword
+ [pix X>0 ? log10(X) : -99.] - if the pixel value is greater
+ than 0, compute the base 10 log,
+ else set the pixel = -99.
+\end{verbatim}
+Use the letter 'X' in the expression to represent the current pixel value
+in the image. The expression is evaluated
+independently for each pixel in the image and may be a function of 1) the
+original pixel value, 2) the value of other pixels in the image at
+a given relative offset from the position of the pixel that is being
+evaluated, and 3) the value of
+any header keywords. Header keyword values are represented
+by the name of the keyword preceded by the '\#' sign.
+
+
+To access the the value of adjacent pixels in the image,
+specify the (1-D) offset from the current pixel in curly brackets.
+For example
+
+\begin{verbatim}
+ [pix (x{-1} + x + x{+1}) / 3]
+\end{verbatim}
+will replace each pixel value with the running mean of the values of that
+pixel and it's 2 neighboring pixels. Note that in this notation the image
+is treated as a 1-D array, where each row of the image (or higher dimensional
+cube) is appended one after another in one long array of pixels.
+It is possible to refer to pixels
+in the rows above or below the current pixel by using the value of the
+NAXIS1 header keyword. For example
+
+\begin{verbatim}
+ [pix (x{-#NAXIS1} + x + x{#NAXIS1}) / 3]
+\end{verbatim}
+will compute the mean of each image pixel and the pixels immediately
+above and below it in the adjacent rows of the image.
+The following more complex example
+creates a smoothed virtual image where each pixel
+is a 3 x 3 boxcar average of the input image pixels:
+
+\begin{verbatim}
+ [pix (X + X{-1} + X{+1}
+ + X{-#NAXIS1} + X{-#NAXIS1 - 1} + X{-#NAXIS1 + 1}
+ + X{#NAXIS1} + X{#NAXIS1 - 1} + X{#NAXIS1 + 1}) / 9.]
+\end{verbatim}
+If the pixel offset
+extends beyond the first or last pixel in the image, the function will
+evaluate to undefined, or NULL.
+
+For complex or commonly used image filtering operations,
+one can write the expression into an external text file and
+then import it into the
+filter using the syntax '[pix @filename.txt]'. The mathematical
+expression can
+extend over multiple lines of text in 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.
+
+By default, the datatype of the resulting image will be the same as
+the original image, but one may force a different datatype by appended
+a code letter to the 'pix' keyword:
+
+\begin{verbatim}
+ pixb - 8-bit byte image with BITPIX = 8
+ pixi - 16-bit integer image with BITPIX = 16
+ pixj - 32-bit integer image with BITPIX = 32
+ pixr - 32-bit float image with BITPIX = -32
+ pixd - 64-bit float image with BITPIX = -64
+\end{verbatim}
+Also by default, any other HDUs in the input file will be copied without
+change to the
+output virtual FITS file, but one may discard the other HDUs by adding
+the number '1' to the 'pix' keyword (and following any optional datatype code
+letter). For example:
+
+\begin{verbatim}
+ myfile.fits[3][pixr1 sqrt(X)]
+\end{verbatim}
+will create a virtual FITS file containing only a primary array image
+with 32-bit floating point pixels that have a value equal to the square
+root of the pixels in the image that is in the 3rd extension
+of the 'myfile.fits' file.
+
+
+
+\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. (If a `\#' character is appended to the name
+or number of the
+table HDU then only the primary array, and none of the other
+HDUs in the input file will be copied into memory).
+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 commas or 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). If the keyword name ends with a
+pound sign '\#', then cfitsio will substitute the number of the
+most recently referenced column for the \# character .
+This is especially useful when writing
+a column-related keyword like TUNITn for a newly created column,
+as shown in the following examples.
+
+\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. If no columns to be deleted are specified, then only the
+columns that are explicitly listed will be included in the filtered
+output table. To include all the columns, add the '*' wildcard
+specifier at the end of the list, as shown in the examples.
+
+For complex or commonly used operations, one can 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; #TUNIT#(column units) = 'counts';*]
+ - creates new PI column from PHA values
+ and also writes the TUNITn keyword
+ for the new column. The final '*'
+ expression means preserve all the
+ columns in the input table in the
+ virtual output table; without the '*'
+ the output table would only contain
+ the single 'PI' column.
+
+ [col rate = rate/exposure; TUNIT#(&) = 'counts/s';*]
+ - recomputes the rate column by dividing
+ it by the EXPOSURE keyword value. This
+ also modifies the value of the TUNITn
+ keyword for this column. The use of the
+ '&' character for the keyword comment
+ string means preserve the existing
+ comment string for that keyword. The
+ final '*' preserves all the columns
+ in the input table in the virtual
+ output table.
+\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.
+(If a `\#' character is appended to the name
+or number of the
+table HDU then only the primary array, and none of the other
+HDUs in the input file will be copied into 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 enclose 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(y,x)
+ "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" x % y "random # [0.0,1.0)" random()
+ "random Gaussian" randomn() "random Poisson" randomp(x)
+ "minimum" min(x,y) "maximum" max(x,y)
+ "cumulative sum" accum(x) "sequential difference" seqdiff(x)
+ "if-then-else" b?x:y
+ "angular separation" angsep(ra1,dec1,ra2,de2) (all in degrees)
+ "substring" strmid(s,p,n) "string search" strstr(s,r)
+\end{verbatim}
+Three different random number functions are provided: random(), with
+no arguments, produces a uniform random deviate between 0 and 1;
+randomn(), also with no arguments, produces a normal (Gaussian) random
+deviate with zero mean and unit standard deviation; randomp(x)
+produces a Poisson random deviate whose expected number of counts is
+X. X may be any positive real number of expected counts, including
+fractional values, but the return value is an integer.
+
+When the random functions are used in a vector expression, by default
+the same random value will be used when evaluating each element of the vector.
+If different random numbers are desired, then the name of a vector
+column should be supplied as the single argument to the random
+function (e.g., "flux + 0.1 * random(flux)", where "flux' is the
+name of a vector column). This will create a vector of
+random numbers that will be used in sequence when evaluating each
+element of the vector expression.
+
+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.
+
+In the if-then-else expression, "b?x:y", b is an explicit boolean
+value or expression. There is no automatic type conversion from
+numeric to boolean values, so one needs to use "iVal!=0" instead of
+merely "iVal" as the boolean argument. x and y can be any scalar data
+type (including string).
+
+The angsep function computes the angular separation in degrees
+between 2 celestial positions, where the first 2 parameters
+give the RA-like and Dec-like coordinates (in decimal degrees)
+of the first position, and the 3rd and 4th parameters give the
+coordinates of the second position.
+
+The substring function strmid(S,P,N) extracts a substring from S,
+starting at string position P, with a substring length N. The first
+character position in S is labeled as 1. If P is 0, or refers to a
+position beyond the end of S, then the extracted substring will be
+NULL. S, P, and N may be functions of other columns.
+
+The string search function strstr(S,R) searches for the first occurrence
+of the substring R in S. The result is an integer, indicating the
+character position of the first match (where 1 is the first character
+position of S). If no match is found, then strstr() returns a NULL
+value.
+
+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.
+
+ 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)
+ "summation" 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 STDDEV() function computes the sample
+ standard deviation, i.e. it is proportional to 1/SQRT(N-1) instead
+ of 1/SQRT(N), where N is NVALID(V).
+
+ 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. There are 2 supported formats for the
+ region file: ASCII file or FITS binary table. The region file
+ 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. The FITS region file format is defined in a document
+ available from the FITS Support Office at
+ http://fits.gsfc.nasa.gov/ registry/ region.html
+
+ In its simplest 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 low-level functions that are primarily for use with
+ regfilter function, but they can be called directly. They
+ return a boolean true or false depending on whether a two
+ dimensional point is in the region or not. The positional coordinates
+ must be given in pixel units:
+
+\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 supports reading and writing FITS images or table columns containing
+64-bit integer data values. Support for 64-bit integers was added to the
+official FITS Standard in December 2005.
+ FITS 64-bit images have BITPIX =
+64, and the 64-bit binary table columns have TFORMn = 'K'. CFITSIO also
+supports the 'Q' variable-length array table column format which is
+analogous to the 'P' column format except that the array descriptor
+is stored as a pair of 64-bit integers.
+
+For the convenience of C programmers, the fitsio.h include file
+defines (with a typedef statement) the 'LONGLONG' datatype to be
+equivalent to an appropriate 64-bit integer datatype on each platform.
+Since there is currently no universal standard
+for the name of the 64-bit integer datatype (it might be defined as
+'long long', 'long', or '\_\_int64' depending on the platform)
+C programmers may prefer to use the 'LONGLONG' datatype when
+declaring or allocating 64-bit integer quantities when writing
+code which needs to run on multiple platforms.
+Note that CFITSIO will implicitly convert the datatype when reading
+or writing FITS 64-bit integer images and columns with data arrays of
+a different integer or floating point datatype, but there is an
+increased risk of loss of numerical precision or
+numerical overflow in this case.
+
+
+\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}
+
+CFITSIO supports 2 ways to specify that a character column in a binary
+table contains an array of fixed-length strings. The first way, which
+is officially supported by the FITS Standard document, uses the TDIMn keyword.
+For example, if TFORMn = '60A' and TDIMn = '(12,5)' then that
+column will be interpreted as containing an array of 5 strings, each 12
+characters long.
+
+CFITSIO also supports 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 (except the default with the HCOMPRESS algorithm is to
+compress the whole 2D image as a single tile). 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. Because the data in FITS files is always stored in "big-endian" byte order,
+where the first byte of numeric values contains the most significant bits and the
+last byte contains the least significant bits, CFITSIO must swap the order of the bytes
+when reading or writing FITS files when running on little-endian machines (e.g.,
+Linux and Microsoft Windows operating systems running on PCs with x86 CPUs).
+
+On fairly new CPUs that support "SSSE3" machine instructions
+(e.g., starting with Intel Core 2 CPUs in 2007, and in AMD CPUs
+beginning in 2011) significantly faster 4-byte and 8-byte swapping
+algorithms are available. These faster byte swapping functions are
+not used by default in CFITSIO (because of the potential code
+portablility issues), but users can enable them on supported
+platforms by adding the appropriate compiler flags (-mssse3 with gcc
+or icc on linux) when compiling the swapproc.c source file, which will
+allow the compiler to generate code using the SSSE3 instruction set.
+A convenient way to do this is to configure the CFITSIO library
+with the following command:
+
+\begin{verbatim}
+ > ./configure --enable-ssse3
+\end{verbatim}
+Note, however, that a binary executable file that is
+created using these faster functions will only run on
+machines that support the SSSE3 machine instructions. It will
+crash on machines that do not support them.
+
+For faster 2-byte swaps on virtually all x86-64 CPUs (even those that
+do not support SSSE3), a variant using only SSE2 instructions exists.
+SSE2 is enabled by default on x86\_64 CPUs with 64-bit operating systems
+(and is also automatically enabled by the --enable-ssse3 flag).
+When running on x86\_64 CPUs with 32-bit operating systems, these faster
+2-byte swapping algorithms are not used by default in CFITSIO, but can be
+enabled explicitly with:
+
+\begin{verbatim}
+./configure --enable-sse2
+\end{verbatim}
+Preliminary testing indicates that these SSSE3 and SSE2 based
+byte-swapping algorithms can boost the CFITSIO performance when
+reading or writing FITS images by 20\% - 30\% or more.
+It is important to note, however, that compiler optimization must be
+turned on (e.g., by using the -O1 or -O2 flags in gcc) when building
+programs that use these fast byte-swapping algorithms in order
+to reap the full benefit of the SSSE3 and SSE2 instructions; without
+optimization, the code may actually run slower than when using
+more traditional byte-swapping techniques.
+
+2. 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.
+
+3. 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 and on the number of IO
+buffers that have been allocated in CFITSIO. 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 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.
+
+4. 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.
+
+5. 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 that have the same information content.
+
+6. 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 relatively fast and it makes
+little difference which order they are accessed.
+
+7. 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.
+
+8. 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.
+
+9. 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.
+
+10. 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. In practice, this is probably not a significant efficiency issue.
+
+11. 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.
+
+12. 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?).
+
+13. Finally, external factors such as the speed of the data storage device,
+the size of the data cache, 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, the entire hardware
+and software system should be reviewed 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\_binning & \pageref{calcbinning} \\
+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\_convert\_hdr2str & \pageref{ffhdr2str}, \pageref{hdr2str} \\
+fits\_copy\_cell2image & \pageref{copycell} \\
+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\_image2cell & \pageref{copycell} \\
+fits\_copy\_image\_section & \pageref{ffcpimg} \\
+fits\_copy\_key & \pageref{ffcpky} \\
+fits\_copy\_member & \pageref{ffgmcp} \\
+fits\_copy\_pixlist2image & \pageref{copypixlist2image} \\
+fits\_copy\_rows & \pageref{ffcprw} \\
+fits\_create\_diskfile & \pageref{ffinit} \\
+fits\_create\_file & \pageref{ffinit} \\
+fits\_create\_group & \pageref{ffgtcr} \\
+fits\_create\_hdu & \pageref{ffcrhd} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+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} \\
+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\_delete\_str & \pageref{ffdkey} \\
+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\_free\_memory & \pageref{ffgkls} \\
+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} \\
+\end{tabular}
+\begin{tabular}{lr}
+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} \\
+fits\_get\_hduaddrll & \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\_inttype & \pageref{ffinttyp} \\
+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} \\
+\end{tabular}
+\newpage
+\begin{tabular}{lr}
+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\_is\_reentrant & \pageref{reentrant} \\
+fits\_iterate\_data & \pageref{ffiter} \\
+fits\_make\_hist & \pageref{makehist} \\
+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\_filename & \pageref{ffiurl} \\
+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} \\
+\end{tabular}
+\begin{tabular}{lr}
+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\_ext & \pageref{ffgextn} \\
+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} \\
+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\_str & \pageref{ffgcrd} \\
+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\_read\_wcstab & \pageref{wcstab} \\
+fits\_rebin\_wcs & \pageref{rebinwcs} \\
+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\_rms\_float & \pageref{imageRMS} \\
+fits\_rms\_short & \pageref{imageRMS} \\
+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} \\
+\end{tabular}
+\begin{tabular}{lr}
+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\_translate\_keyword & \pageref{translatekey} \\
+fits\_update\_card & \pageref{ffucrd} \\
+fits\_update\_chksum & \pageref{ffupck} \\
+fits\_update\_key & \pageref{ffuky} \\
+fits\_update\_key\_longstr & \pageref{ffukyx} \\
+fits\_update\_key\_null & \pageref{ffukyu} \\
+fits\_update\_key\_TYP & \pageref{ffukyx} \\
+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\_ext & \pageref{ffgextn} \\
+fits\_write\_exthdr & \pageref{ffphps} \\
+fits\_write\_grphdr & \pageref{ffphpr} \\
+fits\_write\_grppar\_TYP & \pageref{ffpgpx} \\
+fits\_write\_hdu & \pageref{ffwrhdu} \\
+fits\_write\_history & \pageref{ffphis} \\
+fits\_write\_img & \pageref{ffppr} \\
+\end{tabular}
+\newpage
+\begin{tabular}{lr}
+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\_keys\_histo & \pageref{writekeyshisto} \\
+fits\_write\_null\_img & \pageref{ffpprn} \\
+fits\_write\_nullrows & \pageref{ffpclu} \\
+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} \\
+ffcpimg & \pageref{ffcpimg} \\
+ffcpky & \pageref{ffcpky} \\
+ffcprw & \pageref{ffcprw} \\
+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} \\
+ffdstr & \pageref{ffdkey} \\
+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} \\
+fffree & \pageref{ffgkls} \\
+fffrow & \pageref{fffrow} \\
+\end{tabular}
+\begin{tabular}{lr}
+ffg2d\_ & \pageref{ffg2dx} \\
+ffg3d\_ & \pageref{ffg3dx} \\
+ffgabc & \pageref{ffgabc} \\
+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} \\
+ffgextn & \pageref{ffgextn} \\
+ffggp\_ & \pageref{ffggpx} \\
+ffghad & \pageref{ffghad} \\
+ffghbn & \pageref{ffghbn} \\
+ffghdn & \pageref{ffghdn} \\
+ffghdt & \pageref{ffghdt} \\
+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} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+ffgmtf & \pageref{ffgmtf} \\
+ffgncl & \pageref{ffgnrw} \\
+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} \\
+ffgstr & \pageref{ffgcrd} \\
+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} \\
+ffifile & \pageref{ffiurl} \\
+ffiimg & \pageref{ffiimg} \\
+ffikls & \pageref{ffikyx} \\
+ffikyu & \pageref{ffikyu} \\
+ffiky\_ & \pageref{ffikyx} \\
+ffimem & \pageref{ffimem} \\
+ffinit & \pageref{ffinit} \\
+ffinttyp & \pageref{ffinttyp} \\
+ffiopn & \pageref{ffopen} \\
+ffirec & \pageref{ffirec} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+
+ffirow & \pageref{ffirow} \\
+ffitab & \pageref{ffitab} \\
+ffiter & \pageref{ffiter} \\
+ffiurl & \pageref{ffiurl} \\
+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} \\
+ffpextn & \pageref{ffgextn} \\
+ffpgp\_ & \pageref{ffpgpx} \\
+ffphbn & \pageref{ffphbn} \\
+ffphext & \pageref{ffphpr} \\
+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} \\
+
+\end{tabular}
+\begin{tabular}{lr}
+
+ffpmrk & \pageref{ffpmrk} \\
+ffpmsg & \pageref{ffpmsg} \\
+ffpnul & \pageref{ffpnul} \\
+ffppn & \pageref{ffppn} \\
+ffppn\_ & \pageref{ffppnx} \\
+ffppr & \pageref{ffppr} \\
+ffpprn & \pageref{ffpprn} \\
+ffppru & \pageref{ffppru} \\
+ffppr\_ & \pageref{ffpprx} \\
+ffppx & \pageref{ffppx} \\
+ffppxn & \pageref{ffppxn} \\
+ffprec & \pageref{ffprec} \\
+ffprwu & \pageref{ffpclu} \\
+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} \\
+
+\end{tabular}
+\newpage
+\begin{tabular}{lr}
+
+ffurlt & \pageref{ffurlt} \\
+ffvcks & \pageref{ffvcks} \\
+ffvers & \pageref{ffvers} \\
+ffwldp & \pageref{ffwldp} \\
+ffwrhdu & \pageref{ffwrhdu} \\
+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, HCOMPRESS_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 - HDU type: IMAGE_HDU (0), ASCII_TBL (1), BINARY_TBL (2), ANY_HDU (-1)
+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
+nbytes - number of bytes or characters to read or write
+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 or data unit 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!)
+section - section of image to be copied (e.g. 21:80,101:200)
+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 (same as TLONG)
+ long long integer, K 81 TLONGLONG
+ real, E 42 TFLOAT
+ double precision, D 82 TDOUBLE
+ complex, C 83 TCOMPLEX
+ double complex, M 163 TDBLCOMPLEX
+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_INDEX_KEY 206 illegal indexed keyword name (e.g. 'TFORM1000')
+ 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/vendor/cfitsio/cfitsio.toc b/vendor/cfitsio/cfitsio.toc
new file mode 100644
index 00000000..c09a3382
--- /dev/null
+++ b/vendor/cfitsio/cfitsio.toc
@@ -0,0 +1,123 @@
+\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}Acknowledgments}{2}
+\contentsline {section}{\numberline {1.4}Legal Stuff}{4}
+\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}Using CFITSIO in Multi-threaded Environments}{9}
+\contentsline {section}{\numberline {2.5}Getting Started with CFITSIO}{10}
+\contentsline {section}{\numberline {2.6}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}{20}
+\contentsline {section}{\numberline {4.5}Dealing with Character Strings}{22}
+\contentsline {section}{\numberline {4.6}Implicit Data Type Conversion}{23}
+\contentsline {section}{\numberline {4.7}Data Scaling}{23}
+\contentsline {section}{\numberline {4.8}Support for IEEE Special Values}{24}
+\contentsline {section}{\numberline {4.9}Error Status Values and the Error Message Stack}{24}
+\contentsline {section}{\numberline {4.10}Variable-Length Arrays in Binary Tables}{25}
+\contentsline {section}{\numberline {4.11}Multiple Access to the Same FITS File}{26}
+\contentsline {section}{\numberline {4.12}When the Final Size of the FITS HDU is Unknown}{27}
+\contentsline {section}{\numberline {4.13}CFITSIO Size Limitations}{27}
+\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}{38}
+\contentsline {section}{\numberline {5.5}Primary Array or IMAGE Extension I/O Routines}{40}
+\contentsline {section}{\numberline {5.6}Image Compression}{44}
+\contentsline {section}{\numberline {5.7}ASCII and Binary Table Routines}{48}
+\contentsline {subsection}{\numberline {5.7.1}Create New Table}{48}
+\contentsline {subsection}{\numberline {5.7.2}Column Information Routines}{49}
+\contentsline {subsection}{\numberline {5.7.3}Routines to Edit Rows or Columns}{52}
+\contentsline {subsection}{\numberline {5.7.4}Read and Write Column Data Routines}{53}
+\contentsline {subsection}{\numberline {5.7.5}Row Selection and Calculator Routines}{56}
+\contentsline {subsection}{\numberline {5.7.6}Column Binning or Histogramming Routines}{57}
+\contentsline {section}{\numberline {5.8}Utility Routines}{60}
+\contentsline {subsection}{\numberline {5.8.1}File Checksum Routines}{60}
+\contentsline {subsection}{\numberline {5.8.2}Date and Time Utility Routines}{61}
+\contentsline {subsection}{\numberline {5.8.3}General Utility Routines}{62}
+\contentsline {chapter}{\numberline {6} The CFITSIO Iterator Function }{73}
+\contentsline {section}{\numberline {6.1}The Iterator Work Function}{74}
+\contentsline {section}{\numberline {6.2}The Iterator Driver Function}{76}
+\contentsline {section}{\numberline {6.3}Guidelines for Using the Iterator Function}{77}
+\contentsline {section}{\numberline {6.4}Complete List of Iterator Routines}{78}
+\contentsline {chapter}{\numberline {7} World Coordinate System Routines }{81}
+\contentsline {section}{\numberline {7.1} Self-contained WCS Routines}{82}
+\contentsline {chapter}{\numberline {8} Hierarchical Grouping Routines }{85}
+\contentsline {section}{\numberline {8.1}Grouping Table Routines}{86}
+\contentsline {section}{\numberline {8.2}Group Member Routines}{88}
+\contentsline {chapter}{\numberline {9} Specialized CFITSIO Interface Routines }{91}
+\contentsline {section}{\numberline {9.1}FITS File Access Routines}{91}
+\contentsline {section}{\numberline {9.2}HDU Access Routines}{95}
+\contentsline {section}{\numberline {9.3}Specialized Header Keyword Routines}{97}
+\contentsline {subsection}{\numberline {9.3.1}Header Information Routines}{97}
+\contentsline {subsection}{\numberline {9.3.2}Read and Write the Required Keywords}{97}
+\contentsline {subsection}{\numberline {9.3.3}Write Keyword Routines}{99}
+\contentsline {subsection}{\numberline {9.3.4}Insert Keyword Routines}{101}
+\contentsline {subsection}{\numberline {9.3.5}Read Keyword Routines}{102}
+\contentsline {subsection}{\numberline {9.3.6}Modify Keyword Routines}{104}
+\contentsline {subsection}{\numberline {9.3.7}Update Keyword Routines}{105}
+\contentsline {section}{\numberline {9.4}Define Data Scaling and Undefined Pixel Parameters}{106}
+\contentsline {section}{\numberline {9.5}Specialized FITS Primary Array or IMAGE Extension I/O Routines}{107}
+\contentsline {section}{\numberline {9.6}Specialized FITS ASCII and Binary Table Routines}{110}
+\contentsline {subsection}{\numberline {9.6.1}General Column Routines}{110}
+\contentsline {subsection}{\numberline {9.6.2}Low-Level Table Access Routines}{112}
+\contentsline {subsection}{\numberline {9.6.3}Write Column Data Routines}{112}
+\contentsline {subsection}{\numberline {9.6.4}Read Column Data Routines}{113}
+\contentsline {chapter}{\numberline {10} Extended File Name Syntax }{117}
+\contentsline {section}{\numberline {10.1}Overview}{117}
+\contentsline {section}{\numberline {10.2}Filetype}{120}
+\contentsline {subsection}{\numberline {10.2.1}Notes about HTTP proxy servers}{120}
+\contentsline {subsection}{\numberline {10.2.2}Notes about the stream filetype driver}{121}
+\contentsline {subsection}{\numberline {10.2.3}Notes about the gsiftp filetype}{122}
+\contentsline {subsection}{\numberline {10.2.4}Notes about the root filetype}{122}
+\contentsline {subsection}{\numberline {10.2.5}Notes about the shmem filetype:}{124}
+\contentsline {section}{\numberline {10.3}Base Filename}{124}
+\contentsline {section}{\numberline {10.4}Output File Name when Opening an Existing File}{126}
+\contentsline {section}{\numberline {10.5}Template File Name when Creating a New File}{128}
+\contentsline {section}{\numberline {10.6}Image Tile-Compression Specification}{128}
+\contentsline {section}{\numberline {10.7}HDU Location Specification}{128}
+\contentsline {section}{\numberline {10.8}Image Section}{130}
+\contentsline {section}{\numberline {10.9}Image Transform Filters}{131}
+\contentsline {section}{\numberline {10.10}Column and Keyword Filtering Specification}{132}
+\contentsline {section}{\numberline {10.11}Row Filtering Specification}{134}
+\contentsline {subsection}{\numberline {10.11.1}General Syntax}{135}
+\contentsline {subsection}{\numberline {10.11.2}Bit Masks}{138}
+\contentsline {subsection}{\numberline {10.11.3}Vector Columns}{138}
+\contentsline {subsection}{\numberline {10.11.4}Good Time Interval Filtering}{140}
+\contentsline {subsection}{\numberline {10.11.5}Spatial Region Filtering}{141}
+\contentsline {subsection}{\numberline {10.11.6}Example Row Filters}{143}
+\contentsline {section}{\numberline {10.12} Binning or Histogramming Specification}{144}
+\contentsline {chapter}{\numberline {11}Template Files }{147}
+\contentsline {section}{\numberline {11.1}Detailed Template Line Format}{147}
+\contentsline {section}{\numberline {11.2}Auto-indexing of Keywords}{148}
+\contentsline {section}{\numberline {11.3}Template Parser Directives}{149}
+\contentsline {section}{\numberline {11.4}Formal Template Syntax}{149}
+\contentsline {section}{\numberline {11.5}Errors}{150}
+\contentsline {section}{\numberline {11.6}Examples}{150}
+\contentsline {chapter}{\numberline {12} Local FITS Conventions }{153}
+\contentsline {section}{\numberline {12.1}64-Bit Long Integers}{153}
+\contentsline {section}{\numberline {12.2}Long String Keyword Values.}{153}
+\contentsline {section}{\numberline {12.3}Arrays of Fixed-Length Strings in Binary Tables}{155}
+\contentsline {section}{\numberline {12.4}Keyword Units Strings}{155}
+\contentsline {section}{\numberline {12.5}HIERARCH Convention for Extended Keyword Names}{156}
+\contentsline {section}{\numberline {12.6}Tile-Compressed Image Format}{156}
+\contentsline {chapter}{\numberline {13} Optimizing Programs }{159}
+\contentsline {section}{\numberline {13.1}How CFITSIO Manages Data I/O}{159}
+\contentsline {section}{\numberline {13.2}Optimization Strategies}{160}
+\contentsline {chapter}{\numberline {A}Index of Routines }{165}
+\contentsline {chapter}{\numberline {B}Parameter Definitions }{171}
+\contentsline {chapter}{\numberline {C}CFITSIO Error Status Codes }{177}
diff --git a/vendor/cfitsio/cfitsio_mac.sit.hqx b/vendor/cfitsio/cfitsio_mac.sit.hqx
new file mode 100644
index 00000000..0a3dbdfb
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/cfortran.doc b/vendor/cfitsio/cfortran.doc
new file mode 100644
index 00000000..f2230b01
--- /dev/null
+++ b/vendor/cfitsio/cfortran.doc
@@ -0,0 +1,2088 @@
+/* cfortran.doc 4.3 */
+/* www-zeus.desy.de/~burow OR anonymous ftp@zebra.desy.de */
+/* Burkhard Burow burow@desy.de 1990 - 1998. */
+
+See Licensing information at the end of this file.
+
+
+ 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.
+
+============================================================================
+
+ADDITIONAL LICENSING INFORMATION (added by W D Pence on 4 October 2007)
+
+The author of cfortran has subsequently stated that cfortran.h may optionally
+be used and distributed under the GNU Library General Public License (LGPL).
+This statement was made in an email to Kevin McCarty, which is reproduced below:
+
+----------------------------------------
+Date: Tue, 22 Oct 2002 12:48:00 -0400
+From: Burkhard D Steinmacher-burow <steinmac@us.ibm.com>
+To: Kevin B. McCarty <kmccarty@Princeton.EDU>
+Subject: Re: CFortran licensing question
+
+Kevin,
+
+[Just noticed that I didn't send this yesterady.]
+
+I have no time right now to read through licenses.
+IIRC, library GPL is fairly unrestrictive, so I'll choose that. So.....
+
+You may consider this e-mail as a notice that as an alternative to any
+other cfortran licenses,
+I hereby relase all versions and all parts of cfortran under the
+the Library GPL license.
+From among these licenses, the user is free to choose
+the license or licenses under which cfortran is used.
+
+Contact me if you'd like to be able to choose another license.
+
+Burkhard
+
+steinmac@us.ibm.com, (914)945-3756, Fax 3684, Tieline 862
+------------------------------------------
+
+/* end: cfortran.doc */
diff --git a/vendor/cfitsio/cfortran.h b/vendor/cfitsio/cfortran.h
new file mode 100644
index 00000000..703a41b0
--- /dev/null
+++ b/vendor/cfitsio/cfortran.h
@@ -0,0 +1,2515 @@
+/* cfortran.h 4.4 */
+/* 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.
+*/
+
+/* The following modifications were made by the authors of CFITSIO or by me.
+ * They are flagged below with CFITSIO, the author's initials, or KMCCARTY.
+ * PDW = Peter Wilson
+ * DM = Doug Mink
+ * LEB = Lee E Brotzman
+ * MR = Martin Reinecke
+ * WDP = William D Pence
+ * -- Kevin McCarty, for Debian (19 Dec. 2005) */
+
+/*******
+ 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)
+
+ Nov 2003: If __INTEL_COMPILER or INTEL_COMPILER defined, also define
+ f2cFortran (KMCCARTY)
+ Dec 2005: If f2cFortran is defined, enforce REAL functions in FORTRAN
+ returning "double" in C. This was one of the items on
+ Burkhard's TODO list. (KMCCARTY)
+ Dec 2005: Modifications to support 8-byte integers. (MR)
+ USE AT YOUR OWN RISK!
+ Feb 2006 Added logic to typedef the symbol 'LONGLONG' to an appropriate
+ intrinsic 8-byte integer datatype (WDP)
+ Apr 2006: Modifications to support gfortran (and g77 with -fno-f2c flag)
+ since by default it returns "float" for FORTRAN REAL function.
+ (KMCCARTY)
+ May 2008: Revert commenting out of "extern" in COMMON_BLOCK_DEF macro.
+ Add braces around do-nothing ";" in 3 empty while blocks to
+ get rid of compiler warnings. Thanks to ROOT developers
+ Jacek Holeczek and Rene Brun for these suggestions. (KMCCARTY)
+ Dec 2008 Added typedef for LONGLONG to support Borland compiler (WDP)
+ *******/
+
+/*
+ Avoid symbols already used by compilers and system *.h:
+ __ - OSF1 zukal06 V3.0 347 alpha, cc -c -std1 cfortest.c
+
+*/
+
+/*
+ Determine what 8-byte integer data type is available.
+ 'long long' is now supported by most compilers, but older
+ MS Visual C++ compilers before V7.0 use '__int64' instead. (WDP)
+*/
+
+#ifndef LONGLONG_TYPE /* this may have been previously defined */
+#if defined(_MSC_VER) /* Microsoft Visual C++ */
+
+#if (_MSC_VER < 1300) /* versions earlier than V7.0 do not have 'long long' */
+ typedef __int64 LONGLONG;
+#else /* newer versions do support 'long long' */
+ typedef long long LONGLONG;
+#endif
+
+#elif defined( __BORLANDC__) /* (WDP) for the free Borland compiler, in particular */
+ typedef __int64 LONGLONG;
+#else
+ typedef long long LONGLONG;
+#endif
+
+#define LONGLONG_TYPE
+#endif
+
+
+/* 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. */
+
+/* 11/29/2003 (KMCCARTY): add *INTEL_COMPILER symbols here */
+/* 04/05/2006 (KMCCARTY): add gFortran symbol here */
+#if defined(CLIPPERFortran) || defined(pgiFortran) || defined(__INTEL_COMPILER) || defined(INTEL_COMPILER) || defined(gFortran)
+#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
+/* 04/13/00 DM (CFITSIO): Add these lines for NT */
+/* with PowerStationFortran and and Visual C++ */
+#if defined(WIN32) && !defined(__CYGWIN__)
+#define PowerStationFortran
+#define VISUAL_CPLUSPLUS
+#endif
+#if defined(g77Fortran) /* 11/03/97 PDW (CFITSIO) */
+#define f2cFortran
+#endif
+#if defined(__CYGWIN__) /* 04/11/02 LEB (CFITSIO) */
+#define f2cFortran
+#endif
+#if defined(__GNUC__) && defined(linux) /* 06/21/00 PDW (CFITSIO) */
+#define f2cFortran
+#endif
+#if defined(macintosh) /* 11/1999 (CFITSIO) */
+#define f2cFortran
+#endif
+#if defined(__APPLE__) /* 11/2002 (CFITSIO) */
+#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:\
+ - GNU gcc (g77) on Linux. \
+ - 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/g77: Use #define f2cFortran, or cc -Df2cFortran \
+ - gfortran: Use #define gFortran, or cc -DgFortran \
+ (also necessary for g77 with -fno-f2c option) \
+ - 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 \
+ - Intel Fortran: Use #define INTEL_COMPILER"
+/* 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. */
+
+/* "extname" changed to "appendus" below (CFITSIO) */
+#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) extern 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 (CFITSIO) -- 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;
+}
+if (0) { /* to prevent not used warnings in gcc (added by ROOT) */
+ c2fstrv(0, 0, 0, 0); f2cstrv(0, 0, 0, 0); kill_trailing(0, 0);
+ vkill_trailing(0, 0, 0, 0); num_elem(0, 0, 0, 0);
+}
+return (int)num;
+}
+/* #endif removed 2/10/98 (CFITSIO) */
+
+/*-------------------------------------------------------------------------*/
+
+/* 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 LONGLONGVVVVVVV_cfTYPE LONGLONG /* added by MR December 2005 */
+#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 PLONGLONG_cfTYPE LONGLONG /* added by MR December 2005 */
+#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 LONGLONG_cfINT(N,A,B,X,Y,Z) DOUBLE_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#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 PLONGLONG_cfINT(N,A,B,X,Y,Z) PDOUBLE_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#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 LONGLONGV_cfINT(N,A,B,X,Y,Z) DOUBLEV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define LONGLONGVV_cfINT(N,A,B,X,Y,Z) DOUBLEVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define LONGLONGVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define LONGLONGVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define LONGLONGVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define LONGLONGVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define LONGLONGVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#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))
+#if defined (f2cFortran) && ! defined (gFortran)
+/* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
+#define FLOAT_cfPU(A) CFextern DOUBLE_PRECISION FCALLSC_QUALIFIER A
+#else
+#define FLOAT_cfPU(A) CFextern FORTRAN_REAL FCALLSC_QUALIFIER A
+#endif
+#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 LONGLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#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 LONGLONGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define LONGLONGVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define LONGLONGVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define LONGLONGVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define LONGLONGVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define LONGLONGVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define LONGLONGVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#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 PLONGLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#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 LONGLONG_cfT(M,I,A,B,D) *A /* added by MR December 2005 */
+#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 LONGLONGV_cfT(M,I,A,B,D) A /* added by MR December 2005 */
+#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 LONGLONGVV_cfT(M,I,A,B,D) (void *)A /* added by MR December 2005 */
+#define LONGLONGVVV_cfT(M,I,A,B,D) (void *)A /* added by MR December 2005 */
+#define LONGLONGVVVV_cfT(M,I,A,B,D) (void *)A /* added by MR December 2005 */
+#define LONGLONGVVVVV_cfT(M,I,A,B,D) (void *)A /* added by MR December 2005 */
+#define LONGLONGVVVVVV_cfT(M,I,A,B,D) (void *)A /* added by MR December 2005 */
+#define LONGLONGVVVVVVV_cfT(M,I,A,B,D) (void *)A /* added by MR December 2005 */
+#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 PLONGLONG_cfT(M,I,A,B,D) A /* added by MR December 2005 */
+#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 LONGLONG_cfFZ(UN,LN) LONGLONG FCALLSC_QUALIFIER fcallsc(UN,LN)( /* added by MR December 2005 */
+#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. */
+#if defined (f2cFortran) && ! defined (gFortran)
+/* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
+#define FLOAT_cfFZ(UN,LN) DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(void
+#else
+#define FLOAT_cfFZ(UN,LN) FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(void
+#endif
+#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))
+#if defined (f2cFortran) && ! defined (gFortran)
+/* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
+#define FLOAT_cfFZ(UN,LN) DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#else
+#define FLOAT_cfFZ(UN,LN) FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#endif
+#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
+#if defined (f2cFortran) && ! defined (gFortran)
+/* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
+#define FLOAT_cfF(UN,LN) DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#else
+#define FLOAT_cfF(UN,LN) FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#endif
+#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 LONGLONG_cfF(UN,LN) LONGLONG_cfFZ(UN,LN) /* added by MR December 2005 */
+#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 LONGLONG_cfI return A0; /* added by MR December 2005 */
+#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/vendor/cfitsio/changes.txt b/vendor/cfitsio/changes.txt
new file mode 100644
index 00000000..ebd8bb9d
--- /dev/null
+++ b/vendor/cfitsio/changes.txt
@@ -0,0 +1,3844 @@
+ Log of Changes Made to CFITSIO
+
+Version 3.31 - 18 July 2012
+
+ - enhanced the CFITSIO column filtering syntax to allow the comma, in addition
+ to the semi-colon, to be used to separate clauses, for example:
+ [col X,Y;Z = max(X,Y)]. This was done because users are not allowed to
+ enter the semi-colon character in the on-line Hera data processing
+ system due to computer security concerns.
+
+ - enhanced the CFITSIO extended filename syntax to allow specifying image
+ compression parameters (e.g. '[compress Rice]') when opening an existing
+ FITS file with write access. The specified compression parameters will
+ be used by default if more images are appended to the existing file.
+
+ - modified drvrfile.c to do additional file secrity checks when CFITSIO
+ is running within the HEASARC's Hera software system. In this case
+ CFITSIO will not allow FITS files to be created outside of the user's
+ individual Hera data directory area.
+
+ - fixed an issue in fpack and funpack on Windows machines, caused by
+ the fact that the 'rename' function behaves differently on Windows
+ in that it does not clobber an existing file, as it does on Unix
+ platforms.
+
+ - fixed bug in the way byte-swapping was being performed when writing
+ integer*8 null values to an image or binary table column.
+
+ - added the missing macro definition for fffree to fitsio.h.
+
+ - modified the low level table read and write functions in getcol*.c and
+ putcol*.c to remove the 32-bit limitation on the number of elements.
+ These routines now support reading and writing more than 2**31 elements
+ at one time. Thanks to Keh-Cheng Chu (Stanford U.) for the patch.
+
+ - modified Makefile.in so that the shared libcfitsio.so is linked against
+ pthreads and libm.
+
+Version 3.30 - 11 April 2012
+
+ Enhancements
+
+ - Added new routine called fits_is_reentrant which returns 1 or 0 depending on
+ whether or not CFITSIO was compiled with the -D_REENTRANT directive. This can
+ be used to determine if it is safe to use CFITSIO in multi-threaded programs.
+
+ - Implimented much faster byte-swapping algorithms in swapproc.c based on code
+ provided by Julian Taylor at ESO, Garching. These routines significantly
+ improve the FITS image read and write speed (by more than a factor of 2 in
+ some cases) on little-endian machines (e.g., Linux and Microsoft Windows and
+ Macs running on x86 CPUs) where byte-swapping is required when reading and
+ writing data in FITS files. This has no effect on big-endian machines
+ (e.g. Motorola CPUs and some IBM systems). Even faster byte-swapping
+ performance can be achieved in some cases by invoking the new "--enable-sse2"
+ or "--enable-ssse3" configure options when building CFITSIO on machines that
+ have CPUs and compilers that support the SSE2 and SSSE3 machine instructions.
+
+ - added additional support for implicit data type conversion in cases where
+ the floating point image has been losslessly compressed with gzip. The
+ pixels in these compressed images can now be read back as arrays of short,
+ int, and long integers as well as single and double precision floating-point.
+
+ - modified fitsio2.h and f77_wrap.h to recognize IBM System z mainframes by
+ testing if __s390x__ or __s390__ is defined.
+
+ - small change to ffgcrd in getkey.c so that it supports reading a blank
+ keyword (e.g., a keyword whose name simply contains 8 space chracters).
+
+ Bug Fixes
+
+ - fixed a bug in imcomp_decompress_tile that caused the tile-compressed image
+ to be uncompressed incorrectly (even though the tile-compressed image itself
+ was written correctly) under the following specific conditions:
+ - the original FITS image has a "float" datatype (R*4)
+ - one or more of the image tiles cannot be compressed using the standard
+ quantization method and instead are losslessly compressed with gzip
+ - the pixels in these tiles are not all equal to zero (this bug does
+ affect tiles where all the pixels are equal to zero)
+ - the program that is reading the compressed image uses CFITSIO's
+ "implicit datatype conversion" feature to read the "float" image
+ back into an array of "double" pixel values.
+ If all these conditions are met, then the returned pixel values in the
+ affected image tiles will be garbage, with values often ranging
+ up to 10**34. Note that this bug does not affect the fpack/funpack
+ programs, because funpack does not use CFITSIO's implicit datatype
+ conversion feature when uncompressing the image.
+
+Version 3.29 - 2 December 2011
+
+ Enhancements
+
+ - modified Makefile.in to allow configure to override the lib and include
+ destination directories.
+
+ - added (or restored actually) support for tile compression of 1-byte integer
+ images in imcomp_compress_tile. Support for that data type was overlooked
+ during recent updates to this routine.
+
+ - modified the fits_get_token command-line parsing routine to perform more
+ rigorous checks to determine if the token can be interpreted as a number
+ or not.
+
+ - made small modification to fpack.c to not allow the -i2f option (convert
+ image from integer to floating point) with the "-g -q 0" option (do lossless
+ gzip compression). It is more efficient to simply use the -g option alone.
+
+ - made modifications to fitsio.h and drvrfile.c to support reading and
+ writing large FITS files (> 2.1 GB) when building CFITSIO using
+ Microsoft Visual C++ on Windows platforms.
+
+ - added new WCS routine (ffgicsa) which returns the WCS keyword values
+ for a particular WCS version ('A' - 'Z').
+
+ Bug Fixes
+
+ - fixed a problem with multi-threaded apps that open/close FITS files
+ simultaneously by putting mutex locks around the call to
+ fits_already_open and in fits_clear_Fptr.
+
+ - fixed a bug when using the 'regfilter' function to select a subset of the
+ rows in a FITS table that have coordinates that lie within a specified
+ spatial region on the sky. This bug only affects the rarely used panda
+ (and epanda and bpanda) region shapes in which the region is defined by
+ the intersection of an annulus and a pie-shaped wedge. The previous code
+ (starting with version 3.181 of CFITSIO where support for the panda region
+ was first introduced) only worked correctly if the 2 angles that define
+ the wedge have values between -180 and +180. If not, then fewer rows than
+ expected may have been selected from the table.
+
+ - fixed the extended filename parser so that when creating a histogram by
+ binning 2 table columns, if a keyword or column name is given as the
+ weighting factor, then the output histrogram image will have a floating
+ point datatype, not the default integer datatype as is the case when no
+ weigth is specified (e.g. with a filename like
+ "myfile.fits[bin x,y; weight_column]"
+
+ - added fix to the code in imcompress.c to work around a problem with
+ dereferencing the value of a pointer, in cases where the address of
+ that pointer has not been defined (e.g., the nulval variable).
+
+ - modified the byte shuffling algorithm in fits_shuffle_8bytes to work
+ around a strange bug in the proprietary SunStudioExpress C compiler
+ under OpenSolaris.
+
+ - removed spurious messages on the CFITSIO error stack when opening a
+ FITS file with FTP (in drvrnet.c);
+
+Version 3.28 - 12 May 2011
+
+ - added an enhancement to the tiled-image compression method when compressing
+ floating-point image using the standard (lossy) quantization method. In
+ cases where an image tile cannot be quantized, The floating-point pixel values
+ will be losslessly compressed with gzip before writing them to the tile-
+ compressed file. Previously, the uncompressed pixel values would have
+ been written to the file, which obviously requires more disk space.
+
+ - made significant internal changes to the structure of the tile compression
+ and uncompression routines in imcompress.c to make them more modular and
+ easier to maintain.
+
+ - modified configure.in and configure to force it to build a Universal
+ binary on Mac OS X.
+
+ - modified the ffiter function in putcol.c to properly clean up allocated
+ memory if an error occurs.
+
+ - in quantize.c, when searching for the min and max values in a float array,
+ initialize the max value to -FLT_MAX instead of FLT_MIN (and similarly
+ for double array).
+
+Version 3.27 - 3 March 2011
+
+ Enhancements
+
+ - added new routines fits_read_str and fits_delete_str which read or
+ delete, respectively, a header keyword record that contains a specified
+ character string.
+
+ - added a new routine called fits_free_memory which frees the memory
+ that fits_read_key_longstr allocated for the long string keyword value.
+
+ - enhanced the ffmkky routine in fitscore.c to not put a space before the
+ equals sign when writing long string-valued keywords using the ESO
+ HIERARCH keyword convension, if that extra character is needed to
+ fit the length of the keyword name + value string within the 80-character
+ FITS keyword record.
+
+ - made small change to fits_translate_keyword to support translation of
+ blank keywords (where the name = 8 blank chracters)
+
+ - modified fpack so that it uses the minimum of the 2nd, 3rd, and 5th order
+ MAD noise values when quantizing and compressing a floating point image.
+ This is more conservative than just using the 3rd order MAD value alone.
+
+ - added new routine imcomp_copy_prime2img to imcompress.c that is used by
+ funpack to copy any keywords that may have been added to the primary
+ array of the compressed image file (a null image) back into the header of
+ the uncompressed image.
+
+ - enhanced the fits_quantize_float and fits_quantize_double routines in
+ quantize.c to also compress the tile if it is completely filled with
+ null values. Previously, this type of tile would have been written
+ to the output compressed image without any compression.
+
+ - enhanced imcomp_decompress_tile to support implicit datatype conversion
+ when reading a losslessly compressed (with gzip) real*4 image into an
+ array of real*8 values.
+
+ - in imcompress.c, removed possible attempt to free memory that had not
+ been allocated.
+
+
+Version 3.26 - 30 December 2010
+
+ Enhancements
+
+ - defined 2 new macros in fitsio.h:
+ #define CFITSIO_MAJOR 3
+ #define CFITSIO_MINOR 26
+ These may be used within other macros to detect the CFITSIO
+ version number at compile time.
+
+ - modified group.c to initialize the output URL to a null string in
+ fits_url2relurl. Also added more robust tests to see if 2 file
+ pointers point to the same file.
+
+ - enhanced the template keyword parsing code in grparser.c to support
+ the 'D' exponent character in the ASCII representation of floating
+ point keyword values (as in TVAL = 1.23D03). Previously, the parser
+ would have writen this keyword with a string value (TVAL = '1.23D03').
+
+ - modified the low-level routines that write a keyword record to a FITS
+ header so that they silently replace any illegal characters (ASCII
+ values less than 32 or greater than 126) with an ASCII space character.
+ Previously, these routines would have returned with an error when
+ encountering these illegal characters in the keyword record (most commonly
+ tab, carriage return, and line feed characters).
+
+ - made substantial internal changes to imcompress.c in preparation for
+ possible future support for compression methods for FITS tables analogous
+ to the tiled image compression method.
+
+ - replaced all the source code in CFITSIO that was distributed under the
+ GNU General Public License with freely available code. In particular,
+ the gzip file compression and uncompression code was replaced by the
+ zlib compression library. Thus, beginning with this version 3.26 of CFITSIO,
+ other software applications may freely use CFITSIO without necessarily
+ incurring any GNU licensing requirement. See the License.txt file for
+ the CFITSIO licensing requirements.
+
+ - added support for using cfitsio in different 'locales' which use a
+ comma, not a period, as the decimal point character in ASCII
+ representation of a floating point number (e.g., France). This
+ affects how floating point keyword values and floating point numbers
+ in ASCII tables are read and written with the 'printf' and 'strtod'
+ functions.
+
+ - added a new utility routine called fits_copy_rows/ffcprw that copies
+ a specified range of rows from one table to another.
+
+ - enhanced the test for illegal ASCII characters in a header (fftrec) to
+ print out the name of the offending character (e.g TAB or Line Feed) as
+ well as the Hex value of the chracter.
+
+ - modified ffgtbc (in fitscore.c) to support nonstandard vector variable
+ length array columns in binary tables (e.g. with TFORMn = 2000PE(500)').
+
+ - modified the configure file to add "-lm" when linking CFITSIO on
+ Solaris machines.
+
+ - added new routine, fits_get_inttype, to parse an integer keyword value
+ string and return the minimum integer datatype (TBYTE, TSHORT, TLONG,
+ TLONGLONG) required to store the integer value.
+
+ - added new routine, fits_convert_hdr2str, which is similar to fits_hdr2str
+ except that if the input HDU is a tile compressed image (stored
+ in a binary table) then it will first convert that header back to
+ that of a normal uncompressed FITS image before concatenating the header
+ keyword records.
+
+ - modified the file template reading routine (ngp_line_from_file in
+ grparser.c) so that it ignores any carriage return characters (\r)
+ in the line, that might be present, e.g. if the file was created on a
+ Windows machine that uses \r\n as end of line characters.
+
+ - modified the ffoptplt routine in cfileio.c to check if the PCOUNT
+ keyword in the template file has a non-zero value, and if so, resets
+ it to zero in the newly created file.
+
+ Bug Fixes
+
+ - fixed a bug when uncompressing floating-point images that contain Nan
+ values on some 64-bit platforms.
+
+ - fixed a bug when updating the value of the CRPIXn world coordinate
+ system keywords when extracting a subimage from larger FITS image, using the
+ extended CFITSIO syntax (e.g. myimage[1:500:2, 1:500:2]). This bug only
+ affects casee where the pixel increment value is not equal to 1, and caused
+ the coordinate grid to be shifted by between 0.25 pixels (in the case of
+ a pixel increment of 2) and 0.5 pixels (for large pixel increment values).
+
+ - fixed a potential string buffer overflow error in the ffmkls routine
+ that modifies the value and comment strings in a keyword that uses
+ the HEASARC long string keyword convention.
+
+ - fixed a bug in imcompress.c that could cause programs to abort on 64-bit
+ machines when using gzip to tile-compress images. Changed the declaration
+ of clen in imcomp_compress_tile from int to size_t.
+
+Version 3.25 - 9 June 2010
+
+ - fixed bug that was introduced in version 3.13 that broke the ability
+ to reverse an image section along the y-axis with an image section
+ specifier like this: myimage.fits[*,-*]. This bug caused the output
+ image to be filled with zeros.
+
+ - fixed typo in the definition of the ftgprh Fortran wrapper routine
+ in f77_wrap3.c.
+
+ - modified the cfitsio.pc.in configuration file to make the lib path
+ a variable instead of hard coding the path. The provides more
+ flexibility for projects such as suse and fedora when building CFITSIO.
+
+ - fixed bug in imcomp_compress_tile in imcompress.c which caused
+ null pixel values to be written incorrectly in the rare case where
+ the floating-point tile of pixels could not be quantized into integers.
+
+ - modified imcompress.c to add a new specialized routine to uncompress
+ an input image and then write it to a output image on a tile by tile basis.
+ This appears to be faster than the old method of uncompressing the
+ whole image into memory before writing it out. It also supports
+ large images with more than 2**31 pixels.
+
+ - made trivial changes to 2 statements in drvrfile.c to suppress
+ nuisance compiler warnings.
+
+ - some compilers define CLOCKS_PER_SEC as a double instead of an integer,
+ so added an explicted integer type conversion to 2 statements in
+ imcompress.c that used this macro.
+
+ - removed debugging printf statements in drvrnet.c (15 July)
+
+Version 3.24 - 26 January 2010
+
+ - modified fits_translate_keywords so that it silently ignores any
+ illegal ASCII characters in the value or comment fields of the input
+ FITS file. Otherwise, fpack would abort without compressing input
+ files that contained this minor violation of the FITS rules.
+
+ - added support for Super H cpu in fitsio2.h
+
+ - updated funpack to correctly handle the -S option, and to use a
+ more robust algorithm for creating temporary output files.
+
+ - modified the imcomp_compress_tile routine to support the NOCOMPRESS
+ debugging option for real*4 images.
+
+Version 3.23 - 7 January 2010
+
+ - reduced the default value for the floating point image quantization
+ parameter (q) from 16 to 4. This parameter is used when tile compressing
+ floating point images. This change will increase the average compression
+ ratio for floating point images from about 4.6 to about 6.5 without losing
+ any significant information in the image.
+
+ - enhanced the template keyword parsing routine to reject a header
+ template string that only contains a sequence of dashes.
+
+ - enhanced the ASCII region file reading routine to allow tabs as well
+ as spaces between fields in the file.
+
+ - got rid of bogus error message when calling fits_update_key_longstr
+
+ - Made the error message more explicit when CFITSIO tries to write
+ to a GZIP compressed file. Instead of just stating "cannot write
+ to a READONLY file", it will say "cannot write to a GZIP compressed
+ file".
+
+Version 3.22 - 28 October 2009
+
+ - added an option (in imcompress.c) to losslessly compress floating
+ point images, rather than using the default integer scaling method.
+ This option is almost never useful in practice for astronomical
+ images (because the amount of compression is so poor), but it has
+ been added for test comparison purposes.
+
+ - enhanced the dithering option when quantizing and compressing
+ floating point images so that a random dithering starting point
+ is used, so that the same dithering pattern does not get used for
+ every image.
+
+ - modified the architecture setup section of fitsio2.h to support the
+ 64-core 8x8-architecture Tile64 platform (thanks to Ken Mighell, NOAO)
+
+ Fixes
+
+ - fixed a problem that was introduced in version 3.13 of CFITSIO
+ in cases where a program writes it own END keyword to the header
+ instead of letting CFITSIO do it, as is strongly recommended. In
+ one case this caused CFITSIO to rewrite the END keyword and any
+ blank fill keywords in the header many times, causing a
+ noticeable slow-down in the FITS file writing speed.
+
+Version 3.21 - 24 September 2009
+
+ - fixed bug in cfileio.c that caused CFITSIO to crash with a bus error
+ on Mac OS X if CFITSIO was compiled with multi-threaded support (with
+ the --enable-reentrant configure option). The Mac requires an
+ additional thread initialization step that is not required on Linux
+ machines. Even with this fix, occasional bus errors have been seen on
+ some Mac platforms, The bus errors are seen when running the
+ thread_test.c program. The bus errors are very intermittent, and occur
+ less than about 1% of the time, on the affected platforms.
+ These bus errors have not been seen on Linux platforms.
+
+ - fixed invalid C comment delimiter ("//*" should have been "/*")
+ in imcompress.c.
+
+ - Increased the CFITSIO version number string length
+ in fpackutil.c, to fix problem on some platforms when running
+ fpack -V or funpack -V. Also modified the output format of the
+ fpack -L command.
+
+Version 3.20 - 31 August 2009
+
+ - modified configure.in and configure so that it will build the Fortran
+ interface routines by default, even if no Fortran compiler is found
+ in the user's path. Building the interface routines may be disabled
+ by specifying FC="none". This was done at the request of users who
+ obtained CFITSIO from some other standard linux distributions, where
+ CFITSIO was apparently built in an environment that had no Fortran
+ compiler and hence did not build the Fortran wrappers.
+
+ - modified ffchdu (close HDU) so that it calls the routine to update
+ the maximum length of variable length table columns in the TFORM
+ values in all cases where the values may have changed. Previously
+ it would not update the values if a value was already specified in
+ the TFORM value.
+
+ - added 2 new string manipulation functions to the CFITSIO parser
+ (contributed by Craig Markwardt): strmid extracts a substring
+ from a string, and strstr searches for a substring within a string.
+
+ - removed the code in quantize.c that treated "floating-point integer"
+ images as a special case (it would just do a datatype conversion from
+ float to int, and not otherwise quantize the pixel values). This
+ caused complications with the new subtractive dithering feature.
+
+ - enhanced the code for converting floating point images to quantized
+ scaled integer prior to tile-compressing them, to apply a random
+ subtractive dithering, which improves the photometric accuracy
+ of the compressed images.
+
+ - added new internal routine, iraf_delete_file, for use by fpack to
+ delete a pair of IRAF format header and pixel files.
+
+ - small change in cfileio.c in the way it recognizes an IRAF format
+ .imh file. Instead of just requiring that the filename contain the
+ ".imh" string, that string must occur at the end of the file name.
+
+ - fixed bug in the code that is used when tile-compressing real*4 FITS
+ images, which quantizes the floating point pixel values into
+ integer levels. The bug would only appear in the fairly rare
+ circumstance of tile compressing a floating point image that contains
+ null pixels (NaNs) and only when using the lossy Hcompress algorithm
+ (with the s parameter not equal to 1). This could cause underflow of
+ low valued pixels, causing them to appear as very large pixel values
+ (e.g., > 10**30) in the compressed image
+
+ - changed the "if defined" blocks in fitsio.h, fitsio2.h and f77_wrap.h
+ to correctly set the length of long variables on sparc64 machines.
+ Patch contributed by Matthew Truch (U. Penn).
+
+ - modified the HTTP file access code in drvrnet.c to support basic
+ HTTP authentication, where the user supplies a user name and
+ password. The CFITSIO filename format in this case is:
+ "http://username:password@hostname/..."
+ Thanks to Jochen Liske (ESO) for the suggestion and the code.
+
+Version 3.181 (BETA) - 12 May 2009
+
+ - modified region.c and region.h to add support for additional
+ types of region shapes that are supported by ds9: panda, epanda,
+ and bpanda.
+
+ - fixed compiler error when using the new _REENTRANT flag, having to
+ do with the an attempted static definition of Fitsio_Lock in
+ several source files, after declaring it to be non-static in fitsio2.h.
+
+Version 3.18 (BETA) - 10 April 2009
+
+ - Made extensive changes to make CFITSIO thread safe. Previously,
+ all opened FITS files shared a common pool of memory to store
+ the most recently read or written FITS records in the files.
+ In a multi-threaded environment different threads could
+ simultaneously read or write to this common area causing
+ unpredictable results. This was changed so that every opened
+ FITS file has its own private memory area for buffering the
+ file. Most of the changes were in buffers.c, fitsio.h, and
+ fitsio2.h. Additional changes were made to cfileio.c, mainly
+ to put locks around small sections of code when setting up the
+ low-level drivers to read or write the FITS file. Also, locks
+ were needed around the GZIP compression and uncompression code
+ in compress.c., the error message stack access routine in
+ fitscore.c, the encode and decode routines in fits_hcompress.c
+ and fits_hdecompress.c, in ricecomp.c, and the table row
+ selection and table calculator functions. Also, removed the
+ 'static' declaration of the local variables in pliocomp.c
+ which did not appeared to be required and prevented the
+ routines from being thread safe.
+
+ As a consequence of having a separate memory buffer for every
+ FITS file (by default, about 115 kB per file), CFITSIO may now
+ allocate more memory than previously when an application
+ program opens multiple FITS files at once. The read and write
+ speed may also be slightly faster, since the buffers are not
+ shared between files.
+
+ - Added new families of Fortran wrapper routines to read and
+ write values to large tables that have more than 2**31 rows.
+ The arguments that define the first row and first element to
+ read or write must be I*8 integers, not ordinary I*4
+ integers. The names of these new routines have 'LL' appended
+ to them, so for example, ftgcvb becomes ftgcvbll.
+
+ Fixes
+
+ - Corrected an obscure bug in imcompress.c that would have incorrectly
+ written the null values only in the rare case of writing a signed
+ byte array that is then tile compressed using the Hcompress or PLIO
+ algorithm.
+
+Version 3.14 - 18 March 2009
+
+ Enhancements
+
+ - modified the tiled-image compression and uncompression code to
+ support compressing unsigned 16-bit integer images with PLIO.
+ FITS unsigned integer arrays are offset by -32768, but the PLIO
+ algorithm does not work with negative integer values. In this
+ case, an offset of 32768 is added to the array before compression,
+ and then subtracted again when reading the compressed array.
+ IMPORTANT NOTE: This change is not backward compatible, so
+ these PLIO compressed unsigned 16-bit integer images will not be
+ read correctly by previous versions of CFITSIO; the pixel values
+ will have an offset of +32768.
+
+ - minor changes to the fpack utility to print out more complete
+ version information with the -V option, and format the report
+ produced by the -T option more compactly.
+
+ Fixes
+
+ - Modified imcomp_compress_image (which is called by fpack) so that
+ it will preserve any null values (NaNs) if the input image has
+ a floating point datatype (BITPIX = -32 or -64). Null values in
+ integer datatype images are handled correctly.
+
+ - Modified imcomp_copy_comp2img so that it does not copy the
+ ZBLANK keyword, if present, from the compressed image header
+ when uncompressing the image.
+
+ - Fixed typo in the Fortran wrapper macro for the ftexist function.
+
+Version 3.13 - 5 January 2009
+
+ Enhancements
+
+ - updated the typedef of LONGLONG in fitsio.h and cfortran.h to
+ support the Borland compiler which uses the __int64 data type.
+
+ - added new feature to the extended filename syntax so that when
+ performing a filtering operation on specified HDU, if you add
+ a '#' character after the name or number of the HDU, then ONLY
+ that HDU (and the primary array if the HDU is a table) will be
+ copied into the filtered version of the file in memory. Otherwise,
+ by default CFITSIO copies all the HDUs from the input file into
+ memory.
+
+ - when specifying a section, if the specified number of dimensions
+ is less than the number of dimensions in the image, then CFITSIO
+ will use the entire dimension, as if a '*' had been specified.
+ Thus [1:100] is equivalent to [1:100,*] when specifying a section
+ of 2 dimensional image.
+
+ - modified fits_copy_image_section to read/write the section 1 row
+ at a time, instead of the whole section, to reduce memory usage.
+
+ - added new stream:// drivers for reading/writing to stdin/stdout.
+ This driver is somewhat fragile, but for simple FITS read and
+ write operations this driver streams the FITS file on stdin
+ or stdout without first copying the entire file in memory, as is
+ done when specifying the file name as "-".
+
+ - slight modification to ffcopy to make sure that the END keyword
+ is correctly written before copying the data. This is required
+ by the new stream driver.
+
+ - modified ffgcprll, so that when writing data to an HDU, it first
+ checks that the END keyword has been written to the correct place.
+ This is required by the new stream driver.
+
+ Fixes
+
+ - fixed bug in ffgcls2 when reading an ASCII string column in binary
+ tables in cases where the width of the column is greater than 2880
+ characters and when reading more than 1 row at a time. Similar
+ change was made to ffpcls to fix same problem with writing to
+ columns wider than 2880 characters.
+
+ - updated the source files listed in makepc.bat so that it can be
+ used to build CFITSIO with the Borland C++ compiler.
+
+ - fixed overflow error in ffiblk that could cause writing to Large Files
+ (> 2.1 GB) to fail with an error status.
+
+ - fixed a bug in the spatial region code (region.c) with the annulus
+ region. This bug only affected specialized applications which
+ directly use the internal region structure; it does not affect
+ any CFITSIO functions directly.
+
+ - fixed memory corruption bug in region.c that was triggered if the
+ region file contained a large number of excluded regions.
+
+ - got rid of a harmless error message that would appear if filtering
+ a FITS table with a GTI file that has zero rows. (eval_f.c)
+
+ - modified fits_read_rgnfile so that it removes the error messages
+ from the error stack if it is unable to open the region file as
+ a FITS file. (region.c)
+
+Version 3.12 - 8 October 2008
+
+ - modified the histogramming code so that the first pixel in the binned
+ array is chosen as the reference pixel by default, if no other
+ value is previously defined.
+
+ - modified ffitab and ffibin to allow a null pointer to the
+ EXTNAME string, when inserting a table with no name.
+
+Version 3.11 - 19 September 2008
+
+ - optimized the code when tile compressing real*4 images (which get
+ scaled to integers). This produced a modest speed increase. For
+ best performance, one must specify the absolute q quantization
+ parameter, rather than relative to the noise in the tile (which
+ is expensive to compute).
+
+ - modified the FITS region file reading code to check for NaN values,
+ which signify the end of the array of points in a polygon region.
+
+ - removed the test for LONGSIZE == 64 from fitsio.h, since it may
+ not be defined.
+
+ - modified imcompress.c to support unconventional floating point FITS
+ images that also have BSCALE and BZERO keywords. The compressed
+ floating point images are linearly scaled twice in this case.
+
+Version 3.10 - 20 August 2008
+
+ - fixed a number of cases, mainly dealing with long input file names
+ (> 1024 char), where unsafe usage of strcat and strcpy could have caused
+ buffer overflows. These buffer overflows could cause the application
+ to crash, and at least theoretically, could be exploited by a
+ malicious user to execute arbitrary code. There are no known instances
+ of this type of malicious attack on CFITSIO applications, and the
+ likelihood of such an attack seems remote. None the less, it would
+ be prudent for CFITSIO users to upgrade to this new version to guard
+ against this possibility.
+
+ - modified some of the routines to define input character string
+ parameters as "const char *" rather than just "char *" to eliminate
+ some compiler warnings when the calling routine passes a constant
+ string to the CFITSIO routine. Most of the changes were to the
+ keyword name argument in the many routines that read or write keywords.
+
+ - fixed bug when tile-compressing a FITS image which caused all the
+ completely blank keywords in the input header to be deleted from
+ the output compressed image. Also added a feature to preserve any
+ empty FITS blocks in the header (reserved space for future keywords)
+ when compressing or uncompressing an image.
+
+ - fixed small bug in the way the default tile size is set in imcompress.c.
+ (Fix sent in by Paul Price).
+
+ - added support for reading FITS format region files (in addition
+ to the ASCII format that was previously supported). Thanks to
+ Keith Arnaud for modifying region.c to do this.
+
+Version 3.09 - 12 June 2008
+
+ - fixed bug in the calculator function, parse_data, that evaluates
+ expressions then selecting rows or modifying values in table columns.
+ This bug only appeared in unusual circumstances
+ where the calculated value has a null value (= TNULLn). The bug
+ could cause elements to not be flagged as having a null value, or
+ in rare cases could cause valid elements to be flagged as null. This
+ only appears to have affected 64-bit platforms (where size(long) = 8).
+
+ - fixed typo in imcomp_decompress_tile: call to fffi2r8 should have
+ been to fffi4r8.
+
+ - in the imcopy_copy_comp2img routine, moved the call to
+ fits_translate_keywords outside of the 'if' statement. This could
+ affect reading compressed images that did not have a EXTNAME keyword
+ in the header.
+
+ - fixed imcomp_compress_tile in imcompress.c to properly support
+ writing unsigned integers, in place, to tile compressed images.
+
+ - modified fits_read_compressed_img so that if the calling routine
+ specifies nullval = 0, then it will not check for null-valued
+ pixels in the compressed FITS image. This mimics the same
+ behavior when reading normal uncompressed FITS images.
+
+Version 3.08 - 15 April 2008
+
+ - fixed backwards compatibility issue when uncompressing a Rice
+ compressed image that was created with previous versions of
+ CFITSIO (this late fix was added on May 18).
+
+ - small change to cfortran.h to add "extern" to the common block
+ definition. This was done for compatibility with the version
+ of cfortran.h that is distributed by the debian project.
+
+ - relaxed the requirement that a string valued keyword must have a
+ closing quote character. If the quote is missing, CFITSIO will silently
+ append a quote at the end of the keyword record. This change was made
+ because otherwise it is very difficult to correct the keyword
+ because CFITSIO would exit with an error before making the fix.
+
+ - added a new BYTEPIX compression parameter when tile-compressing
+ images with the Rice algorithm.
+
+ - cached the NAXIS and NAXISn keyword values in the fitsio structure
+ for efficiency, to eliminate duplicates reads of these keywords.
+
+ - added variants of the Rice compression and uncompression routines to
+ support short int images (in addition to the routines that support int).
+
+ - moved the definition of LONGLONG_MIN and LONGLONG_MAX from fitsio2.h
+ to fitsio.h, to make it accessible to application programs.
+
+ - make efficiency improvements to fitscore.c, to avoid needless searches
+ through the entire header when reading the required keywords that must
+ be near the beginning of the header.
+
+ - made several improvements to getcol.c to optimize reading of compressed
+ and uncompressed images.
+
+ - changed the compression level in the gzip code from 6 to 1. In most
+ cases this will provide nearly the same amount of compression, but is
+ significantly faster in some cases.
+
+ - added new "helper routines' to imcompress.c to allow applications to
+ specified the "quantize level" and Hcompress scaling and smoothing
+ parameters
+
+ - modified the extended filename syntax to support the "quantize level"
+ and Hcompress scaling and smoothing parameters. The parser in
+ cfileio.c was extensively modified.
+
+ - extensive changes to quantize.c:
+ - replace the "nbits" parameter with "quantize level"
+ - the quantize level is now relative to the RMS noise in the image
+ - the HCOMPRESS scale factor is now relative to the RMS noise
+ - added routines to calculate RMS noise in image
+ (these changes require a change to the main file structure in fitsio.h)
+
+ - initialize errno = 0 before the call to strtol in ffext, in case errno
+ has previously been set by an unrelated error condition.
+
+ - added the corresponding long name for the ffgkyjj routine to longnam.h.
+
+ - changed imcomp_copy_comp2img (in imcompress.c) to not require the
+ presence of the EXTNAME keyword in the input compressed image header.
+
+ - modified imcompress.c to only write the UNCOMPRESSED_DATA column
+ in tile-compressed images if it is actually needed. This eliminates
+ the need to subsequently delete the column if it is not used
+ (which is almost always the case).
+
+ - found that it is necessary to seek to the EOF of a file after
+ truncating the size of the file, to reestablish a definite
+ current location in the file. The required small changes to 3
+ routines: file_truncate (to seek to EOF) and fftrun (to set io_pos)
+ and the truncation routine in drvrmem.c.
+
+ - improved the efficiency when compressing integer images with
+ gzip. Previously, the image was always represented using integer*4
+ pixels, which were then compressed. Now, if the range of pixel
+ values can be represented with integer*2 pixels or integer*1 pixels,
+ then that is used. This change is backward compatible with any
+ compressed images that used the previous method.
+
+ - changed the default tiling pattern when using Hcompress from
+ large squares (200 to 600 pixels wide) to 16 rows of the image.
+ This generally requires less memory, compresses faster, and is more
+ consistent with the default row by row tiling when using the other
+ compression methods.
+
+ - modified imcomp_init_table in imcompress.c to enforce a restriction
+ when using the Hcompress algorithm that the 1st 2 dimensions of sll
+ image tiles must be at least 4 pixels long. Hcompress becomes very
+ inefficient for smaller dimensions, and does not work at all with
+ 1D images.
+
+ - fixed bug in the Hcompress compression algorithm that could affect
+ compression of I*4 images, using non-square compression tiles
+ (in the encode64 routine).
+
+Version 3.07 - 6 December 2007 (internal release)
+
+ - fixed bug with the PLIO image compression routine which silently
+ produced a corrupted compressed image if the uncompressed image pixels
+ were not all in the range 0 to 2**24. (fixed in November)
+
+ - fixed several 'for' loops in imcompress.c which were exceeding the
+ bounds of an array by 1. (fixed in November)
+
+ - fixed a possible, but unlikely, memory overflow issue in iraffits.c.
+
+ - added a clarification to the cfortran.doc file that cfortran.h
+ may be used and distributed under the terms of the GNU Library
+ General Public License.
+
+ - fixed bug in the fits_modify_vector_len routine when modifying
+ the vector length of a 'X' bit column.
+
+Version 3.06 - 27 August 2007
+
+ - modified the imcopy.c utility program (to tile-compress images)
+ so that it writes the default EXTNAME = 'COMPRESSED_IMAGE'
+ keyword in the compressed images, to preserve the behavior of
+ earlier versions of imcopy.
+
+ - modified the angsep function in the FITS calculator (in eval.y)
+ to use haversines, instead of the 'law of cosines', to provide
+ more precision at small angles (< 0.1 arcsec).
+
+Version 3.05 - July 2007 (internal release only)
+
+ - extensive changes to imcompress.c to fully support implicit data
+ type conversion when reading and writing arrays of data to FITS
+ images, where the data type of the array is not the same as the
+ data type of the FITS image. This includes support for null pixels,
+ and data scaling via the BSCALE and BZERO keywords.
+
+ - rewrote the fits_read_tbl_coord routine in wcssub.c, that gets the
+ standard set of WCS keywords appropriate to a pair of columns in a
+ table, to better support the full set of officially approved WCS keywords.
+
+ - made significant changes to histo.c, which creates an image by binning
+ columns of a table, to better translate the WCS keywords in the table
+ header into the WCS keywords that are appropriate for an image HDU.
+
+ - modified imcompress.c so that when pixels are written to a
+ tile-compressed image, the appropriate BSCALE and BZERO values of
+ that image are applied. This fixes a bug in which writing to
+ an unsigned integer datatype image (with BZERO = 32768) was not
+ done correctly.
+
+Version 3.04 - 3 April 2007
+
+ - The various table calculator routines (fits_select_rows, etc.) implicitly
+ assumed that the input table has not been modified immediately prior to
+ the call. To cover cases where the table has been modified a call to
+ ffrdef has been added to ffprs. IN UNUSUAL CASES THIS CHANGE COULD
+ CAUSE CFITSIO TO BEHAVE DIFFERENTLY THAN IN PREVIOUS VERSIONS. For
+ example, opening a FITS table with this column-editing virtual file
+ expression:
+ myfile.fits[3][col A==X; B = sqrt(X)]
+ no longer works, because the X column does not exist when the
+ sqrt expression is evaluated. The correct expression in this case is
+ myfile.fits[3][col A==X; B = sqrt(A)]
+
+ - modified putkey.c to support USHORT_IMG when calling fits_create_img
+ to create a signed byte datatype image.
+
+ - enhanced the column histogramming function to propagate any TCn_k and
+ TPn_k keywords in the table header to the corresponding CDi_j and PCi_j
+ keywords in the image header.
+
+ - enhanced the random, randomn, and randomp functions in the lexical
+ parser to take a vector column name argument to specify the length
+ of the vector of random numbers that should be generated (provided by
+ Craig Markwardt, GSFC)
+
+ - enhanced the ffmcrd routine (to modify an existing header card) to
+ support long string keywords so that any CONTINUE keywords associated
+ with the previous keyword will be deleted.
+
+ - modified the ffgtbp routine to recognize the TDIMn keyword for
+ ASCII string columns in a binary table. The first dimension is
+ taken to be the size of a unit string. (The TFORMn = 'rAw'
+ syntax may also be used to specify the unit string size).
+
+ - in fits_img_decompress, the fits_get_img_param function was called
+ with an invalid dimension size, which caused a fatal error on at
+ least 1 platform.
+
+ - in ffopentest, set the status value before returning in case of error.
+
+ - in the drvrnet.c file, the string terminators needed to be changed
+ from "\n" to "\r\n" to support the strict interpretation of the
+ http and ftp standard that is enforced by some newer web servers.
+
+Version 3.03 - 11 December 2006
+
+ New Routine
+
+ - fits_write_hdu writes the current HDU to a FILE stream (e.g. stdout).
+
+ Changes
+
+ - modified the region parsing code to support region files where the
+ keyword "physical" is on a separate line preceding the region shape
+ token. (However, "physical" coordinates are not fully supported, and
+ are treated identically to "image" coordinates).
+
+ - enhanced the iterator routines to support calculations on 64-bit
+ integer columns and images. Currently, the values are cast to
+ double precision when doing the calculations, which can cause a
+ loss of precision for integer values greater than about 2**52.
+
+ - added support for accessing FITS files on the computational grid.
+ Giuliano Taffoni and Andrea Barisani, at INAF, University of Trieste,
+ Italy, implemented the necessary I/O driver routines in drvrgsiftp.c.
+
+ - modified the tiled image compression/uncompression routines to
+ preserve/restore the original CHECKSUM and DATASUM keywords if they
+ exist. (saved as ZHECKSUM and ZDATASUM in the compressed image)
+
+ - split fits_select_image_section into 2 routines: a higher level routine
+ that creates the output file and copies other HDUs from the input file
+ to the output file, and a lower level routine that extracts the image
+ section from the input image into an output image HDU.
+
+ - Improved the error messages that get generated if one tries to
+ use the lexical parser to perform calculations on variable-length
+ array columns.
+
+ - added "#define MACHINE NATIVE" in fitsio2.h for all machines where
+ BYTESWAPPED == FALSE. This may improve the file writing performance
+ by eliminating the need to allocate a temporary buffer in some cases.
+
+ - modified the configure.in and configure script to fix problems with
+ testing if network services are available, which affects the definition
+ of the HAVE_NET_SERVICES flag.
+
+ - added explicit type casting to all malloc statements, and deleted
+ declarations of unreferenced variables in the image compression code
+ to suppress compiler warnings.
+
+ - fixed incorrect logic in fitsio2.h in the way it determined if numerical
+ values are byteswapped or not on MIPS and ARM architectures.
+
+ - added __BORLANDC__ to the list of environments in fitsio.h that don't
+ use %lld in printf for longlong integers
+
+ - added "#if defined(unix)" around "#include <usistd.h>" statements in
+ several C source files, to make them compatible with Windows.
+
+
+Version 3.02 - 18 Sept 2006
+
+ - applied the security patch to the gzip code, available at
+ http://security.FreeBSD.org/patches/SA-06:21/gzip.patch
+ The insufficient bounds checks in buffer use can cause gzip to crash,
+ and may permit the execution of arbitrary code. The NULL pointer
+ deference can cause gzip to crash. The infinite loop can cause a
+ Denial-of-Service situation where gzip uses all available CPU time.
+
+ - added HCOMPRESS as one of the compression algorithm options in the
+ tiled image compression code. (code provided by Richard White (STScI))
+ Made other improvements to preserve the exact header structure in the
+ compressed image file so that the compressed-and-then-uncompressed FITS
+ image will be as identical as possible to the original FITS image file.
+
+ New Routines
+
+ - the following new routines were added to support reading and writing
+ non-standard extension types:
+ fits_write_exthdr - write required keywords for a conforming extension
+ fits_write_ext - write data to the extension
+ fits_read_ext - read data from the extension
+
+ - added new routines to compute the RMS noise in the background pixels
+ of an image: fits_rms_float and fits_rms_short (take an input
+ array of floats or shorts, respectively).
+
+ Fixes
+
+ - added the missing 64-bit integer case to set of "if (datatype)"
+ statements in the routine that returns information about a
+ particular column (ffgbclll).
+
+ - fixed a parsing error in ffexts in cases where an extension number
+ is followed by a semi-colon and then the column and row number of an
+ array in a binary table. Also removed an extraneous HISTORY keyword
+ that was being written when specifying an input image in a table cel.
+
+ - modified the routine that reads a table column returning a string
+ value (ffgcls) so that if the displayed numerical value is too
+ wide to fit in the specified length string, then it will return
+ a string of "*" characters instead of the number string.
+
+ - small change to fitsio.h to support a particular Fortran and C
+ compiler combination on a SGI Altix system
+
+ - added a test in the gunzip code to prevent seg. fault when trying
+ to uncompress a corrupted file (at least in some cases).
+
+ - fixed a rarely-occurring bug in the routine that copies a table
+ cell into an image; had to call the ffflsh call a few lines earlier.
+
+Version 3.01 - (in FTOOLS 6.1 release)
+
+ - modified fits_copy_image2cell to correctly copy all the appropriate
+ header keywords when copying an image into a table cell
+
+ - in eval.y, explicitly included the code for the lgamma function
+ instead of assuming it is available in a system library (e.g., the
+ lgamma function is currently not included in MS Visual++ libraries)
+
+ - modified the logic in fits_pixel_filter so that the default data
+ type of the output image will be promoted to at least BITPIX = -32
+ (a single precision floating point) if the expression that is being
+ evaluated resolves to a floating point result. If the expression
+ resolves to an integer result, the output image will have the same
+ BITPIX as the input image.
+
+ - in fits_copy_cell2image, added 5 more WCS keywords to the list of
+ keywords related to other columns that should be deleted in the
+ output image header.
+
+ - disabled code in cfileio.c that would write HISTORY keywords to the
+ output file in fits_copy_image2cell and cell2image, because some tasks
+ would not want these extraneous HISTORY keywords.
+
+ - added 2 new random number functions to the CFITSIO parser
+ RANDOMN() - produces a normal deviate (mean=0, stddev=1)
+ RANDOMP(X) - produces a Poisson deviate for an expected # of counts X
+
+ - in f77_wrap.h, removed the restriction that "g77Fortran" must be
+ defined on 64-bit Itanium machines before assuming that
+ sizeof(long) = 8. It appears that "long"s are always
+ 8 bytes long on this machine, regardless of what compilers are used.
+
+ - added test in fitsio.h so that LONGLONG cannot be multiply defined
+
+ - modified longnam.h so that both "fits_write_nulrows" and
+ "fits_write_nullrows" get replace by the string "ffprwu". This
+ fixes a documentation error regarding the long name of this
+ routine.
+
+ Bug fixes
+
+ - fixed a potential null character string dereferencing error in the
+ the ffphtb and ffphbn routines that write the FITS table keywords.
+ This concerned the optional TUNITn keywords.
+
+ - fixed a few issues in fits_copy_cell2image and fits_copy_image2cell
+ related to converting some WCS keyword between the image extension
+ form and the table cell form of the keyword. (cfileio.c)
+
+ - fixed bug in fits_translate_keyword (fitscore.c) that, e.g., caused
+ 'EQUINOX' to be translated to EQUINOXA' if the pattern is 'EQUINOXa'
+
+ - fixed 2 bugs that could affect 'tile compressed' floating point
+ images that contain NaN pixels (null pixels). First, the
+ ZBLANK keyword was not being written, and second, an integer
+ overflow could occur when computing the BZERO offset in the
+ compressed array. (quantize.c and imcompress.c)
+
+Version 3.006 - 20 February 2006 -(first full release of v3)
+
+ - enhanced the 'col' extended filename syntax to support keyword name
+ expressions like
+ [col error=sqrt(rate); #TUNIT# = 'counts/s'],
+ in which the trailing '#' will be replaced by the column number
+ of the most recently referenced column.
+
+ - fixed bug in the parse_data iterator work function that caused it
+ to fail to return a value of -1 in cases where only a selected
+ set of rows were to be processed. (affected Fv)
+
+ - added code to fitsio.h and cfortran.h to typedef LONGLONG to
+ the appropriate 8-byte integer data type. Most compilers now
+ support the 'long long' data type, but older MS Visual C++
+ compilers used '__int64' instead.
+
+ - made several small changes based on testing by Martin Reinecke:
+ o in eval.y, change 'int undef' to 'long undef'
+ o in getcold.c and getcole.c, fixed a couple format conversion
+ specifiers when displaying the value of long long variables.
+ o in fitsio.h, modified the definition of USE_LL_SUFFIX in the
+ case of Athon64 machines.
+ o in fitsio2.h, defined BYTESWAPPED in the case of SGI machines.
+ o in group.c, added 'include unistd.h' to get rid of compiler warning.
+
+Version 3.005 - 20 December 2005 (beta)
+
+ - cfortran.h has been enhanced to support 64-bit integer parameters
+ when calling C routines from Fortran. This modification was kindly
+ provided by Martin Reinecke (MPE, Garching).
+
+ - Many new Fortran wrapper routines have been added to support reading
+ and writing 64-bit integer values in FITS files. These new routines
+ are documented in the updated version of the 'FITSIO User's Guide'
+ for Fortran programmers.
+
+ - fixed a problem in the fits_get_keyclass routine that caused it
+ to not recognize the special COMMENT keywords at the beginning
+ of most FITS files that defines the FITS format.
+
+ - added a new check to the ffifile routine that parses the
+ input extended file name, to distinguish between a FITS extension
+ name that begins with 'pix', and a pixel filtering operator that
+ begins with the 'pix' keyword.
+
+ - small change to the WCSLIB interface routine, fits_read_wcstab, to
+ be more permissive in allowing the TDIMn keyword to be omitted for
+ degenerate coordinate array.
+
+Version 3.004 - 16 September 2005 (3rd public beta release)
+
+ - a major enhancement to the CFITSIO virtual file parser was provided
+ by Robert Wiegand (GSFC). One can now specify filtering operations
+ that will be applied on the fly to the pixel values in a FITS image.
+ For example [pix sqrt(X)] will create a virtual FITS image where the
+ pixel values are the square root of the input image pixels.
+
+ - modified region.c so that it interprets the position angles of regions
+ in a SAO style region file in the same way as DS9. In particular, if
+ the region parameters are given in WCS units, then the position angle
+ should be relative to the WCS coordinates of the image (increasing CCW
+ from West) instead of relative to the X/Y pixel coordinate system.
+ This only affects rotated images (e.g. with non-zero CROTA2 keyword)
+ with elliptical or rectangular regions.
+
+ - cleaned up fitsio.h and fitsio2.h to make the definition of LONGLONG
+ and BYTESWAPPED and MACHINE more logical.
+
+ - removed HAVE_LONGLONG everywhere since it is no longer needed (the
+ compiler now must have an 8-byte integer datatype to build CFITSIO).
+
+ - added support for the 64-bit IBM AIX platform
+
+ - modified eval.y so that the circle, ellipse, box, and near functions
+ can operate on vectors as well as scalars. This allows region filtering
+ on images that are stored in a vector cell in a binary table.
+ (provided by Craig Markwardt, GSFC)
+
+ New Routines
+
+ - added new fits_read_wcstab routine that serves as an interface to
+ Mark Calabretta's wcslib library for reading WCS information when
+ the -TAB table lookup convention is used in the FITS file.
+
+ - added new fits_write_nullrows routine, which writes null values into
+ every column of a specified range of rows in a FITS table.
+
+ - added the fits_translate_keyword and fits_translate_keywords utility
+ routines for converting the names of keywords when moving columns and
+ images around.
+
+ - added fits_copy_cell2image and fits_copy_image2cell routines for
+ copying an image extension (or primary array) to or from a cell
+ in a binary table vector column.
+
+ Bug fixes
+
+ - fixed a memory leak in eval.y; was fixed by changing a call to malloc
+ to cmalloc instead.
+
+ - changed the definition of several global variables at the beginning
+ of buffers.c to make them 'static' and thus invisible to applications
+ programs.
+
+ - in fits_copy_image_cell, added a call to flush the internal buffers
+ before reading from the file, in case any records had been modified.
+
+Version 3.003 - 28 July 2005 - 2nd public beta release (used in HEASOFT)
+
+ Enhancements
+
+ - enhanced the string column reading routing fits_get_col_str to
+ support cases where the user enters a null pointer (rather than
+ a null string) as the nulval parameter.
+
+ - modified the low level ffread and ffwrite routines that physically
+ read and write data from the FITS file so that they write the name
+ of the file to the CFITSIO error stack if an error occurs.
+
+ - changed the definition of fits_open_file into a macro that will test
+ that the version of the fitsio.h include file that was used to
+ build the CFITSIO library is the same version as included when
+ compiling the application program.
+
+ - made a simple modification to region.c to support regions files
+ of type "linear", for compatibility with ds9 and fv.
+
+ - modified the internal ffgpr routine (and renamed it ffgprll) so
+ that it returns the TNULL value as a LONGLONG parameter instead
+ of 'long'.
+
+ - in fits_get_col_display_width, added support for TFORM = 'k'
+
+ - modified fitsio.h, fitsio2.h, and f77_wrap.h to add test for (_SX)
+ to identify NEC SX supercomputers.
+
+ - modified eval_f.c to treat table columns of TULONG (unsigned long)
+ as a double. Also added support for TLONGLONG (8-byte integers) as
+ a double, which is only a temporary fix, since doubles only have about
+ 52 bits of precision.
+
+ - changed the 'blank' parameter in the internal ffgphd function to
+ to type LONGLONG to support integer*8 FITS images.
+
+ - when reading the TNULL keyword value, now use ffc2jj instead of
+ ffc2ii, to support integer*8 values.
+
+ Bug fixes
+
+ - fixed a significant bug when writing character strings to a variable
+ length array column of a binary table. This bug would result in some
+ unused space in the variable length heap, making the heap somewhat
+ larger than necessary. This in itself is usually a minor issue, since
+ the FITS files are perfectly valid, and other software should have
+ no problems reading back the characters strings. In some cases, however,
+ this problem could cause the program that is writing the table
+ to exit with a status = 108 disk read error.
+
+ - modified the standalone imcopy.c utility program to fix a memory allocation
+ bug when running on 64-bit platforms where sizeof(long) = 8 bytes.
+
+ - added an immediate 'return' statement to ffgtcl if the input status >0,
+ to prevent a segfault on some platforms.
+
+Version 3.002 - 15 April 2005 - first public beta release
+
+ - in drvrfile.c, if it fails to open the file for some reason, then
+ it should reset file_outfile to a null string, to avoid errors on
+ a subsequent call to open a file.
+
+ - updated fits_get_keyclass to recognize most of the WCS keywords
+ defined in the WCS Papers I and II.
+
+Version 3.001 - 15 March 2005 - released with HEASOFT 6.0
+
+ - numerous minor changes to the code to get rid of compiler warning
+ messages, mainly dealing with numerical data type casting and the
+ subsequent possible loss of precision in the result.
+
+Version 3.000 - 1 March 2005 (internal beta release)
+
+ Enhancements:
+
+ - Made major changes to many of the CFITSIO routines to more generally
+ support Large Files (> 2.1 GB). These changes are intended to
+ be 100% backward compatible with software that used the previous
+ versions of CFITSIO. The datatype of many of the integer parameters
+ in the CFITSIO functions has been changed from 'long' to 'LONGLONG',
+ which is typedef'ed to be equivalent to an 8-byte integer datatype on
+ each platform. With these changes, CFITSIO supports the following:
+ - integer FITS keywords with absolute values > 2**31
+ - FITS files with total sizes > 2**31 bytes
+ - FITS tables in which the number of rows, the row width, or
+ the size of the heap is > 2**31 bytes
+ - FITS images with dimensions > 2**31 bytes (support is still
+ somewhat limited, with full support to be added later).
+
+ - added another lexical parser function (thanks to Craig Markwardt,
+ GSFC): angsep computes the angular separation between 2 positions
+ on the celestial sphere.
+
+ - modified the image subset extraction code (e.g., when specifying
+ an image subregion when opening the file, such as
+ 'myimage.fits[21:40, 81:90]') so that in addition to
+ updating the values of the primary WCS keywords CRPIXk, CDELTi, and
+ CDj_i in the extracted/binned image, it also looks for and updates
+ any secondary WCS keywords (e.g., 'CRPIX1P').
+
+ - made cosmetic change to group.c, so that when a group table is
+ copied, any extra columns will be appended after the last existing
+ column, instead of being inserted before the last column.
+
+ - modified the routines that read tile compressed images to support
+ NULL as the input value for the 'anynul' parameter (meaning the
+ calling program does not want the value of 'anynul' returned to it).
+
+ - when constructing or parsing a year/month/day character string,
+ (e.g, when writing the DATE keyword) the routines now rigorously
+ verify that the input day value is valid for the given month
+ (including leap years).
+
+ - added some checks in cfileio.c to detect if some vital parameters
+ that are stored in memory have been corrupted. This can occur if
+ a user's program writes to areas of memory that it did not allocate.
+
+ - added the wcsutil_alternate.c source code file which contains
+ non-working stubs for the 2 Classic AIPS world coordinate
+ conversion routines that are distributed under the GNU General
+ Public License. Users who are unwilling or unable to distribute
+ their software under the General Public License may use this
+ alternate source file which has no GPL restrictions, instead
+ of wcsutil.c. This will have no effect on programs that use
+ CFITSIO as long as they do not call the fits_pix_to_world/ffwldp
+ or fits_world_to_pix/ffxypx routines.
+
+ Bug Fixes
+
+ - in ffdtdm (which parses the TDIMn keyword value), the check for
+ consistency between the length of the array defined by TDIMn and
+ the size of the TFORMn repeat value, is now not performed for variable
+ length array columns (which always have repeat = 1).
+
+ - fixed byteswapping problem when writing null values to non-standard
+ long integer FITS images with BITPIX = 64 and FITS table columns with
+ TFORMn = 'K'.
+
+ - fixed buffer overflow problem in fits_parse_template/ffgthd that
+ occurred only if the input template keyword value string was much
+ longer than can fit in an 80-char header record.
+
+Version 2.510 - 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 cumulative 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 byte 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 compiler. 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 scaling 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 specifying 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.
+
+ - non-sensible (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
+ precede 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/vendor/cfitsio/checksum.c b/vendor/cfitsio/checksum.c
new file mode 100644
index 00000000..c52b9ef5
--- /dev/null
+++ b/vendor/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;
+ LONGLONG 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 = (unsigned long) 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 (ffghadll(fptr, &headstart, &datastart, &dataend, status) > 0)
+ return(*status);
+
+ nrec = (long) ((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 = (long) ((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 = (long) ((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;
+ LONGLONG 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 = (unsigned long) tdouble;
+
+ /* get size of the HDU */
+ if (ffghadll(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 = (long) ((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 = (long) ((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 = (unsigned long) 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;
+ LONGLONG headstart, datastart, dataend;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get size of the HDU */
+ if (ffghadll(fptr, &headstart, &datastart, &dataend, status) > 0)
+ return(*status);
+
+ nrec = (long) ((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 = (long) ((datastart - headstart) / 2880);
+
+ /* accumulate the header checksum into the previous data checksum */
+ *hdusum = *datasum;
+ ffcsum(fptr, nrec, hdusum, status);
+
+ return(*status);
+}
+
diff --git a/vendor/cfitsio/config.log b/vendor/cfitsio/config.log
new file mode 100644
index 00000000..1c475ab0
--- /dev/null
+++ b/vendor/cfitsio/config.log
@@ -0,0 +1,591 @@
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by configure, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ $ ./configure --prefix=/d1/build.v216/iraf/ --exec-prefix=/d1/build.v216/iraf/ --disable-shared --bindir=/d1/build.v216/iraf/bin --libdir=/d1/build.v216/iraf/bin
+
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = tucana.tuc.noao.edu
+uname -m = i686
+uname -r = 2.6.18-194.17.1.el5
+uname -s = Linux
+uname -v = #1 SMP Wed Sep 29 12:51:33 EDT 2010
+
+/usr/bin/uname -p = unknown
+/bin/uname -X = unknown
+
+/bin/arch = i686
+/usr/bin/arch -k = unknown
+/usr/convex/getsysinfo = unknown
+/usr/bin/hostinfo = unknown
+/bin/machine = unknown
+/usr/bin/oslevel = unknown
+/bin/universe = unknown
+
+PATH: .
+PATH: /home/fitz/bin
+PATH: /usr/local/bin
+PATH: /sbin
+PATH: /usr/java/latest/bin
+PATH: /usr/sbin
+PATH: /usr/bin/X11
+PATH: /etc/
+PATH: usr/etc
+PATH: /usr/lib
+PATH: .
+PATH: /home/fitz/bin
+PATH: /usr/local/bin
+PATH: /sbin
+PATH: /usr/java/latest/bin
+PATH: /usr/sbin
+PATH: /usr/bin/X11
+PATH: /etc/
+PATH: usr/etc
+PATH: /usr/lib
+PATH: /usr/lib/jvm/jre//bin
+PATH: /usr/local/nvoss//bin
+PATH: /usr/local/nvoss//java/apache-ant-1.7.1/bin
+PATH: /usr/local/nvoss//python/bin
+PATH: /usr/kerberos/bin
+PATH: /usr/local/bin
+PATH: /bin
+PATH: /usr/bin
+PATH: /usr/X11R6/bin
+PATH: /home/fitz/dhs
+PATH: /home/fitz/dhs/bin
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+configure:2125: checking for uname
+configure:2141: found /bin/uname
+configure:2153: result: 1
+configure:2263: checking for gcc
+configure:2290: result: gcc
+configure:2519: checking for C compiler version
+configure:2528: gcc --version >&5
+gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-4)
+Copyright (C) 2006 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+configure:2539: $? = 0
+configure:2528: gcc -v >&5
+Reading specs from /usr/lib/../lib/gcc/i386-redhat-linux/3.4.6/specs
+Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,f77 --disable-libgcj --host=i386-redhat-linux
+Thread model: posix
+gcc version 3.4.6 20060404 (Red Hat 3.4.6-4)
+configure:2539: $? = 0
+configure:2528: gcc -V >&5
+gcc: `-V' option must have argument
+configure:2539: $? = 1
+configure:2528: gcc -qversion >&5
+gcc: unrecognized option `-qversion'
+gcc: no input files
+configure:2539: $? = 1
+configure:2559: checking whether the C compiler works
+configure:2581: gcc conftest.c >&5
+configure:2585: $? = 0
+configure:2633: result: yes
+configure:2636: checking for C compiler default output file name
+configure:2638: result: a.out
+configure:2644: checking for suffix of executables
+configure:2651: gcc -o conftest conftest.c >&5
+configure:2655: $? = 0
+configure:2677: result:
+configure:2699: checking whether we are cross compiling
+configure:2707: gcc -o conftest conftest.c >&5
+configure:2711: $? = 0
+configure:2718: ./conftest
+configure:2722: $? = 0
+configure:2737: result: no
+configure:2742: checking for suffix of object files
+configure:2764: gcc -c conftest.c >&5
+configure:2768: $? = 0
+configure:2789: result: o
+configure:2793: checking whether we are using the GNU C compiler
+configure:2812: gcc -c conftest.c >&5
+configure:2812: $? = 0
+configure:2821: result: yes
+configure:2830: checking whether gcc accepts -g
+configure:2850: gcc -c -g conftest.c >&5
+configure:2850: $? = 0
+configure:2891: result: yes
+configure:2908: checking for gcc option to accept ISO C89
+configure:2972: gcc -c -g -O2 conftest.c >&5
+configure:2972: $? = 0
+configure:2985: result: none needed
+configure:3018: checking for gfortran
+configure:3034: found /usr/bin/gfortran
+configure:3045: result: gfortran
+configure:3129: checking for ranlib
+configure:3156: result: ranlib
+configure:3185: checking how to run the C preprocessor
+configure:3216: gcc -E conftest.c
+configure:3216: $? = 0
+configure:3230: gcc -E conftest.c
+conftest.c:9:28: ac_nonexistent.h: No such file or directory
+configure:3230: $? = 1
+configure: failed program was:
+| /* confdefs.h */
+| #define PACKAGE_NAME ""
+| #define PACKAGE_TARNAME ""
+| #define PACKAGE_VERSION ""
+| #define PACKAGE_STRING ""
+| #define PACKAGE_BUGREPORT ""
+| #define PACKAGE_URL ""
+| /* end confdefs.h. */
+| #include <ac_nonexistent.h>
+configure:3255: result: gcc -E
+configure:3275: gcc -E conftest.c
+configure:3275: $? = 0
+configure:3289: gcc -E conftest.c
+conftest.c:9:28: ac_nonexistent.h: No such file or directory
+configure:3289: $? = 1
+configure: failed program was:
+| /* confdefs.h */
+| #define PACKAGE_NAME ""
+| #define PACKAGE_TARNAME ""
+| #define PACKAGE_VERSION ""
+| #define PACKAGE_STRING ""
+| #define PACKAGE_BUGREPORT ""
+| #define PACKAGE_URL ""
+| /* end confdefs.h. */
+| #include <ac_nonexistent.h>
+configure:3318: checking for grep that handles long lines and -e
+configure:3376: result: /bin/grep
+configure:3381: checking for egrep
+configure:3443: result: /bin/grep -E
+configure:3448: checking for ANSI C header files
+configure:3468: gcc -c -g -O2 conftest.c >&5
+configure:3468: $? = 0
+configure:3541: gcc -o conftest -g -O2 conftest.c >&5
+configure:3541: $? = 0
+configure:3541: ./conftest
+configure:3541: $? = 0
+configure:3552: result: yes
+configure:3565: checking for sys/types.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3565: checking for sys/stat.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3565: checking for stdlib.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3565: checking for string.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3565: checking for memory.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3565: checking for strings.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3565: checking for inttypes.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3565: checking for stdint.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3565: checking for unistd.h
+configure:3565: gcc -c -g -O2 conftest.c >&5
+configure:3565: $? = 0
+configure:3565: result: yes
+configure:3580: checking for stdlib.h
+configure:3580: result: yes
+configure:3580: checking for string.h
+configure:3580: result: yes
+configure:3580: checking math.h usability
+configure:3580: gcc -c -g -O2 conftest.c >&5
+configure:3580: $? = 0
+configure:3580: result: yes
+configure:3580: checking math.h presence
+configure:3580: gcc -E conftest.c
+configure:3580: $? = 0
+configure:3580: result: yes
+configure:3580: checking for math.h
+configure:3580: result: yes
+configure:3580: checking limits.h usability
+configure:3580: gcc -c -g -O2 conftest.c >&5
+configure:3580: $? = 0
+configure:3580: result: yes
+configure:3580: checking limits.h presence
+configure:3580: gcc -E conftest.c
+configure:3580: $? = 0
+configure:3580: result: yes
+configure:3580: checking for limits.h
+configure:3580: result: yes
+configure:3603: gcc -c -g -O2 conftest.c >&5
+configure:3603: $? = 0
+configure:3943: checking "whether ftruncate works"
+configure:3959: gcc -o conftest -g -O2 -Dg77Fortran -fPIC conftest.c >&5
+configure:3959: $? = 0
+configure:3963: result: "yes"
+configure:3977: checking "whether long long is defined"
+configure:3993: gcc -c -g -O2 -Dg77Fortran -fPIC conftest.c >&5
+configure:3993: $? = 0
+configure:3997: result: "yes"
+configure:4018: checking "whether system V style IPC services are supported"
+configure:4039: gcc -o conftest -g -O2 -Dg77Fortran -fPIC conftest.c >&5
+configure:4039: $? = 0
+configure:4044: result: "yes"
+configure:4060: checking "do we have flock_t defined in sys/fcntl.h"
+configure:4076: gcc -c -g -O2 -Dg77Fortran -fPIC conftest.c >&5
+conftest.c: In function `main':
+conftest.c:34: error: `flock_t' undeclared (first use in this function)
+conftest.c:34: error: (Each undeclared identifier is reported only once
+conftest.c:34: error: for each function it appears in.)
+conftest.c:34: error: syntax error before "filler"
+configure:4076: $? = 1
+configure: failed program was:
+| /* confdefs.h */
+| #define PACKAGE_NAME ""
+| #define PACKAGE_TARNAME ""
+| #define PACKAGE_VERSION ""
+| #define PACKAGE_STRING ""
+| #define PACKAGE_BUGREPORT ""
+| #define PACKAGE_URL ""
+| #define STDC_HEADERS 1
+| #define HAVE_SYS_TYPES_H 1
+| #define HAVE_SYS_STAT_H 1
+| #define HAVE_STDLIB_H 1
+| #define HAVE_STRING_H 1
+| #define HAVE_MEMORY_H 1
+| #define HAVE_STRINGS_H 1
+| #define HAVE_INTTYPES_H 1
+| #define HAVE_STDINT_H 1
+| #define HAVE_UNISTD_H 1
+| #define HAVE_STDLIB_H 1
+| #define HAVE_STRING_H 1
+| #define HAVE_MATH_H 1
+| #define HAVE_LIMITS_H 1
+| #define _LARGEFILE_SOURCE 1
+| #define _FILE_OFFSET_BITS 64
+| #define HAVE_FTRUNCATE 1
+| #define HAVE_LONGLONG 1
+| #define HAVE_SHMEM_SERVICES 1
+| /* end confdefs.h. */
+| #include <sys/fcntl.h>
+|
+| int
+| main ()
+| {
+|
+| flock_t filler;
+|
+| ;
+| return 0;
+| }
+configure:4084: result: "no"
+configure:4090: checking "do we have flock_t defined in sys/flock.h"
+configure:4106: gcc -c -g -O2 -Dg77Fortran -fPIC conftest.c >&5
+conftest.c:28:23: sys/flock.h: No such file or directory
+conftest.c: In function `main':
+conftest.c:34: error: `flock_t' undeclared (first use in this function)
+conftest.c:34: error: (Each undeclared identifier is reported only once
+conftest.c:34: error: for each function it appears in.)
+conftest.c:34: error: syntax error before "filler"
+configure:4106: $? = 1
+configure: failed program was:
+| /* confdefs.h */
+| #define PACKAGE_NAME ""
+| #define PACKAGE_TARNAME ""
+| #define PACKAGE_VERSION ""
+| #define PACKAGE_STRING ""
+| #define PACKAGE_BUGREPORT ""
+| #define PACKAGE_URL ""
+| #define STDC_HEADERS 1
+| #define HAVE_SYS_TYPES_H 1
+| #define HAVE_SYS_STAT_H 1
+| #define HAVE_STDLIB_H 1
+| #define HAVE_STRING_H 1
+| #define HAVE_MEMORY_H 1
+| #define HAVE_STRINGS_H 1
+| #define HAVE_INTTYPES_H 1
+| #define HAVE_STDINT_H 1
+| #define HAVE_UNISTD_H 1
+| #define HAVE_STDLIB_H 1
+| #define HAVE_STRING_H 1
+| #define HAVE_MATH_H 1
+| #define HAVE_LIMITS_H 1
+| #define _LARGEFILE_SOURCE 1
+| #define _FILE_OFFSET_BITS 64
+| #define HAVE_FTRUNCATE 1
+| #define HAVE_LONGLONG 1
+| #define HAVE_SHMEM_SERVICES 1
+| /* end confdefs.h. */
+| #include <sys/flock.h>
+|
+| int
+| main ()
+| {
+|
+| flock_t filler;
+|
+| ;
+| return 0;
+| }
+configure:4114: result: "no"
+configure:4125: checking "do we have union semun defined"
+configure:4143: gcc -c -g -O2 -Dg77Fortran -fPIC conftest.c >&5
+conftest.c: In function `main':
+conftest.c:36: error: storage size of 'filler' isn't known
+configure:4143: $? = 1
+configure: failed program was:
+| /* confdefs.h */
+| #define PACKAGE_NAME ""
+| #define PACKAGE_TARNAME ""
+| #define PACKAGE_VERSION ""
+| #define PACKAGE_STRING ""
+| #define PACKAGE_BUGREPORT ""
+| #define PACKAGE_URL ""
+| #define STDC_HEADERS 1
+| #define HAVE_SYS_TYPES_H 1
+| #define HAVE_SYS_STAT_H 1
+| #define HAVE_STDLIB_H 1
+| #define HAVE_STRING_H 1
+| #define HAVE_MEMORY_H 1
+| #define HAVE_STRINGS_H 1
+| #define HAVE_INTTYPES_H 1
+| #define HAVE_STDINT_H 1
+| #define HAVE_UNISTD_H 1
+| #define HAVE_STDLIB_H 1
+| #define HAVE_STRING_H 1
+| #define HAVE_MATH_H 1
+| #define HAVE_LIMITS_H 1
+| #define _LARGEFILE_SOURCE 1
+| #define _FILE_OFFSET_BITS 64
+| #define HAVE_FTRUNCATE 1
+| #define HAVE_LONGLONG 1
+| #define HAVE_SHMEM_SERVICES 1
+| /* end confdefs.h. */
+| #include <sys/ipc.h>
+| #include <sys/shm.h>
+| #include <sys/sem.h>
+|
+| int
+| main ()
+| {
+|
+| union semun filler;
+|
+| ;
+| return 0;
+| }
+configure:4151: result: "no"
+configure:4159: checking for library containing gethostbyname
+configure:4190: gcc -o conftest -g -O2 -Dg77Fortran -fPIC conftest.c >&5
+configure:4190: $? = 0
+configure:4207: result: none required
+configure:4217: checking for library containing connect
+configure:4248: gcc -o conftest -g -O2 -Dg77Fortran -fPIC conftest.c >&5
+configure:4248: $? = 0
+configure:4265: result: none required
+configure:4485: creating ./config.status
+
+## ---------------------- ##
+## Running config.status. ##
+## ---------------------- ##
+
+This file was extended by config.status, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES =
+ CONFIG_HEADERS =
+ CONFIG_LINKS =
+ CONFIG_COMMANDS =
+ $ ./config.status
+
+on tucana.tuc.noao.edu
+
+config.status:748: creating Makefile
+configure:5498: WARNING: unrecognized options: --disable-shared
+configure:5654: creating ./config.status
+
+## ---------------------- ##
+## Running config.status. ##
+## ---------------------- ##
+
+This file was extended by config.status, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES =
+ CONFIG_HEADERS =
+ CONFIG_LINKS =
+ CONFIG_COMMANDS =
+ $ ./config.status
+
+on tucana.tuc.noao.edu
+
+config.status:749: creating Makefile
+config.status:749: creating cfitsio.pc
+configure:6668: WARNING: unrecognized options: --disable-shared
+configure:6674: result:
+configure:6676: result: Congratulations, Makefile update was successful.
+configure:6678: result: You may want to run "make" now.
+configure:6680: result:
+
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+
+ac_cv_c_compiler_gnu=yes
+ac_cv_env_CC_set=set
+ac_cv_env_CC_value=gcc
+ac_cv_env_CFLAGS_set=
+ac_cv_env_CFLAGS_value=
+ac_cv_env_CPPFLAGS_set=
+ac_cv_env_CPPFLAGS_value=
+ac_cv_env_CPP_set=
+ac_cv_env_CPP_value=
+ac_cv_env_LDFLAGS_set=
+ac_cv_env_LDFLAGS_value=
+ac_cv_env_LIBS_set=
+ac_cv_env_LIBS_value=
+ac_cv_env_build_alias_set=
+ac_cv_env_build_alias_value=
+ac_cv_env_host_alias_set=
+ac_cv_env_host_alias_value=
+ac_cv_env_target_alias_set=
+ac_cv_env_target_alias_value=
+ac_cv_header_inttypes_h=yes
+ac_cv_header_limits_h=yes
+ac_cv_header_math_h=yes
+ac_cv_header_memory_h=yes
+ac_cv_header_stdc=yes
+ac_cv_header_stdint_h=yes
+ac_cv_header_stdlib_h=yes
+ac_cv_header_string_h=yes
+ac_cv_header_strings_h=yes
+ac_cv_header_sys_stat_h=yes
+ac_cv_header_sys_types_h=yes
+ac_cv_header_unistd_h=yes
+ac_cv_objext=o
+ac_cv_path_EGREP='/bin/grep -E'
+ac_cv_path_GREP=/bin/grep
+ac_cv_prog_CPP='gcc -E'
+ac_cv_prog_FC=gfortran
+ac_cv_prog_ac_ct_CC=gcc
+ac_cv_prog_ac_ct_RANLIB=ranlib
+ac_cv_prog_cc_c89=
+ac_cv_prog_cc_g=yes
+ac_cv_prog_uname_found=1
+ac_cv_search_connect='none required'
+ac_cv_search_gethostbyname='none required'
+
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+
+ARCH='linux'
+CC='gcc'
+CFLAGS='-g -O2 -Dg77Fortran -fPIC'
+CPP='gcc -E'
+CPPFLAGS=''
+DEFS='-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MATH_H=1 -DHAVE_LIMITS_H=1 -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DHAVE_FTRUNCATE=1 -DHAVE_LONGLONG=1 -DHAVE_SHMEM_SERVICES=1 -DHAVE_NET_SERVICES=1'
+ECHO_C=''
+ECHO_N='-n'
+ECHO_T=''
+EGREP='/bin/grep -E'
+EXEEXT=''
+F77_WRAPPERS='${FITSIO_SRC}'
+FC='gfortran'
+GCCVERSION='3.4.6'
+GREP='/bin/grep'
+INSTALL_ROOT='${prefix}'
+LDFLAGS=''
+LIBOBJS=''
+LIBPRE=''
+LIBS=''
+LTLIBOBJS=''
+OBJEXT='o'
+PACKAGE_BUGREPORT=''
+PACKAGE_NAME=''
+PACKAGE_STRING=''
+PACKAGE_TARNAME=''
+PACKAGE_URL=''
+PACKAGE_VERSION=''
+PATH_SEPARATOR=':'
+RANLIB='ranlib'
+SHELL='/bin/sh'
+SHLIB_LD='gcc -shared'
+SHLIB_SUFFIX='.so'
+SSE_FLAGS=''
+ac_ct_CC='gcc'
+bindir='/d1/build.v216/iraf/bin'
+build_alias=''
+datadir='${datarootdir}'
+datarootdir='${prefix}/share'
+docdir='${datarootdir}/doc/${PACKAGE}'
+dvidir='${docdir}'
+exec_prefix='/d1/build.v216/iraf'
+host_alias=''
+htmldir='${docdir}'
+includedir='${prefix}/include'
+infodir='${datarootdir}/info'
+libdir='/d1/build.v216/iraf/bin'
+libexecdir='${exec_prefix}/libexec'
+localedir='${datarootdir}/locale'
+localstatedir='${prefix}/var'
+mandir='${datarootdir}/man'
+my_shmem='${SOURCES_SHMEM}'
+oldincludedir='/usr/include'
+pdfdir='${docdir}'
+prefix='/d1/build.v216/iraf'
+program_transform_name='s,x,x,'
+psdir='${docdir}'
+sbindir='${exec_prefix}/sbin'
+sharedstatedir='${prefix}/com'
+sysconfdir='${prefix}/etc'
+target_alias=''
+uname_found='1'
+
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+
+/* confdefs.h */
+#define PACKAGE_NAME ""
+#define PACKAGE_TARNAME ""
+#define PACKAGE_VERSION ""
+#define PACKAGE_STRING ""
+#define PACKAGE_BUGREPORT ""
+#define PACKAGE_URL ""
+#define STDC_HEADERS 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+#define HAVE_MATH_H 1
+#define HAVE_LIMITS_H 1
+#define _LARGEFILE_SOURCE 1
+#define _FILE_OFFSET_BITS 64
+#define HAVE_FTRUNCATE 1
+#define HAVE_LONGLONG 1
+#define HAVE_SHMEM_SERVICES 1
+#define HAVE_NET_SERVICES 1
+
+configure: exit 0
diff --git a/vendor/cfitsio/config.status b/vendor/cfitsio/config.status
new file mode 100755
index 00000000..17c795a5
--- /dev/null
+++ b/vendor/cfitsio/config.status
@@ -0,0 +1,916 @@
+#! /bin/sh
+# Generated by configure.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+# Files that config.status was made for.
+config_files=" Makefile cfitsio.pc"
+
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+ac_cs_config="'--prefix=/d1/build.v216/iraf/' '--exec-prefix=/d1/build.v216/iraf/' '--disable-shared' '--bindir=/d1/build.v216/iraf/bin' '--libdir=/d1/build.v216/iraf/bin' 'CC=gcc'"
+ac_cs_version="\
+config.status
+configured by ./configure, generated by GNU Autoconf 2.68,
+ with options \"$ac_cs_config\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='/iraf/build/iraf/vendor/cfitsio'
+srcdir='.'
+test -n "$AWK" || AWK=awk
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+if $ac_cs_recheck; then
+ set X '/bin/sh' './configure' '--prefix=/d1/build.v216/iraf/' '--exec-prefix=/d1/build.v216/iraf/' '--disable-shared' '--bindir=/d1/build.v216/iraf/bin' '--libdir=/d1/build.v216/iraf/bin' 'CC=gcc' $ac_configure_extra_args --no-create --no-recursion
+ shift
+ $as_echo "running CONFIG_SHELL=/bin/sh $*" >&6
+ CONFIG_SHELL='/bin/sh'
+ export CONFIG_SHELL
+ exec "$@"
+fi
+
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "cfitsio.pc") CONFIG_FILES="$CONFIG_FILES cfitsio.pc" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+cat >>"$ac_tmp/subs1.awk" <<\_ACAWK &&
+S["LTLIBOBJS"]=""
+S["LIBOBJS"]=""
+S["my_shmem"]="${SOURCES_SHMEM}"
+S["F77_WRAPPERS"]="${FITSIO_SRC}"
+S["SHLIB_SUFFIX"]=".so"
+S["SHLIB_LD"]="gcc -shared"
+S["LIBPRE"]=""
+S["ARCH"]="linux"
+S["GCCVERSION"]="3.4.6"
+S["SSE_FLAGS"]=""
+S["EGREP"]="/bin/grep -E"
+S["GREP"]="/bin/grep"
+S["CPP"]="gcc -E"
+S["RANLIB"]="ranlib"
+S["FC"]="gfortran"
+S["OBJEXT"]="o"
+S["EXEEXT"]=""
+S["ac_ct_CC"]="gcc"
+S["CPPFLAGS"]=""
+S["LDFLAGS"]=""
+S["CFLAGS"]="-g -O2 -Dg77Fortran -fPIC"
+S["CC"]="gcc"
+S["uname_found"]="1"
+S["INSTALL_ROOT"]="${prefix}"
+S["target_alias"]=""
+S["host_alias"]=""
+S["build_alias"]=""
+S["LIBS"]=""
+S["ECHO_T"]=""
+S["ECHO_N"]="-n"
+S["ECHO_C"]=""
+S["DEFS"]="-DPACKAGE_NAME=\\\"\\\" -DPACKAGE_TARNAME=\\\"\\\" -DPACKAGE_VERSION=\\\"\\\" -DPACKAGE_STRING=\\\"\\\" -DPACKAGE_BUGREPORT=\\\"\\\" -DPACKAGE_URL=\\\"\\\" -DSTDC_HEADERS=1"\
+" -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT"\
+"_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MATH_H=1 -DHAVE_LIMITS_H=1 -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DHAVE_FTR"\
+"UNCATE=1 -DHAVE_LONGLONG=1 -DHAVE_SHMEM_SERVICES=1 -DHAVE_NET_SERVICES=1"
+S["mandir"]="${datarootdir}/man"
+S["localedir"]="${datarootdir}/locale"
+S["libdir"]="/d1/build.v216/iraf/bin"
+S["psdir"]="${docdir}"
+S["pdfdir"]="${docdir}"
+S["dvidir"]="${docdir}"
+S["htmldir"]="${docdir}"
+S["infodir"]="${datarootdir}/info"
+S["docdir"]="${datarootdir}/doc/${PACKAGE}"
+S["oldincludedir"]="/usr/include"
+S["includedir"]="${prefix}/include"
+S["localstatedir"]="${prefix}/var"
+S["sharedstatedir"]="${prefix}/com"
+S["sysconfdir"]="${prefix}/etc"
+S["datadir"]="${datarootdir}"
+S["datarootdir"]="${prefix}/share"
+S["libexecdir"]="${exec_prefix}/libexec"
+S["sbindir"]="${exec_prefix}/sbin"
+S["bindir"]="/d1/build.v216/iraf/bin"
+S["program_transform_name"]="s,x,x,"
+S["prefix"]="/d1/build.v216/iraf"
+S["exec_prefix"]="/d1/build.v216/iraf"
+S["PACKAGE_URL"]=""
+S["PACKAGE_BUGREPORT"]=""
+S["PACKAGE_STRING"]=""
+S["PACKAGE_VERSION"]=""
+S["PACKAGE_TARNAME"]=""
+S["PACKAGE_NAME"]=""
+S["PATH_SEPARATOR"]=":"
+S["SHELL"]="/bin/sh"
+_ACAWK
+cat >>"$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+ ac_datarootdir_hack='
+ s&@datadir@&${datarootdir}&g
+ s&@docdir@&${datarootdir}/doc/${PACKAGE}&g
+ s&@infodir@&${datarootdir}/info&g
+ s&@localedir@&${datarootdir}/locale&g
+ s&@mandir@&${datarootdir}/man&g
+ s&\${datarootdir}&${prefix}/share&g' ;;
+esac
+ac_sed_extra="/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}
+
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
diff --git a/vendor/cfitsio/configure b/vendor/cfitsio/configure
new file mode 100755
index 00000000..f8043590
--- /dev/null
+++ b/vendor/cfitsio/configure
@@ -0,0 +1,6682 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.68.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ # Preserve -v and -x to the replacement shell.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+ esac
+ exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="fitscore.c"
+ac_default_prefix=`pwd`
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+my_shmem
+F77_WRAPPERS
+SHLIB_SUFFIX
+SHLIB_LD
+LIBPRE
+ARCH
+GCCVERSION
+SSE_FLAGS
+EGREP
+GREP
+CPP
+RANLIB
+FC
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+uname_found
+INSTALL_ROOT
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_reentrant
+enable_sse2
+enable_ssse3
+enable_hera
+with_gsiftp_flavour
+with_gsiftp
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+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=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$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 ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=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 ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used" >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# 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 the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-reentrant Enable reentrant multithreading
+ --enable-sse2 Enable use of instructions in the SSE2 extended
+ instruction set
+ --enable-ssse3 Enable use of instructions in the SSSE3 extended
+ instruction set
+ --enable-hera Build for HERA (ASD use only)
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-gsiftp-flavour[=PATH]
+ Enable Globus Toolkit gsiftp protocol support
+ --with-gsiftp[=PATH] Enable Globus Toolkit gsiftp protocol support
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.68
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+#--------------------------------------------------------------------
+# Command options
+#--------------------------------------------------------------------
+
+# Check whether --enable-reentrant was given.
+if test "${enable_reentrant+set}" = set; then :
+ enableval=$enable_reentrant; if test $enableval = yes; then BUILD_REENTRANT=yes; fi
+
+fi
+
+
+SSE_FLAGS=""
+# Check whether --enable-sse2 was given.
+if test "${enable_sse2+set}" = set; then :
+ enableval=$enable_sse2; if test $enableval = yes; then SSE_FLAGS="-msse2"; fi
+
+fi
+
+
+# Check whether --enable-ssse3 was given.
+if test "${enable_ssse3+set}" = set; then :
+ enableval=$enable_ssse3; if test $enableval = yes; then SSE_FLAGS="$SSE_FLAGS -mssse3"; fi
+
+fi
+
+
+# Define BUILD_HERA when building for HERA project to activate code in
+# drvrfile.c (by way of fitsio2.h):
+# Check whether --enable-hera was given.
+if test "${enable_hera+set}" = set; then :
+ enableval=$enable_hera; if test $enableval = yes; then BUILD_HERA=yes; fi
+
+fi
+
+if test "x$BUILD_HERA" = xyes; then
+ $as_echo "#define BUILD_HERA 1" >>confdefs.h
+
+fi
+
+
+# Check whether --with-gsiftp-flavour was given.
+if test "${with_gsiftp_flavour+set}" = set; then :
+ withval=$with_gsiftp_flavour; if test "x$withval" != "xno"; then
+
+ if test "x$withval" != "xyes" ; then
+ GSIFTP_FLAVOUR=${withval}
+ fi
+
+$as_echo "#define GSIFTP_FLAVOUR 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+
+# Check whether --with-gsiftp was given.
+if test "${with_gsiftp+set}" = set; then :
+ withval=$with_gsiftp; if test "x$withval" != "xno"; then
+
+ if test "x$withval" != "xyes" ; then
+ CFLAGS="$CFLAGS -I${withval}/include/${GSIFTP_FLAVOUR}"
+ LDFLAGS="$LDFLAGS -L${withval}/lib -lglobus_ftp_client_${GSIFTP_FLAVOUR}"
+ HAVE_GSIFTP=yes
+ fi
+
+$as_echo "#define HAVE_GSIFTP 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+#--------------------------------------------------------------------
+# Check for install location prefix
+#--------------------------------------------------------------------
+
+
+
+# make will complain about duplicate targets for the install directories
+# if prefix == exec_prefix
+INSTALL_ROOT='${prefix}'
+
+test "$exec_prefix" != NONE -a "$prefix" != "$exec_prefix" \
+ && INSTALL_ROOT="$INSTALL_ROOT "'${exec_prefix}'
+
+
+#--------------------------------------------------------------------
+# 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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_uname_found+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$uname_found"; then
+ ac_cv_prog_uname_found="$uname_found" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_uname_found="1"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $uname_found" >&5
+$as_echo "$uname_found" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&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
+
+
+
+# Try first to find a proprietary C compiler, then gcc
+if test "x$CC" = x; then
+ for ac_prog in cc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+done
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_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 $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+if test "x$FC" = "xnone" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: cfitsio: == Fortran compiler search has been overridden" >&5
+$as_echo "$as_me: cfitsio: == Fortran compiler search has been overridden" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: cfitsio: == Cfitsio will be built without Fortran wrapper support" >&5
+$as_echo "$as_me: cfitsio: == Cfitsio will be built without Fortran wrapper support" >&6;}
+ FC=
+ F77_WRAPPERS=
+else
+ for ac_prog in gfortran g95 g77 f77 ifort f95 f90 xlf cf77 gf77 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
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_FC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$FC"; then
+ ac_cv_prog_FC="$FC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_FC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+FC=$ac_cv_prog_FC
+if test -n "$FC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FC" >&5
+$as_echo "$FC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$FC" && break
+done
+test -n "$FC" || FC="notfound"
+
+ if test $FC = 'notfound' ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cfitsio: == No acceptable Fortran compiler found in \$PATH" >&5
+$as_echo "$as_me: WARNING: cfitsio: == No acceptable Fortran compiler found in \$PATH" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: cfitsio: == Adding wrapper support for GNU Fortran by default" >&5
+$as_echo "$as_me: cfitsio: == Adding wrapper support for GNU Fortran by default" >&6;}
+ CFORTRANFLAGS="-Dg77Fortran"
+ F77_WRAPPERS="\${FITSIO_SRC}"
+ 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
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in stdlib.h string.h math.h limits.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ ANSI_HEADER=yes
+else
+ ANSI_HEADER=no
+fi
+
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+void d( int , double)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ PROTO=yes
+else
+ PROTO=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+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
+
+if test "x$SSE_FLAGS" != x; then
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $SSE_FLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts $SSE_FLAGS" >&5
+$as_echo_n "checking whether $CC accepts $SSE_FLAGS... " >&6; }
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ c_has_option=yes
+else
+ c_has_option=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $c_has_option" >&5
+$as_echo "$c_has_option" >&6; }
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ if test "$c_has_option" = no; then SSE_FLAGS=""; fi
+ CFLAGS="$SAVE_CFLAGS"
+fi
+
+
+CFLAGS="$CFLAGS"
+LIBPRE=""
+
+case $system in
+ Darwin-*)
+ # Build for i386 & x86_64 architectures on Darwin 10.x or newer:
+
+ case $system in
+ Darwin-[56789]*)
+ ;;
+ *)
+
+ # Test to see whether the C compiler accepts the "-arch"
+ # flags for building "universal" binaries (Apple XCode only):
+ SAVE_CFLAGS="$CFLAGS"
+ C_UNIV_SWITCH="-arch i386 -arch x86_64"
+ CFLAGS="$CFLAGS $C_UNIV_SWITCH"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts $C_UNIV_SWITCH" >&5
+$as_echo_n "checking whether $CC accepts $C_UNIV_SWITCH... " >&6; }
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ c_has_option=yes
+else
+ c_has_option=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $c_has_option" >&5
+$as_echo "$c_has_option" >&6; }
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ # Value of C_UNIV_SWITCH will be needed later for SHLIB_LD:
+ if test "$c_has_option" = no; then C_UNIV_SWITCH=""; fi
+ CFLAGS="$SAVE_CFLAGS $C_UNIV_SWITCH"
+ ;;
+ esac
+ # Darwin can be powerpc, i386, or x86_64
+ ARCH=`uname -p`
+ EXT="darwin"
+ # For large file support (but may break Absoft compilers):
+ $as_echo "#define _LARGEFILE_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _FILE_OFFSET_BITS 64" >>confdefs.h
+
+ ;;
+ 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
+ # We need libm on Solaris:
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for frexp in -lm" >&5
+$as_echo_n "checking for frexp in -lm... " >&6; }
+if ${ac_cv_lib_m_frexp+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char frexp ();
+int
+main ()
+{
+return frexp ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_frexp=yes
+else
+ ac_cv_lib_m_frexp=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_frexp" >&5
+$as_echo "$ac_cv_lib_m_frexp" >&6; }
+if test "x$ac_cv_lib_m_frexp" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ # For large file support:
+ $as_echo "#define _LARGEFILE_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _FILE_OFFSET_BITS 64" >>confdefs.h
+
+ ;;
+ 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"
+ # For large file support:
+ $as_echo "#define _LARGEFILE_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _FILE_OFFSET_BITS 64" >>confdefs.h
+
+ ;;
+ 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 $GCC in
+ yes)
+ GCCVERSION="`$CC -dumpversion 2>&1`"
+ echo "cfitsio: == Using gcc version $GCCVERSION"
+
+
+ gcc_test=`echo $GCCVERSION | grep -c '2\.[45678]'`
+
+ if test $gcc_test -gt 0
+ then
+
+ CFLAGS=`echo $CFLAGS | sed 's:-O[^ ]* *::'`
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: This gcc is pretty old. Disabling optimization to be safe." >&5
+$as_echo "$as_me: WARNING: This gcc is pretty old. Disabling optimization to be safe." >&2;}
+ fi
+ ;;
+ no)
+ echo "cfitsio: Old CFLAGS is $CFLAGS"
+ CFLAGS=`echo $CFLAGS | sed -e "s/-g/-O/"`
+ case $system in
+ SunOS-5*)
+
+ if test `echo $CFLAGS | grep -c fast` -gt 0
+ then
+ echo "cfitsio: Replacing -fast with -O3"
+ CFLAGS=`echo $CFLAGS | sed 's:-fast:-O3:'`
+ fi
+
+ 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
+ cygwin)
+ SHLIB_LD="$CC -shared"
+ SHLIB_SUFFIX=".dll"
+ ;;
+ darwin)
+
+ case $system in
+ Darwin-[56789]*)
+ SHLIB_LD="$CC -dynamiclib"
+ ;;
+ *)
+ # Build for i386 & x86_64 architectures on Darwin 10.x or newer:
+ SHLIB_LD="$CC -dynamiclib $C_UNIV_SWITCH"
+ ;;
+ esac
+
+ SHLIB_SUFFIX=".dylib"
+ lhea_shlib_cflags="-fPIC -fno-common"
+ ;;
+ hpu)
+ SHLIB_LD="ld -b"
+ SHLIB_SUFFIX=".sl"
+ ;;
+ lnx)
+ 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"
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to determine how to make a shared library" >&5
+$as_echo "$as_me: WARNING: Unable to determine how to make a shared library" >&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 && test "x$EXT" != xcygwin; 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 ================
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking \"whether ftruncate works\"" >&5
+$as_echo_n "checking \"whether ftruncate works\"... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <unistd.h>
+
+int
+main ()
+{
+
+ftruncate(0, 0);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define HAVE_FTRUNCATE 1" >>confdefs.h
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"yes\"" >&5
+$as_echo "\"yes\"" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"no\"" >&5
+$as_echo "\"no\"" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+# ---------------------------------------------------------
+# some systems define long long for 64-bit ints
+# ---------------------------------------------------------
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking \"whether long long is defined\"" >&5
+$as_echo_n "checking \"whether long long is defined\"... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+int
+main ()
+{
+
+long long filler;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define HAVE_LONGLONG 1" >>confdefs.h
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"yes\"" >&5
+$as_echo "\"yes\"" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"no\"" >&5
+$as_echo "\"no\"" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# ==================== 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
+# -------------------------------------------------------------------------
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking \"whether system V style IPC services are supported\"" >&5
+$as_echo_n "checking \"whether system V style IPC services are supported\"... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end 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;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define HAVE_SHMEM_SERVICES 1" >>confdefs.h
+
+my_shmem=\${SOURCES_SHMEM}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"yes\"" >&5
+$as_echo "\"yes\"" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"no\"" >&5
+$as_echo "\"no\"" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+
+# -------------------------------------------------------------------------
+# some systems define flock_t, for others we have to define it ourselves
+# -------------------------------------------------------------------------
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking \"do we have flock_t defined in sys/fcntl.h\"" >&5
+$as_echo_n "checking \"do we have flock_t defined in sys/fcntl.h\"... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/fcntl.h>
+
+int
+main ()
+{
+
+flock_t filler;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define HAVE_FLOCK_T 1" >>confdefs.h
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"yes\"" >&5
+$as_echo "\"yes\"" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"no\"" >&5
+$as_echo "\"no\"" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test "$HAVE_FLOCK_T" != 1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking \"do we have flock_t defined in sys/flock.h\"" >&5
+$as_echo_n "checking \"do we have flock_t defined in sys/flock.h\"... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/flock.h>
+
+int
+main ()
+{
+
+ flock_t filler;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ $as_echo "#define HAVE_FLOCK_T 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"yes\"" >&5
+$as_echo "\"yes\"" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"no\"" >&5
+$as_echo "\"no\"" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+# -------------------------------------------------------------------------
+# there are some idiosyncrasies with semun defs (used in semxxx). Solaris
+# does not define it at all
+# -------------------------------------------------------------------------
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking \"do we have union semun defined\"" >&5
+$as_echo_n "checking \"do we have union semun defined\"... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+int
+main ()
+{
+
+union semun filler;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define HAVE_UNION_SEMUN 1" >>confdefs.h
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"yes\"" >&5
+$as_echo "\"yes\"" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"no\"" >&5
+$as_echo "\"no\"" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# ==================== END OF SHARED MEMORY DRIVER SECTION ================
+# ================= test for the unix networking functions ================
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5
+$as_echo_n "checking for library containing gethostbyname... " >&6; }
+if ${ac_cv_search_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' nsl; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_gethostbyname=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_gethostbyname+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_gethostbyname+:} false; then :
+
+else
+ ac_cv_search_gethostbyname=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5
+$as_echo "$ac_cv_search_gethostbyname" >&6; }
+ac_res=$ac_cv_search_gethostbyname
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+ cfitsio_have_nsl=1
+else
+ cfitsio_have_nsl=0
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing connect" >&5
+$as_echo_n "checking for library containing connect... " >&6; }
+if ${ac_cv_search_connect+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' socket; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib -lnsl $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_connect=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_connect+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_connect+:} false; then :
+
+else
+ ac_cv_search_connect=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_connect" >&5
+$as_echo "$ac_cv_search_connect" >&6; }
+ac_res=$ac_cv_search_connect
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+ cfitsio_have_socket=1
+else
+ cfitsio_have_socket=0
+fi
+
+
+if test "$cfitsio_have_nsl" = 1 -a "$cfitsio_have_socket" = 1; then
+ $as_echo "#define HAVE_NET_SERVICES 1" >>confdefs.h
+
+fi
+
+# ==================== END OF unix networking SECTION ================
+
+# ------------------------------------------------------------------------------
+# Define _REENTRANT & add -lpthread to LIBS if reentrant multithreading enabled:
+# ------------------------------------------------------------------------------
+if test "x$BUILD_REENTRANT" = xyes; then
+ $as_echo "#define _REENTRANT 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lpthread" >&5
+$as_echo_n "checking for main in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_main+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_pthread_main=yes
+else
+ ac_cv_lib_pthread_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_main" >&5
+$as_echo "$ac_cv_lib_pthread_main" >&6; }
+if test "x$ac_cv_lib_pthread_main" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+ LIBS="-lpthread $LIBS"
+
+else
+ as_fn_error $? "Unable to locate pthread library needed when enabling reentrant multithreading" "$LINENO" 5
+fi
+
+fi
+# ------------------------------------------------------------------------------
+
+ac_config_files="$ac_config_files Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# 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.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.68,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+ac_config_files="$ac_config_files cfitsio.pc"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# 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.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.68,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "cfitsio.pc") CONFIG_FILES="$CONFIG_FILES cfitsio.pc" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5
+$as_echo "" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Congratulations, Makefile update was successful." >&5
+$as_echo " Congratulations, Makefile update was successful." >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: You may want to run \"make\" now." >&5
+$as_echo " You may want to run \"make\" now." >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5
+$as_echo "" >&6; }
+
diff --git a/vendor/cfitsio/configure.in b/vendor/cfitsio/configure.in
new file mode 100644
index 00000000..39547406
--- /dev/null
+++ b/vendor/cfitsio/configure.in
@@ -0,0 +1,507 @@
+#
+# 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
+AC_CONFIG_SRCDIR([fitscore.c])
+
+#--------------------------------------------------------------------
+# Command options
+#--------------------------------------------------------------------
+
+AC_ARG_ENABLE(
+ reentrant,
+ [AS_HELP_STRING([--enable-reentrant],[Enable reentrant multithreading])],
+ [ if test $enableval = yes; then BUILD_REENTRANT=yes; fi ]
+)
+
+SSE_FLAGS=""
+AC_ARG_ENABLE(
+ sse2,
+ [AS_HELP_STRING([--enable-sse2],[Enable use of instructions in the SSE2 extended instruction set])],
+ [ if test $enableval = yes; then SSE_FLAGS="-msse2"; fi ]
+)
+
+AC_ARG_ENABLE(
+ ssse3,
+ [AS_HELP_STRING([--enable-ssse3],[Enable use of instructions in the SSSE3 extended instruction set])],
+ [ if test $enableval = yes; then SSE_FLAGS="$SSE_FLAGS -mssse3"; fi ]
+)
+
+# Define BUILD_HERA when building for HERA project to activate code in
+# drvrfile.c (by way of fitsio2.h):
+AC_ARG_ENABLE(
+ hera,
+ [AS_HELP_STRING([--enable-hera],[Build for HERA (ASD use only)])],
+ [ if test $enableval = yes; then BUILD_HERA=yes; fi ]
+)
+if test "x$BUILD_HERA" = xyes; then
+ AC_DEFINE(BUILD_HERA)
+fi
+
+AC_ARG_WITH(
+ gsiftp-flavour,
+ [AS_HELP_STRING([--with-gsiftp-flavour[[=PATH]]],[Enable Globus Toolkit gsiftp protocol support])],
+ [ if test "x$withval" != "xno"; then
+
+ if test "x$withval" != "xyes" ; then
+ GSIFTP_FLAVOUR=${withval}
+ fi
+ AC_DEFINE(GSIFTP_FLAVOUR,1,[Define Globus Toolkit architecture])
+ fi
+ ]
+)
+
+AC_ARG_WITH(
+ gsiftp,
+ [AS_HELP_STRING([--with-gsiftp[[=PATH]]],[Enable Globus Toolkit gsiftp protocol support])],
+ [ if test "x$withval" != "xno"; then
+
+ if test "x$withval" != "xyes" ; then
+ CFLAGS="$CFLAGS -I${withval}/include/${GSIFTP_FLAVOUR}"
+ LDFLAGS="$LDFLAGS -L${withval}/lib -lglobus_ftp_client_${GSIFTP_FLAVOUR}"
+ HAVE_GSIFTP=yes
+ fi
+ AC_DEFINE(HAVE_GSIFTP,1,[Define if you want Globus Toolkit gsiftp protocol support])
+ fi
+ ]
+)
+
+#--------------------------------------------------------------------
+# Check for install location prefix
+#--------------------------------------------------------------------
+
+AC_PREFIX_DEFAULT(`pwd`)
+
+# make will complain about duplicate targets for the install directories
+# if prefix == exec_prefix
+AC_SUBST(INSTALL_ROOT,'${prefix}')
+test "$exec_prefix" != NONE -a "$prefix" != "$exec_prefix" \
+ && INSTALL_ROOT="$INSTALL_ROOT "'${exec_prefix}'
+
+
+#--------------------------------------------------------------------
+# Check "uname" to determine system type
+#--------------------------------------------------------------------
+AC_CHECK_PROG([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.
+
+# Try first to find a proprietary C compiler, then gcc
+if test "x$CC" = x; then
+ AC_CHECK_PROGS(CC, cc)
+fi
+AC_PROG_CC
+
+if test "x$FC" = "xnone" ; then
+ AC_MSG_NOTICE(cfitsio: == Fortran compiler search has been overridden)
+ AC_MSG_NOTICE(cfitsio: == Cfitsio will be built without Fortran wrapper support)
+ FC=
+ F77_WRAPPERS=
+else
+ AC_CHECK_PROGS(FC, gfortran g95 g77 f77 ifort f95 f90 xlf cf77 gf77 af77 ncf f2c, notfound)
+ if test $FC = 'notfound' ; then
+ AC_MSG_WARN(cfitsio: == No acceptable Fortran compiler found in \$PATH)
+ AC_MSG_NOTICE(cfitsio: == Adding wrapper support for GNU Fortran by default)
+ CFORTRANFLAGS="-Dg77Fortran"
+ F77_WRAPPERS="\${FITSIO_SRC}"
+ 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
+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_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[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
+
+dnl Check if C compiler supports sse extended instruction flags.
+if test "x$SSE_FLAGS" != x; then
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $SSE_FLAGS"
+ AC_MSG_CHECKING([whether $CC accepts $SSE_FLAGS])
+ AC_LANG_PUSH([C])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],[c_has_option=yes],[c_has_option=no])
+ AC_MSG_RESULT($c_has_option)
+ AC_LANG_POP([])
+ if test "$c_has_option" = no; then SSE_FLAGS=""; fi
+ CFLAGS="$SAVE_CFLAGS"
+fi
+AC_SUBST(SSE_FLAGS)
+
+CFLAGS="$CFLAGS"
+LIBPRE=""
+
+case $system in
+ Darwin-*)
+ # Build for i386 & x86_64 architectures on Darwin 10.x or newer:
+ changequote(,)
+ case $system in
+ Darwin-[56789]*)
+ ;;
+ *)
+ changequote([,])
+ # Test to see whether the C compiler accepts the "-arch"
+ # flags for building "universal" binaries (Apple XCode only):
+ SAVE_CFLAGS="$CFLAGS"
+ C_UNIV_SWITCH="-arch i386 -arch x86_64"
+ CFLAGS="$CFLAGS $C_UNIV_SWITCH"
+ AC_MSG_CHECKING([whether $CC accepts $C_UNIV_SWITCH])
+ AC_LANG_PUSH([C])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],[c_has_option=yes],[c_has_option=no])
+ AC_MSG_RESULT($c_has_option)
+ AC_LANG_POP([])
+ # Value of C_UNIV_SWITCH will be needed later for SHLIB_LD:
+ if test "$c_has_option" = no; then C_UNIV_SWITCH=""; fi
+ CFLAGS="$SAVE_CFLAGS $C_UNIV_SWITCH"
+ ;;
+ esac
+ # Darwin can be powerpc, i386, or x86_64
+ ARCH=`uname -p`
+ EXT="darwin"
+ # For large file support (but may break Absoft compilers):
+ AC_DEFINE(_LARGEFILE_SOURCE)
+ AC_DEFINE(_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
+ # We need libm on Solaris:
+ AC_CHECK_LIB(m, frexp)
+ # For large file support:
+ AC_DEFINE(_LARGEFILE_SOURCE)
+ AC_DEFINE(_FILE_OFFSET_BITS,64)
+ ;;
+ 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"
+ # For large file support:
+ AC_DEFINE(_LARGEFILE_SOURCE)
+ AC_DEFINE(_FILE_OFFSET_BITS,64)
+ ;;
+ 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 $GCC in
+ yes)
+ GCCVERSION="`$CC -dumpversion 2>&1`"
+ echo "cfitsio: == Using gcc version $GCCVERSION"
+ AC_SUBST(GCCVERSION)
+ changequote(,)
+ gcc_test=`echo $GCCVERSION | grep -c '2\.[45678]'`
+ changequote([,])
+ if test $gcc_test -gt 0
+ then
+ changequote(,)
+ CFLAGS=`echo $CFLAGS | sed 's:-O[^ ]* *::'`
+ changequote([,])
+ AC_MSG_WARN(This gcc is pretty old. Disabling optimization to be safe.)
+ fi
+ ;;
+ no)
+ echo "cfitsio: Old CFLAGS is $CFLAGS"
+ CFLAGS=`echo $CFLAGS | sed -e "s/-g/-O/"`
+ case $system in
+ SunOS-5*)
+ changequote(,)
+ if test `echo $CFLAGS | grep -c fast` -gt 0
+ then
+ echo "cfitsio: Replacing -fast with -O3"
+ CFLAGS=`echo $CFLAGS | sed 's:-fast:-O3:'`
+ fi
+ changequote([,])
+ 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
+ cygwin)
+ SHLIB_LD="$CC -shared"
+ SHLIB_SUFFIX=".dll"
+ ;;
+ darwin)
+ changequote(,)
+ case $system in
+ Darwin-[56789]*)
+ SHLIB_LD="$CC -dynamiclib"
+ ;;
+ *)
+ # Build for i386 & x86_64 architectures on Darwin 10.x or newer:
+ SHLIB_LD="$CC -dynamiclib $C_UNIV_SWITCH"
+ ;;
+ esac
+ changequote([,])
+ SHLIB_SUFFIX=".dylib"
+ lhea_shlib_cflags="-fPIC -fno-common"
+ ;;
+ hpu)
+ SHLIB_LD="ld -b"
+ SHLIB_SUFFIX=".sl"
+ ;;
+ lnx)
+ 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 && test "x$EXT" != xcygwin; 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_LINK_IFELSE([AC_LANG_PROGRAM([[#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_COMPILE_IFELSE([AC_LANG_PROGRAM([[#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_LINK_IFELSE([AC_LANG_PROGRAM([[#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 in sys/fcntl.h")
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/fcntl.h>
+]], [[
+flock_t filler;
+]])],[
+AC_DEFINE(HAVE_FLOCK_T)
+AC_MSG_RESULT("yes")
+],[AC_MSG_RESULT("no") ])
+
+if test "$HAVE_FLOCK_T" != 1; then
+ AC_MSG_CHECKING("do we have flock_t defined in sys/flock.h")
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/flock.h>
+ ]], [[
+ flock_t filler;
+ ]])],[
+ AC_DEFINE(HAVE_FLOCK_T)
+ AC_MSG_RESULT("yes")
+ ],[AC_MSG_RESULT("no") ])
+fi
+
+# -------------------------------------------------------------------------
+# 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[#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 ================
+
+AC_SEARCH_LIBS([gethostbyname], [nsl], cfitsio_have_nsl=1, cfitsio_have_nsl=0)
+AC_SEARCH_LIBS([connect], [socket], cfitsio_have_socket=1,
+ cfitsio_have_socket=0, [-lnsl])
+
+if test "$cfitsio_have_nsl" = 1 -a "$cfitsio_have_socket" = 1; then
+ AC_DEFINE(HAVE_NET_SERVICES)
+fi
+
+# ==================== END OF unix networking SECTION ================
+
+# ------------------------------------------------------------------------------
+# Define _REENTRANT & add -lpthread to LIBS if reentrant multithreading enabled:
+# ------------------------------------------------------------------------------
+if test "x$BUILD_REENTRANT" = xyes; then
+ AC_DEFINE(_REENTRANT)
+ AC_CHECK_LIB([pthread],[main],[],[AC_MSG_ERROR(Unable to locate pthread library needed when enabling reentrant multithreading)])
+fi
+# ------------------------------------------------------------------------------
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+AC_CONFIG_FILES([cfitsio.pc])
+AC_OUTPUT
+
+
+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/vendor/cfitsio/cookbook.c b/vendor/cfitsio/cookbook.c
new file mode 100644
index 00000000..3b42ac61
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/cookbook.f b/vendor/cfitsio/cookbook.f
new file mode 100644
index 00000000..8becfdd2
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/crc32.c b/vendor/cfitsio/crc32.c
new file mode 100644
index 00000000..08843ff7
--- /dev/null
+++ b/vendor/cfitsio/crc32.c
@@ -0,0 +1,440 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2);
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case (also disallow negative lengths) */
+ if (len2 <= 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
diff --git a/vendor/cfitsio/crc32.h b/vendor/cfitsio/crc32.h
new file mode 100644
index 00000000..8053b611
--- /dev/null
+++ b/vendor/cfitsio/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/vendor/cfitsio/deflate.c b/vendor/cfitsio/deflate.c
new file mode 100644
index 00000000..1c6a00c1
--- /dev/null
+++ b/vendor/cfitsio/deflate.c
@@ -0,0 +1,1832 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle OF((deflate_state *s, int flush));
+local block_state deflate_huff OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->high_water = 0; /* nothing written to s->window yet */
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > s->w_size) {
+ length = s->w_size;
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if ((strategy != s->strategy || func != configuration_table[level].func) &&
+ strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_BLOCK);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel. But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong complen, wraplen;
+ Bytef *str;
+
+ /* conservative upper bound for compressed data */
+ complen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+ /* if can't get parameters, return conservative bound plus zlib wrapper */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return complen + 6;
+
+ /* compute wrapper length */
+ s = strm->state;
+ switch (s->wrap) {
+ case 0: /* raw deflate */
+ wraplen = 0;
+ break;
+ case 1: /* zlib wrapper */
+ wraplen = 6 + (s->strstart ? 4 : 0);
+ break;
+ case 2: /* gzip wrapper */
+ wraplen = 18;
+ if (s->gzhead != Z_NULL) { /* user-supplied gzip header */
+ if (s->gzhead->extra != Z_NULL)
+ wraplen += 2 + s->gzhead->extra_len;
+ str = s->gzhead->name;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ str = s->gzhead->comment;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ if (s->gzhead->hcrc)
+ wraplen += 2;
+ }
+ break;
+ default: /* for compiler happiness */
+ wraplen = 6;
+ }
+
+ /* if not default parameters, return conservative bound */
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return complen + wraplen;
+
+ /* default settings: return tight bound for that case */
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_BLOCK || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == Z_NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != Z_NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+ (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+ (*(configuration_table[s->level].func))(s, flush));
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ if (s->lookahead == 0) {
+ s->strstart = 0;
+ s->block_start = 0L;
+ }
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy(dest, source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+ /* If the WIN_INIT bytes after the end of the current data have never been
+ * written, then zero those bytes in order to avoid memory check reports of
+ * the use of uninitialized (or uninitialised as Julian writes) bytes by
+ * the longest match routines. Update the high water mark for the next
+ * time through here. WIN_INIT is set to MAX_MATCH since the longest match
+ * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+ */
+ if (s->high_water < s->window_size) {
+ ulg curr = s->strstart + (ulg)(s->lookahead);
+ ulg init;
+
+ if (s->high_water < curr) {
+ /* Previous high water mark below current data -- zero WIN_INIT
+ * bytes or up to end of window, whichever is less.
+ */
+ init = s->window_size - curr;
+ if (init > WIN_INIT)
+ init = WIN_INIT;
+ zmemzero(s->window + curr, (unsigned)init);
+ s->high_water = curr + init;
+ }
+ else if (s->high_water < (ulg)curr + WIN_INIT) {
+ /* High water mark at or above current data, but below current data
+ * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+ * to end of window, whichever is less.
+ */
+ init = (ulg)curr + WIN_INIT - s->high_water;
+ if (init > s->window_size - s->high_water)
+ init = s->window_size - s->high_water;
+ zmemzero(s->window + s->high_water, (unsigned)init);
+ s->high_water += init;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (last)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+ FLUSH_BLOCK_ONLY(s, last); \
+ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan, *strend; /* scan goes up to strend for length of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest encodable run.
+ */
+ if (s->lookahead < MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ s->match_length = 0;
+ if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+ scan = s->window + s->strstart - 1;
+ prev = *scan;
+ if (prev == *++scan && prev == *++scan && prev == *++scan) {
+ strend = s->window + s->strstart + MAX_MATCH;
+ do {
+ } while (prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ scan < strend);
+ s->match_length = MAX_MATCH - (int)(strend - scan);
+ if (s->match_length > s->lookahead)
+ s->match_length = s->lookahead;
+ }
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+ _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we have a literal to write. */
+ if (s->lookahead == 0) {
+ fill_window(s);
+ if (s->lookahead == 0) {
+ if (flush == Z_NO_FLUSH)
+ return need_more;
+ break; /* flush the current block */
+ }
+ }
+
+ /* Output a literal byte */
+ s->match_length = 0;
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
diff --git a/vendor/cfitsio/deflate.h b/vendor/cfitsio/deflate.h
new file mode 100644
index 00000000..6ac0a1eb
--- /dev/null
+++ b/vendor/cfitsio/deflate.h
@@ -0,0 +1,340 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2010 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+ ulg high_water;
+ /* High water mark offset in window for initialized bytes -- bytes above
+ * this are set to zero in order to avoid memory check warnings when
+ * longest match routines access bytes past the input. This is then
+ * updated to the new high water mark.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+ memory checker errors from longest match routines */
+
+ /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch ZLIB_INTERNAL _length_code[];
+ extern uch ZLIB_INTERNAL _dist_code[];
+#else
+ extern const uch ZLIB_INTERNAL _length_code[];
+ extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/vendor/cfitsio/drvrfile.c b/vendor/cfitsio/drvrfile.c
new file mode 100644
index 00000000..0303503d
--- /dev/null
+++ b/vendor/cfitsio/drvrfile.c
@@ -0,0 +1,966 @@
+/* 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
+#if defined(unix) || defined(__unix__) || defined(__unix)
+#include <unistd.h> /* needed for getcwd prototype on unix machines */
+#endif
+#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;
+ LONGLONG 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) {
+ file_outfile[0] = '\0';
+ 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);
+ file_outfile[0] = '\0';
+ 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) {
+ file_outfile[0] = '\0';
+ 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);
+ file_outfile[0] = '\0';
+ }
+ 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[1024], *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)
+ {
+ if (strlen(cptr) + strlen(filename+1) > 1023)
+ return(FILE_NOT_OPENED);
+
+ strcpy(tempname, cptr);
+ strcat(tempname, filename+1);
+ }
+ else
+ {
+ if (strlen(filename) > 1023)
+ return(FILE_NOT_OPENED);
+
+ 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 */
+ if (strlen(pwd->pw_dir) + strlen(cptr) > 1023)
+ return(FILE_NOT_OPENED);
+
+ 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 */
+ {
+
+ if (strlen(filename) + 7 > 1023)
+ return(FILE_NOT_OPENED);
+
+ 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];
+
+#if defined(BUILD_HERA)
+
+ /* special code to verify that the path to the file to be created */
+ /* is within the users data directory on Hera */
+
+ int status = 0, rootlen, slen;
+ char *cpos;
+ char cwd[FLEN_FILENAME], absURL[FLEN_FILENAME];
+ /* note that "/heradata/users/" is actually "/.hera_mountpnt/hera_users/" */
+ char rootstring[]="/.hera_mountpnt/hera_users/";
+ char username[FLEN_FILENAME], userroot[FLEN_FILENAME];
+
+ /* Get the current working directory */
+ fits_get_cwd(cwd, &status);
+ slen = strlen(cwd);
+ if (cwd[slen-1] != '/') strcat(cwd,"/"); /* make sure the CWD ends with slash */
+
+/* printf("CWD = %s\n", cwd); */
+
+ /* check that CWD string matches the rootstring */
+ rootlen = strlen(rootstring);
+ if (strncmp(rootstring, cwd, rootlen)) {
+ ffpmsg("invalid CWD: does not match Hera data directory");
+/* ffpmsg(rootstring); */
+ return(FILE_NOT_CREATED);
+ } else {
+
+ /* get the user name from CWD (it follows the root string) */
+ strcpy(username, cwd+rootlen);
+ cpos=strchr(username, '/');
+ if (!cpos) {
+ ffpmsg("invalid CWD: not equal to Hera data directory + username");
+/* ffpmsg(cwd); */
+ return(FILE_NOT_CREATED);
+ } else {
+ *(cpos+1) = '\0'; /* truncate user name string */
+
+ /* construct full user root name */
+ strcpy(userroot, rootstring);
+ strcat(userroot, username);
+ rootlen = strlen(userroot);
+
+ /* convert the input filename to absolute path relative to the CWD */
+ fits_relurl2url(cwd, filename, absURL, &status);
+/*
+ printf("username = %s\n", username);
+ printf("userroot = %s\n", userroot);
+ printf("filename = %s\n", filename);
+ printf("ABS = %s\n", absURL);
+*/
+ /* check that CWD string matches the rootstring */
+
+ if (strncmp(userroot, absURL, rootlen)) {
+ ffpmsg("invalid filename: path not within user directory");
+/*
+ ffpmsg(absURL);
+ ffpmsg(userroot);
+*/
+ return(FILE_NOT_CREATED);
+ }
+ }
+ }
+ /* if we got here, then the input filename appears to be valid */
+
+#endif
+
+ *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, LONGLONG filesize)
+/*
+ truncate the diskfile to a new smaller size
+*/
+{
+
+#ifdef HAVE_FTRUNCATE
+ int fdesc;
+
+ fdesc = fileno(handleTable[handle].fileptr);
+ ftruncate(fdesc, (OFF_T) filesize);
+ file_seek(handle, filesize);
+
+ handleTable[handle].currentpos = filesize;
+ handleTable[handle].last_io_op = IO_SEEK;
+
+#endif
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int file_size(int handle, LONGLONG *filesize)
+/*
+ return the size of the file in bytes
+*/
+{
+ OFF_T position1,position2;
+ FILE *diskfile;
+
+ diskfile = handleTable[handle].fileptr;
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+
+/* call the VISUAL C++ version of the routines which support */
+/* Large Files (> 2GB) if they are supported (since VC 8.0) */
+
+ position1 = _ftelli64(diskfile); /* save current postion */
+ if (position1 < 0)
+ return(SEEK_ERROR);
+
+ if (_fseeki64(diskfile, 0, 2) != 0) /* seek to end of file */
+ return(SEEK_ERROR);
+
+ position2 = _ftelli64(diskfile); /* get file size */
+ if (position2 < 0)
+ return(SEEK_ERROR);
+
+ if (_fseeki64(diskfile, position1, 0) != 0) /* seek back to original pos */
+ return(SEEK_ERROR);
+
+#elif _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);
+
+ position2 = ftello(diskfile); /* get file size */
+ if (position2 < 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);
+
+ position2 = ftell(diskfile); /* get file size */
+ if (position2 < 0)
+ return(SEEK_ERROR);
+
+ if (fseek(diskfile, position1, 0) != 0) /* seek back to original pos */
+ return(SEEK_ERROR);
+
+#endif
+
+ *filesize = (LONGLONG) position2;
+
+ 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, LONGLONG offset)
+/*
+ seek to position relative to start of the file
+*/
+{
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+
+ /* Microsoft visual studio C++ */
+ /* _fseeki64 supported beginning with version 8.0 */
+
+ if (_fseeki64(handleTable[handle].fileptr, (OFF_T) offset, 0) != 0)
+ return(SEEK_ERROR);
+
+#elif _FILE_OFFSET_BITS - 0 == 64
+
+ if (fseeko(handleTable[handle].fileptr, (OFF_T) offset, 0) != 0)
+ return(SEEK_ERROR);
+
+#else
+
+ if (fseek(handleTable[handle].fileptr, (OFF_T) 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;
+ 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 */
+ 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 */
+ file_outfile[0] = '\0';
+ 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);
+ file_outfile[0] = '\0';
+ 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);
+ file_outfile[0] = '\0';
+ 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))
+ {
+ if (strlen(filename) > FLEN_FILENAME - 1)
+ return(0);
+
+ 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)) {
+ file_outfile[0] = '\0';
+ strncat(file_outfile,outfile,FLEN_FILENAME-1);
+ }
+ }
+
+ return 0;
+}
+/**********************************************************************/
+/**********************************************************************/
+/**********************************************************************/
+
+/**** driver routines for stream//: device (stdin or stdout) ********/
+
+
+/*--------------------------------------------------------------------------*/
+int stream_open(char *filename, int rwmode, int *handle)
+{
+ /*
+ read from stdin
+ */
+ if (filename)
+ rwmode = 1; /* dummy statement to suppress unused parameter compiler warning */
+
+ *handle = 1; /* 1 = stdin */
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stream_create(char *filename, int *handle)
+{
+ /*
+ write to stdout
+ */
+
+ if (filename) /* dummy statement to suppress unused parameter compiler warning */
+ *handle = 2;
+ else
+ *handle = 2; /* 2 = stdout */
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stream_size(int handle, LONGLONG *filesize)
+/*
+ return the size of the file in bytes
+*/
+{
+ handle = 0; /* suppress unused parameter compiler warning */
+
+ /* this operation is not supported in a stream; return large value */
+ *filesize = LONG_MAX;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stream_close(int handle)
+/*
+ don't have to close stdin or stdout
+*/
+{
+ handle = 0; /* suppress unused parameter compiler warning */
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stream_flush(int handle)
+/*
+ flush the file
+*/
+{
+ if (handle == 2)
+ fflush(stdout);
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stream_seek(int handle, LONGLONG offset)
+ /*
+ seeking is not allowed in a stream
+ */
+{
+ offset = handle; /* suppress unused parameter compiler warning */
+ return(1);
+}
+/*--------------------------------------------------------------------------*/
+int stream_read(int hdl, void *buffer, long nbytes)
+/*
+ reading from stdin stream
+*/
+
+{
+ long nread;
+
+ if (hdl != 1)
+ return(1); /* can only read from stdin */
+
+ nread = (long) fread(buffer, 1, nbytes, stdin);
+
+ if (nread != nbytes)
+ {
+/* return(READ_ERROR); */
+ return(END_OF_FILE);
+ }
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int stream_write(int hdl, void *buffer, long nbytes)
+/*
+ write bytes at the current position in the file
+*/
+{
+ if (hdl != 2)
+ return(1); /* can only write to stdout */
+
+ if((long) fwrite(buffer, 1, nbytes, stdout) != nbytes)
+ return(WRITE_ERROR);
+
+ return(0);
+}
+
+
+
+
diff --git a/vendor/cfitsio/drvrgsiftp.c b/vendor/cfitsio/drvrgsiftp.c
new file mode 100644
index 00000000..ab9aaed4
--- /dev/null
+++ b/vendor/cfitsio/drvrgsiftp.c
@@ -0,0 +1,522 @@
+
+/* This file, drvrgsiftp.c contains driver routines for gsiftp files. */
+/* Andrea Barisani <lcars@si.inaf.it> */
+/* Taffoni Giuliano <taffoni@oats.inaf.it> */
+#ifdef HAVE_NET_SERVICES
+#ifdef HAVE_GSIFTP
+
+#include <sys/types.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include "fitsio2.h"
+
+#include <globus_ftp_client.h>
+
+#define MAXLEN 1200
+#define NETTIMEOUT 80
+#define MAX_BUFFER_SIZE_R 1024
+#define MAX_BUFFER_SIZE_W (64*1024)
+
+static int gsiftpopen = 0;
+static int global_offset = 0;
+static int gsiftp_get(char *filename, FILE **gsiftpfile, int num_streams);
+
+static globus_mutex_t lock;
+static globus_cond_t cond;
+static globus_bool_t done;
+
+static char *gsiftp_tmpfile;
+static char *gsiftpurl = NULL;
+static char gsiftp_tmpdir[MAXLEN];
+
+static jmp_buf env; /* holds the jump buffer for setjmp/longjmp pairs */
+static void signal_handler(int sig);
+
+int gsiftp_init(void)
+{
+
+ if (getenv("GSIFTP_TMPFILE")) {
+ gsiftp_tmpfile = getenv("GSIFTP_TMPFILE");
+ } else {
+ strncpy(gsiftp_tmpdir, "/tmp/gsiftp_XXXXXX", sizeof gsiftp_tmpdir);
+ if (mkdtemp(gsiftp_tmpdir) == NULL) {
+ ffpmsg("Cannot create temporary directory!");
+ return (FILE_NOT_OPENED);
+ }
+ gsiftp_tmpfile = malloc(strlen(gsiftp_tmpdir) + strlen("/gsiftp_buffer.tmp"));
+ strcat(gsiftp_tmpfile, gsiftp_tmpdir);
+ strcat(gsiftp_tmpfile, "/gsiftp_buffer.tmp");
+ }
+
+ return file_init();
+}
+
+int gsiftp_shutdown(void)
+{
+ free(gsiftpurl);
+ free(gsiftp_tmpfile);
+ free(gsiftp_tmpdir);
+
+ return file_shutdown();
+}
+
+int gsiftp_setoptions(int options)
+{
+ return file_setoptions(options);
+}
+
+int gsiftp_getoptions(int *options)
+{
+ return file_getoptions(options);
+}
+
+int gsiftp_getversion(int *version)
+{
+ return file_getversion(version);
+}
+
+int gsiftp_checkfile(char *urltype, char *infile, char *outfile)
+{
+ return file_checkfile(urltype, infile, outfile);
+}
+
+int gsiftp_open(char *filename, int rwmode, int *handle)
+{
+ FILE *gsiftpfile;
+ int num_streams;
+
+ if (getenv("GSIFTP_STREAMS")) {
+ num_streams = (int)getenv("GSIFTP_STREAMS");
+ } else {
+ num_streams = 1;
+ }
+
+ if (rwmode) {
+ gsiftpopen = 2;
+ } else {
+ gsiftpopen = 1;
+ }
+
+ if (gsiftpurl)
+ free(gsiftpurl);
+
+ gsiftpurl = strdup(filename);
+
+ if (setjmp(env) != 0) {
+ ffpmsg("Timeout (gsiftp_open)");
+ goto error;
+ }
+
+ signal(SIGALRM, signal_handler);
+ alarm(NETTIMEOUT);
+
+ if (gsiftp_get(filename,&gsiftpfile,num_streams)) {
+ alarm(0);
+ ffpmsg("Unable to open gsiftp file (gsiftp_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+
+ fclose(gsiftpfile);
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+
+ return file_open(gsiftp_tmpfile, rwmode, handle);
+
+ error:
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ return (FILE_NOT_OPENED);
+}
+
+int gsiftp_create(char *filename, int *handle)
+{
+ if (gsiftpurl)
+ free(gsiftpurl);
+
+ gsiftpurl = strdup(filename);
+
+ return file_create(gsiftp_tmpfile, handle);
+}
+
+int gsiftp_truncate(int handle, LONGLONG filesize)
+{
+ return file_truncate(handle, filesize);
+}
+
+int gsiftp_size(int handle, LONGLONG *filesize)
+{
+ return file_size(handle, filesize);
+}
+
+int gsiftp_flush(int handle)
+{
+ FILE *gsiftpfile;
+ int num_streams;
+
+ if (getenv("GSIFTP_STREAMS")) {
+ num_streams = (int)getenv("GSIFTP_STREAMS");
+ } else {
+ num_streams = 1;
+ }
+
+ int rc = file_flush(handle);
+
+ if (gsiftpopen != 1) {
+
+ if (setjmp(env) != 0) {
+ ffpmsg("Timeout (gsiftp_write)");
+ goto error;
+ }
+
+ signal(SIGALRM, signal_handler);
+ alarm(NETTIMEOUT);
+
+ if (gsiftp_put(gsiftpurl,&gsiftpfile,num_streams)) {
+ alarm(0);
+ ffpmsg("Unable to open gsiftp file (gsiftp_flush)");
+ ffpmsg(gsiftpurl);
+ goto error;
+ }
+
+ fclose(gsiftpfile);
+
+ signal(SIGALRM, SIG_DFL);
+ alarm(0);
+ }
+
+ return rc;
+
+ error:
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ return (FILE_NOT_OPENED);
+}
+
+int gsiftp_seek(int handle, LONGLONG offset)
+{
+ return file_seek(handle, offset);
+}
+
+int gsiftp_read(int hdl, void *buffer, long nbytes)
+{
+ return file_read(hdl, buffer, nbytes);
+}
+
+int gsiftp_write(int hdl, void *buffer, long nbytes)
+{
+ return file_write(hdl, buffer, nbytes);
+}
+
+int gsiftp_close(int handle)
+{
+ unlink(gsiftp_tmpfile);
+
+ if (gsiftp_tmpdir)
+ rmdir(gsiftp_tmpdir);
+
+ return file_close(handle);
+}
+
+static void done_cb( void * user_arg,
+ globus_ftp_client_handle_t * handle,
+ globus_object_t * err)
+{
+
+ if(err){
+ fprintf(stderr, "%s", globus_object_printable_to_string(err));
+ }
+
+ globus_mutex_lock(&lock);
+ done = GLOBUS_TRUE;
+ globus_cond_signal(&cond);
+ globus_mutex_unlock(&lock);
+ return;
+}
+
+static void data_cb_read( void * user_arg,
+ globus_ftp_client_handle_t * handle,
+ globus_object_t * err,
+ globus_byte_t * buffer,
+ globus_size_t length,
+ globus_off_t offset,
+ globus_bool_t eof)
+{
+ if(err) {
+ fprintf(stderr, "%s", globus_object_printable_to_string(err));
+ }
+ else {
+ FILE* fd = (FILE*) user_arg;
+ int rc = fwrite(buffer, 1, length, fd);
+ if (ferror(fd)) {
+ printf("Read error in function data_cb_read; errno = %d\n", errno);
+ return;
+ }
+
+ if (!eof) {
+ globus_ftp_client_register_read(handle,
+ buffer,
+ MAX_BUFFER_SIZE_R,
+ data_cb_read,
+ (void*) fd);
+ }
+ }
+ return;
+}
+
+static void data_cb_write( void * user_arg,
+ globus_ftp_client_handle_t * handle,
+ globus_object_t * err,
+ globus_byte_t * buffer,
+ globus_size_t length,
+ globus_off_t offset,
+ globus_bool_t eof)
+{
+ int curr_offset;
+ if(err) {
+ fprintf(stderr, "%s", globus_object_printable_to_string(err));
+ }
+ else {
+ if (!eof) {
+ FILE* fd = (FILE*) user_arg;
+ int rc;
+ globus_mutex_lock(&lock);
+ curr_offset = global_offset;
+ rc = fread(buffer, 1, MAX_BUFFER_SIZE_W, fd);
+ global_offset += rc;
+ globus_mutex_unlock(&lock);
+ if (ferror(fd)) {
+ printf("Read error in function data_cb_write; errno = %d\n", errno);
+ return;
+ }
+
+ globus_ftp_client_register_write(handle,
+ buffer,
+ rc,
+ curr_offset,
+ feof(fd) != 0,
+ data_cb_write,
+ (void*) fd);
+ } else {
+ globus_libc_free(buffer);
+ }
+ }
+ return;
+}
+
+int gsiftp_get(char *filename, FILE **gsiftpfile, int num_streams)
+{
+ char gsiurl[MAXLEN];
+
+ globus_ftp_client_handle_t handle;
+ globus_ftp_client_operationattr_t attr;
+ globus_ftp_client_handleattr_t handle_attr;
+ globus_ftp_control_parallelism_t parallelism;
+ globus_ftp_control_layout_t layout;
+ globus_byte_t buffer[MAX_BUFFER_SIZE_R];
+ globus_size_t buffer_length = sizeof(buffer);
+ globus_result_t result;
+ globus_ftp_client_restart_marker_t restart;
+ globus_ftp_control_type_t filetype;
+
+ globus_module_activate(GLOBUS_FTP_CLIENT_MODULE);
+ globus_mutex_init(&lock, GLOBUS_NULL);
+ globus_cond_init(&cond, GLOBUS_NULL);
+ globus_ftp_client_handle_init(&handle, GLOBUS_NULL);
+ globus_ftp_client_handleattr_init(&handle_attr);
+ globus_ftp_client_operationattr_init(&attr);
+ layout.mode = GLOBUS_FTP_CONTROL_STRIPING_NONE;
+ globus_ftp_client_restart_marker_init(&restart);
+ globus_ftp_client_operationattr_set_mode(
+ &attr,
+ GLOBUS_FTP_CONTROL_MODE_EXTENDED_BLOCK);
+
+ if (num_streams >= 1)
+ {
+ parallelism.mode = GLOBUS_FTP_CONTROL_PARALLELISM_FIXED;
+ parallelism.fixed.size = num_streams;
+
+ globus_ftp_client_operationattr_set_parallelism(
+ &attr,
+ &parallelism);
+ }
+
+ globus_ftp_client_operationattr_set_layout(&attr,
+ &layout);
+
+ filetype = GLOBUS_FTP_CONTROL_TYPE_IMAGE;
+ globus_ftp_client_operationattr_set_type (&attr,
+ filetype);
+
+ globus_ftp_client_handle_init(&handle, &handle_attr);
+
+ done = GLOBUS_FALSE;
+
+ strcpy(gsiurl,"gsiftp://");
+ strcat(gsiurl,filename);
+
+ *gsiftpfile = fopen(gsiftp_tmpfile,"w+");
+
+ if (!*gsiftpfile) {
+ ffpmsg("Unable to open temporary file!");
+ return (FILE_NOT_OPENED);
+ }
+
+ result = globus_ftp_client_get(&handle,
+ gsiurl,
+ &attr,
+ &restart,
+ done_cb,
+ 0);
+ if(result != GLOBUS_SUCCESS) {
+ globus_object_t * err;
+ err = globus_error_get(result);
+ fprintf(stderr, "%s", globus_object_printable_to_string(err));
+ done = GLOBUS_TRUE;
+ }
+ else {
+ globus_ftp_client_register_read(&handle,
+ buffer,
+ buffer_length,
+ data_cb_read,
+ (void*) *gsiftpfile);
+ }
+
+ globus_mutex_lock(&lock);
+
+ while(!done) {
+ globus_cond_wait(&cond, &lock);
+ }
+
+ globus_mutex_unlock(&lock);
+ globus_ftp_client_handle_destroy(&handle);
+ globus_module_deactivate_all();
+
+ return 0;
+}
+
+int gsiftp_put(char *filename, FILE **gsiftpfile, int num_streams)
+{
+ int i;
+ char gsiurl[MAXLEN];
+
+ globus_ftp_client_handle_t handle;
+ globus_ftp_client_operationattr_t attr;
+ globus_ftp_client_handleattr_t handle_attr;
+ globus_ftp_control_parallelism_t parallelism;
+ globus_ftp_control_layout_t layout;
+ globus_byte_t * buffer;
+ globus_size_t buffer_length = sizeof(buffer);
+ globus_result_t result;
+ globus_ftp_client_restart_marker_t restart;
+ globus_ftp_control_type_t filetype;
+
+ globus_module_activate(GLOBUS_FTP_CLIENT_MODULE);
+ globus_mutex_init(&lock, GLOBUS_NULL);
+ globus_cond_init(&cond, GLOBUS_NULL);
+ globus_ftp_client_handle_init(&handle, GLOBUS_NULL);
+ globus_ftp_client_handleattr_init(&handle_attr);
+ globus_ftp_client_operationattr_init(&attr);
+ layout.mode = GLOBUS_FTP_CONTROL_STRIPING_NONE;
+ globus_ftp_client_restart_marker_init(&restart);
+ globus_ftp_client_operationattr_set_mode(
+ &attr,
+ GLOBUS_FTP_CONTROL_MODE_EXTENDED_BLOCK);
+
+ if (num_streams >= 1)
+ {
+ parallelism.mode = GLOBUS_FTP_CONTROL_PARALLELISM_FIXED;
+ parallelism.fixed.size = num_streams;
+
+ globus_ftp_client_operationattr_set_parallelism(
+ &attr,
+ &parallelism);
+ }
+
+ globus_ftp_client_operationattr_set_layout(&attr,
+ &layout);
+
+ filetype = GLOBUS_FTP_CONTROL_TYPE_IMAGE;
+ globus_ftp_client_operationattr_set_type (&attr,
+ filetype);
+
+ globus_ftp_client_handle_init(&handle, &handle_attr);
+
+ done = GLOBUS_FALSE;
+
+ strcpy(gsiurl,"gsiftp://");
+ strcat(gsiurl,filename);
+
+ *gsiftpfile = fopen(gsiftp_tmpfile,"r");
+
+ if (!*gsiftpfile) {
+ ffpmsg("Unable to open temporary file!");
+ return (FILE_NOT_OPENED);
+ }
+
+ result = globus_ftp_client_put(&handle,
+ gsiurl,
+ &attr,
+ &restart,
+ done_cb,
+ 0);
+ if(result != GLOBUS_SUCCESS) {
+ globus_object_t * err;
+ err = globus_error_get(result);
+ fprintf(stderr, "%s", globus_object_printable_to_string(err));
+ done = GLOBUS_TRUE;
+ }
+ else {
+ int rc;
+ int curr_offset;
+
+ for (i = 0; i< 2 * num_streams && feof(*gsiftpfile) == 0; i++)
+ {
+ buffer = malloc(MAX_BUFFER_SIZE_W);
+ globus_mutex_lock(&lock);
+ curr_offset = global_offset;
+ rc = fread(buffer, 1, MAX_BUFFER_SIZE_W, *gsiftpfile);
+ global_offset += rc;
+ globus_mutex_unlock(&lock);
+ globus_ftp_client_register_write(
+ &handle,
+ buffer,
+ rc,
+ curr_offset,
+ feof(*gsiftpfile) != 0,
+ data_cb_write,
+ (void*) *gsiftpfile);
+ }
+ }
+
+ globus_mutex_lock(&lock);
+
+ while(!done) {
+ globus_cond_wait(&cond, &lock);
+ }
+
+ globus_mutex_unlock(&lock);
+ globus_ftp_client_handle_destroy(&handle);
+ globus_module_deactivate_all();
+
+ return 0;
+}
+
+static void signal_handler(int sig) {
+
+ switch (sig) {
+ case SIGALRM: /* process for alarm */
+ longjmp(env,sig);
+
+ default: {
+ /* Hmm, shouldn't have happend */
+ exit(sig);
+ }
+ }
+}
+
+#endif
+#endif
diff --git a/vendor/cfitsio/drvrgsiftp.h b/vendor/cfitsio/drvrgsiftp.h
new file mode 100644
index 00000000..bd0ec0d4
--- /dev/null
+++ b/vendor/cfitsio/drvrgsiftp.h
@@ -0,0 +1,21 @@
+#ifndef _GSIFTP_H
+#define _GSIFTP_H
+
+int gsiftp_init(void);
+int gsiftp_setoptions(int options);
+int gsiftp_getoptions(int *options);
+int gsiftp_getversion(int *version);
+int gsiftp_shutdown(void);
+int gsiftp_checkfile(char *urltype, char *infile, char *outfile);
+int gsiftp_open(char *filename, int rwmode, int *driverhandle);
+int gsiftp_create(char *filename, int *driverhandle);
+int gsiftp_truncate(int driverhandle, LONGLONG filesize);
+int gsiftp_size(int driverhandle, LONGLONG *filesize);
+int gsiftp_close(int driverhandle);
+int gsiftp_remove(char *filename);
+int gsiftp_flush(int driverhandle);
+int gsiftp_seek(int driverhandle, LONGLONG offset);
+int gsiftp_read (int driverhandle, void *buffer, long nbytes);
+int gsiftp_write(int driverhandle, void *buffer, long nbytes);
+
+#endif
diff --git a/vendor/cfitsio/drvrmem.c b/vendor/cfitsio/drvrmem.c
new file mode 100644
index 00000000..4ef23b70
--- /dev/null
+++ b/vendor/cfitsio/drvrmem.c
@@ -0,0 +1,1184 @@
+/* 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"
+
+/* prototype for .Z file uncompression function in zuncompress.c */
+int zuncompress2mem(char *filename,
+ FILE *diskfile,
+ char **buffptr,
+ size_t *buffsize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ size_t *filesize,
+ int *status);
+
+#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 */
+ LONGLONG currentpos; /* current file position, relative to start */
+ LONGLONG 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 = (char *) 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, LONGLONG filesize)
+/*
+ truncate the file to a new size
+*/
+{
+ char *ptr;
+
+ /* call the memory reallocation function, if defined */
+ if ( memTable[handle].mem_realloc )
+ { /* explicit LONGLONG->size_t cast */
+ ptr = (memTable[handle].mem_realloc)(
+ *(memTable[handle].memaddrptr),
+ (size_t) filesize);
+ if (!ptr)
+ {
+ ffpmsg("Failed to reallocate memory (mem_truncate)");
+ return(MEMORY_ALLOCATION);
+ }
+
+ /* if allocated more memory, initialize it to zero */
+ if ( filesize > *(memTable[handle].memsizeptr) )
+ {
+ memset(ptr + *(memTable[handle].memsizeptr),
+ 0,
+ ((size_t) filesize) - *(memTable[handle].memsizeptr) );
+ }
+
+ *(memTable[handle].memaddrptr) = ptr;
+ *(memTable[handle].memsizeptr) = (size_t) (filesize);
+ }
+
+ memTable[handle].currentpos = 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))
+ {
+ stdin_outfile[0] = '\0';
+ strncat(stdin_outfile,outfile,FLEN_FILENAME-1); /* 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;
+ 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;
+ LONGLONG 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;
+ char simple[] = "SIMPLE";
+ int c, ii, jj, status;
+ 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. explicit LONGLONG->size_t cast */
+ if(fwrite(memTable[handle].memaddr, 1,
+ ((size_t) 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),
+ ((size_t) 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) = (size_t) (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),
+ ((size_t) 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) = (size_t) (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;
+
+ if (strstr(filename, ".Z")) {
+ zuncompress2mem(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*/
+ } else {
+ 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, LONGLONG *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,
+ (size_t) (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, LONGLONG offset)
+/*
+ seek to position relative to start of the file.
+*/
+{
+ if (offset > 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/vendor/cfitsio/drvrnet.c b/vendor/cfitsio/drvrnet.c
new file mode 100644
index 00000000..f0e1a428
--- /dev/null
+++ b/vendor/cfitsio/drvrnet.c
@@ -0,0 +1,2741 @@
+/* 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.
+
+
+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>
+
+#if defined(unix) || defined(__unix__) || defined(__unix)
+#include <unistd.h>
+#endif
+
+#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;
+ LONGLONG currentpos;
+} rootdriver;
+
+static rootdriver handleTable[NMAXFILES]; /* 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 int encode64(unsigned s_len, char *src, unsigned d_len, char *dst);
+
+/***************************/
+/* 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 {
+
+ if (strlen(filename) >= MAXLEN - 4) {
+ ffpmsg("http file name is too long (http_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+
+ 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 tmpstr2[MAXLEN];
+ char errorstr[MAXLEN];
+ char proto[SHORTLEN];
+ char host[SHORTLEN];
+ char userpass[MAXLEN];
+ char fn[MAXLEN];
+ char turl[MAXLEN];
+ char *scratchstr;
+ int port;
+ float version;
+
+ char pproto[SHORTLEN];
+ char phost[SHORTLEN]; /* address of the proxy server */
+ int pport; /* port number of the proxy server */
+ char pfn[MAXLEN];
+ char *proxy; /* URL of the proxy server */
+
+ /* Parse the URL apart again */
+ strcpy(turl,"http://");
+ strncat(turl,url,MAXLEN - 8);
+ if (NET_ParseUrl(turl,proto,host,&port,fn)) {
+ sprintf(errorstr,"URL Parse Error (http_open) %s",url);
+ ffpmsg(errorstr);
+ return (FILE_NOT_OPENED);
+ }
+
+ /* Do we have a user:password combo ? */
+ strcpy(userpass, url);
+ if ((scratchstr = strchr(userpass, '@')) != NULL) {
+ *scratchstr = '\0';
+ } else
+ strcpy(userpass, "");
+
+ /* Ph. Prugniel 2003/04/03
+ Are we using a proxy?
+
+ We use a proxy if the environment variable "http_proxy" is set to an
+ address, eg. http://wwwcache.nottingham.ac.uk:3128
+ ("http_proxy" is also used by wget)
+ */
+ proxy = getenv("http_proxy");
+
+ /* Connect to the remote host */
+ if (proxy) {
+ if (NET_ParseUrl(proxy,pproto,phost,&pport,pfn)) {
+ sprintf(errorstr,"URL Parse Error (http_open) %s",proxy);
+ ffpmsg(errorstr);
+ return (FILE_NOT_OPENED);
+ }
+ sock = NET_TcpConnect(phost,pport);
+ }
+ else
+ sock = NET_TcpConnect(host,port);
+
+ if (sock < 0) {
+ if (proxy) {
+ ffpmsg("Couldn't connect to host via proxy server (http_open_network)");
+ ffpmsg(proxy);
+ }
+ 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 */
+ /* Ph. Prugniel 2003/04/03
+ One must add the Host: command because of HTTP 1.1 servers (ie. virtual
+ hosts) */
+
+ if (proxy)
+ sprintf(tmpstr,"GET http://%s:%-d%s HTTP/1.0\r\n",host,port,fn);
+ else
+ sprintf(tmpstr,"GET %s HTTP/1.0\r\n",fn);
+
+ if (strcmp(userpass, "")) {
+ encode64(strlen(userpass), userpass, MAXLEN, tmpstr2);
+ sprintf(tmpstr1, "Authorization: Basic %s\r\n", tmpstr2);
+
+ if (strlen(tmpstr) + strlen(tmpstr1) > MAXLEN - 1)
+ return (FILE_NOT_OPENED);
+
+ strcat(tmpstr,tmpstr1);
+ }
+
+ sprintf(tmpstr1,"User-Agent: HEASARC/CFITSIO/%-8.3f\r\n",ffvers(&version));
+
+ if (strlen(tmpstr) + strlen(tmpstr1) > MAXLEN - 1)
+ return (FILE_NOT_OPENED);
+
+ strcat(tmpstr,tmpstr1);
+
+ /* HTTP 1.1 servers require the following 'Host: ' string */
+ sprintf(tmpstr1,"Host: %s:%-d\r\n\r\n",host,port);
+
+ if (strlen(tmpstr) + strlen(tmpstr1) > MAXLEN - 1)
+ return (FILE_NOT_OPENED);
+
+ 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 */
+
+ if (strlen(filename) > MAXLEN - 4) {
+ ffpmsg("filename too long (ftp_open)");
+ ffpmsg(filename);
+ goto error;
+ }
+
+ 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 */
+ if (strlen(filename) > MAXLEN - 7) {
+ ffpmsg("ftp filename is too long (ftp_open)");
+ return (FILE_NOT_OPENED);
+ }
+
+ 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);
+ }
+
+
+ /* 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);
+ }
+
+ 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;
+
+
+ if (!strlen(newfn)) {
+ ffpmsg("Null file name (ftp_open)");
+ fclose(*command);
+ return (FILE_NOT_OPENED);
+ }
+
+
+#ifdef DEBUG
+ puts("connection to passive port");
+#endif
+ /* 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 */
+
+ /* Send the retrieve command */
+ sprintf(tmpstr,"RETR %s\n",newfn);
+ status = NET_SendRaw(*sock,tmpstr,strlen(tmpstr),NET_DEFAULT);
+
+#ifdef DEBUG
+ puts("Sent RETR command");
+#endif
+ if (ftp_status(*command,"150 ")) {
+ /* ffpmsg ("RETR error, most likely file is not there (ftp_open)"); */
+ fclose(*command);
+#ifdef DEBUG
+ puts("File not there");
+#endif
+ return (FILE_NOT_OPENED);
+ }
+ 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:")) {
+
+ /* Move past any user:password */
+ if ((thost = strchr(urlcopy, '@')) != NULL)
+ urlcopy = thost+1;
+
+ 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))) {
+#ifdef DEBUG
+ puts("error reading response in ftp_status");
+#endif
+ return 1; /* error reading */
+ }
+
+#ifdef DEBUG
+ printf("ftp_status, return string was %s\n",recbuf);
+#endif
+
+ 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 < NMAXFILES; 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 < NMAXFILES; 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 < NMAXFILES; 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, LONGLONG *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 = (LONGLONG) 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, LONGLONG 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;
+
+}
+
+/*****************************************************************************/
+/*
+ Encode a string into MIME Base64 format string
+*/
+
+
+static int encode64(unsigned s_len, char *src, unsigned d_len, char *dst) {
+
+ static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+"abcdefghijklmnopqrstuvwxyz"
+"0123456789"
+"+/";
+
+ unsigned triad;
+
+
+ for (triad = 0; triad < s_len; triad += 3) {
+ unsigned long int sr;
+ unsigned byte;
+
+ for (byte = 0; (byte<3) && (triad+byte<s_len); ++byte) {
+ sr <<= 8;
+ sr |= (*(src+triad+byte) & 0xff);
+ }
+
+ /* shift left to next 6 bit alignment*/
+ sr <<= (6-((8*byte)%6))%6;
+
+ if (d_len < 4)
+ return 1;
+
+ *(dst+0) = *(dst+1) = *(dst+2) = *(dst+3) = '=';
+ switch(byte) {
+ case 3:
+ *(dst+3) = base64[sr&0x3f];
+ sr >>= 6;
+ case 2:
+ *(dst+2) = base64[sr&0x3f];
+ sr >>= 6;
+ case 1:
+ *(dst+1) = base64[sr&0x3f];
+ sr >>= 6;
+ *(dst+0) = base64[sr&0x3f];
+ }
+ dst += 4;
+ d_len -= 4;
+ }
+
+ *dst = '\0';
+ return 0;
+}
+
+
+#endif
diff --git a/vendor/cfitsio/drvrsmem.c b/vendor/cfitsio/drvrsmem.c
new file mode 100644
index 00000000..c5fda751
--- /dev/null
+++ b/vendor/cfitsio/drvrsmem.c
@@ -0,0 +1,973 @@
+/* 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>
+
+#if defined(unix) || defined(__unix__) || defined(__unix)
+#include <unistd.h>
+#endif
+
+
+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_getaddr(int id, char **address)
+ { int i;
+ char segname[10];
+
+ if (NULL == shared_gt) return(SHARED_NOTINIT); /* not initialized */
+ if (NULL == shared_lt) return(SHARED_NOTINIT); /* not initialized */
+
+ strcpy(segname,"h");
+ sprintf(segname+1,"%d", id);
+
+ if (smem_open(segname,0,&i)) return(SHARED_BADARG);
+
+ *address = ((char *)(((DAL_SHM_SEGHEAD *)(shared_lt[i].p + 1)) + 1));
+ /* smem_close(i); */
+ return(SHARED_OK);
+ }
+
+
+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, LONGLONG *size)
+ {
+ if (NULL == size) return(SHARED_NULPTR);
+ if (shared_check_locked_index(driverhandle)) return(SHARED_INVALID);
+ *size = (LONGLONG) (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, LONGLONG 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/vendor/cfitsio/drvrsmem.h b/vendor/cfitsio/drvrsmem.h
new file mode 100644
index 00000000..52ac7d7c
--- /dev/null
+++ b/vendor/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, LONGLONG *size);
+int smem_flush(int driverhandle);
+int smem_seek(int driverhandle, LONGLONG 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/vendor/cfitsio/editcol.c b/vendor/cfitsio/editcol.c
new file mode 100644
index 00000000..dc82f025
--- /dev/null
+++ b/vendor/cfitsio/editcol.c
@@ -0,0 +1,2474 @@
+/* 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.
+*/
+{
+ LONGLONG tnaxes[99];
+ int ii;
+
+ if (*status > 0)
+ return(*status);
+
+ for (ii = 0; (ii < naxis) && (ii < 99); ii++)
+ tnaxes[ii] = naxes[ii];
+
+ ffrsimll(fptr, bitpix, naxis, tnaxes, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffrsimll(fitsfile *fptr, /* I - FITS file pointer */
+ int bitpix, /* I - bits per pixel */
+ int naxis, /* I - number of axes in the array */
+ LONGLONG *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 nblocks, longval;
+ long pcount, gcount, longbitpix;
+ LONGLONG onaxes[99], 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 (ffghprll(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: %.0f", ii + 1, (double) (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 = (long) (newsize - oldsize);
+ if (ffiblk(fptr, nblocks, 1, status) > 0)
+ return(*status);
+ }
+ else if (oldsize > newsize) /* have to delete blocks from image */
+ {
+ nblocks = (long) (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 */
+ LONGLONG firstrow, /* I - insert space AFTER this row */
+ /* 0 = insert space at beginning of table */
+ LONGLONG 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;
+ LONGLONG naxis1, naxis2;
+ LONGLONG datasize, firstbyte, nshift, nbytes;
+ LONGLONG freespace;
+ long 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 = (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 = naxis1 * nrows; /* no. of bytes to add to table */
+
+ if ( (freespace - nshift) < 0) /* not enough existing space? */
+ {
+ nblock = (long) ((nshift - freespace + 2879) / 2880); /* number of blocks */
+ ffiblk(fptr, nblock, 1, status); /* insert the blocks */
+ }
+
+ firstbyte = 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", (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 */
+ LONGLONG firstrow, /* I - first row to delete (1 = first) */
+ LONGLONG 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;
+ LONGLONG naxis1, naxis2;
+ LONGLONG datasize, firstbyte, nbytes, nshift;
+ LONGLONG freespace;
+ long 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 */
+
+ ffgkyjj(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 = naxis1 * nrows; /* no. of bytes to delete from table */
+ /* cur size of data */
+ datasize = (fptr->Fptr)->heapstart + (fptr->Fptr)->heapsize;
+
+ firstbyte = 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 = (long) ((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, nrows, *rowarray, jj, kk;
+ LONGLONG naxis2;
+
+ 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).
+*/
+{
+ LONGLONG naxis1, naxis2, insertpos, nextrowpos;
+ long 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 */
+
+ ffgkyjj(fptr, "NAXIS1", &naxis1, comm, status); /* row width */
+ ffgkyjj(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( (size_t) 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 ffdrwsll(fitsfile *fptr, /* I - FITS file pointer */
+ LONGLONG *rownum, /* I - list of rows to delete (1 = first) */
+ LONGLONG 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).
+*/
+{
+ LONGLONG insertpos, nextrowpos;
+ LONGLONG 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 */
+
+ ffgkyjj(fptr, "NAXIS1", &naxis1, comm, status); /* row width */
+ ffgkyjj(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( (size_t) naxis1); /* buffer for one row */
+
+ if (!buffer)
+ {
+ ffpmsg("malloc failed (ffdrwsll)");
+ 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 */
+ LONGLONG 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 = (long) 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 = (long) 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] = (long) maxrows;
+ *numranges = 1;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffrwrgll(
+ char *rowlist, /* I - list of rows and row ranges */
+ LONGLONG maxrows, /* I - number of rows in the list */
+ int maxranges, /* I - max number of ranges to be returned */
+ int *numranges, /* O - number ranges returned */
+ LONGLONG *minrow, /* O - first row in each range */
+ LONGLONG *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;
+ LONGLONG minval, maxval;
+ double dvalue;
+
+ 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) ) {
+
+ /* read as a double, because the string to LONGLONG function */
+ /* is platform dependent (strtoll, strtol, _atoI64) */
+
+ dvalue = strtod(next, &next);
+ minval = (LONGLONG) (dvalue + 0.1);
+
+ } 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) ) {
+
+ /* read as a double, because the string to LONGLONG function */
+ /* is platform dependent (strtoll, strtol, _atoI64) */
+
+ dvalue = strtod(next, &next);
+ maxval = (LONGLONG) (dvalue + 0.1);
+
+ } 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;
+ LONGLONG datasize, firstbyte, nbytes, nadd, naxis1, naxis2, freespace;
+ LONGLONG tbcol, firstcol, delbyte;
+ long nblock, width, repeat;
+ 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 = (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 = delbyte * naxis2; /* no. of bytes to add to table */
+
+ if ( (freespace - nadd) < 0) /* not enough existing space? */
+ {
+ nblock = (long) ((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", (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);
+ ffgkyjj(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 */
+ LONGLONG 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;
+ LONGLONG datasize, size, firstbyte, nbytes, nadd, ndelete;
+ LONGLONG naxis1, naxis2, firstcol, freespace;
+ LONGLONG width, delbyte, repeat;
+ long nblock;
+ 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 = 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 = (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 + 7) / 8) - ((repeat + 7) / 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 = (LONGLONG)delbyte * naxis2; /* no. of bytes to add to table */
+
+ if ( (freespace - nadd) < 0) /* not enough existing space? */
+ {
+ nblock = (long) ((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", (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 - ((LONGLONG)delbyte * naxis2);
+ nblock = (long) (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 = (LONGLONG)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", (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 == TLONGLONG)
+ strcpy(tcode,"K");
+ 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");
+
+ /* write as a double value because the LONGLONG conversion */
+ /* character in sprintf is platform dependent ( %lld, %ld, %I64d ) */
+
+ sprintf(tfm,"%.0f%s",(double) newveclen, tcode);
+
+ 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 ffcprw(fitsfile *infptr, /* I - FITS file pointer to input file */
+ fitsfile *outfptr, /* I - FITS file pointer to output file */
+ LONGLONG firstrow, /* I - number of first row to copy (1 based) */
+ LONGLONG nrows, /* I - number of rows to copy */
+ int *status) /* IO - error status */
+/*
+ copy consecutive set of rows from infptr and append it in the outfptr table.
+*/
+{
+ LONGLONG innaxis1, innaxis2, outnaxis1, outnaxis2, ii, jj;
+ unsigned char *buffer;
+
+ 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 rows to or from IMAGE HDUs (ffcprw)");
+ return(*status = NOT_TABLE);
+ }
+
+ if ( ((infptr->Fptr)->hdutype == BINARY_TBL && (outfptr->Fptr)->hdutype == ASCII_TBL) ||
+ ((infptr->Fptr)->hdutype == ASCII_TBL && (outfptr->Fptr)->hdutype == BINARY_TBL) )
+ {
+ ffpmsg
+ ("Copying rows between Binary and ASCII tables is not supported (ffcprw)");
+ return(*status = NOT_BTABLE);
+ }
+
+ ffgkyjj(infptr, "NAXIS1", &innaxis1, 0, status); /* width of input rows */
+ ffgkyjj(infptr, "NAXIS2", &innaxis2, 0, status); /* no. of input rows */
+ ffgkyjj(outfptr, "NAXIS1", &outnaxis1, 0, status); /* width of output rows */
+ ffgkyjj(outfptr, "NAXIS2", &outnaxis2, 0, status); /* no. of output rows */
+
+ if (*status > 0)
+ return(*status);
+
+ if (outnaxis1 > innaxis1) {
+ ffpmsg
+ ("Input and output tables do not have same width (ffcprw)");
+ return(*status = BAD_ROW_WIDTH);
+ }
+
+ if (firstrow + nrows - 1 > innaxis2) {
+ ffpmsg
+ ("Not enough rows in input table to copy (ffcprw)");
+ return(*status = BAD_ROW_NUM);
+ }
+
+ /* allocate buffer to hold 1 row of data */
+ buffer = malloc( (size_t) innaxis1);
+ if (!buffer) {
+ ffpmsg
+ ("Unable to allocate memory (ffcprw)");
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ /* copy the rows, 1 at a time */
+ jj = outnaxis2 + 1;
+ for (ii = firstrow; ii < firstrow + nrows; ii++) {
+ fits_read_tblbytes (infptr, ii, 1, innaxis1, buffer, status);
+ fits_write_tblbytes(outfptr, jj, 1, innaxis1, buffer, status);
+ jj++;
+ }
+
+ outnaxis2 += nrows;
+ fits_update_key(outfptr, TLONGLONG, "NAXIS2", &outnaxis2, 0, status);
+
+ free(buffer);
+ 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;
+ LONGLONG firstbyte, size, ndelete, nbytes, naxis1, naxis2, firstcol, delbyte, freespace;
+ LONGLONG tbcol;
+ long nblock, nspace;
+ 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 = (long) ((nextcol->tbcol) - (colptr->tbcol) - delbyte);
+ if (nspace > 0)
+ delbyte++;
+ }
+ else if (colnum > 1) /* check for space between last 2 columns */
+ {
+ nextcol = colptr - 1;
+ nspace = (long) ((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 = (fptr->Fptr)->rowlength; /* current width of the table */
+ naxis2 = (fptr->Fptr)->numrows;
+
+ /* current size of table */
+ size = (fptr->Fptr)->heapstart + (fptr->Fptr)->heapsize;
+ freespace = ((LONGLONG)delbyte * naxis2) + ((size + 2879) / 2880) * 2880 - size;
+ nblock = (long) (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 = (LONGLONG)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);
+ ffgkyjj(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 */
+ LONGLONG naxis1, /* I - width of the table, in bytes */
+ LONGLONG naxis2, /* I - number of rows in the table */
+ LONGLONG ninsert, /* I - number of bytes to insert in each row */
+ LONGLONG 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;
+ LONGLONG newlen, fbyte, nbytes, irow, nseg, ii;
+
+ 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 = 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 = 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 = 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 = 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 = newlen; /* new row length */
+
+ ffptbb(fptr, naxis2, fbyte + ninsert, nbytes, buffer, status);
+ (fptr->Fptr)->rowlength = 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 = newlen; /* new row length */
+
+ /* write the row in the new place */
+ ffptbb(fptr, irow, fbyte + ninsert, nbytes, buffer, status);
+ (fptr->Fptr)->rowlength = 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, (size_t) nbytes); /* initialize with fill value */
+
+ nseg = (ninsert + 9999) / 10000;
+ (fptr->Fptr)->rowlength = 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 = naxis1; /* reset to orig value */
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcdel(fitsfile *fptr, /* I - FITS file pointer */
+ LONGLONG naxis1, /* I - width of the table, in bytes */
+ LONGLONG naxis2, /* I - number of rows in the table */
+ LONGLONG ndelete, /* I - number of bytes to delete in each row */
+ LONGLONG 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];
+ LONGLONG i1, i2, ii, irow, nseg;
+ LONGLONG newlen, remain, nbytes;
+
+ 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 = newlen; /* new row length */
+
+ ffptbb(fptr, irow, i1, newlen, buffer, status); /* write row */
+ (fptr->Fptr)->rowlength = 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 = newlen; /* new row length */
+
+ ffptbb(fptr, naxis2, i1, remain, buffer, status); /* write row */
+ (fptr->Fptr)->rowlength = 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 = newlen; /* new row length */
+
+ ffptbb(fptr, irow, i1, nbytes, buffer, status); /* rewrite bytes */
+ (fptr->Fptr)->rowlength = 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 = newlen; /* new row length */
+
+ ffptbb(fptr, naxis2, i1, nbytes, buffer, status); /* write row */
+ (fptr->Fptr)->rowlength = 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 */
+ LONGLONG firstbyte, /* I - position of first byte in block to shift */
+ LONGLONG nbytes, /* I - size of block of bytes to shift */
+ LONGLONG 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;
+ LONGLONG 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 = (long) (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 = (long) (minvalue(ntodo, shftbuffsize));
+ ffpbyt(fptr, ntomov, buffer, status);
+ ntodo -= ntomov;
+ }
+ return(*status);
+}
diff --git a/vendor/cfitsio/edithdu.c b/vendor/cfitsio/edithdu.c
new file mode 100644
index 00000000..385bbe93
--- /dev/null
+++ b/vendor/cfitsio/edithdu.c
@@ -0,0 +1,883 @@
+/* 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
+*/
+{
+ int nspace;
+
+ 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 */
+
+ } else {
+ if (ffghsp(infptr, NULL, &nspace, status) > 0) /* get existing space */
+ return(*status);
+
+ if (nspace > 0) {
+ ffhdef(outfptr, nspace, status); /* preserve same amount of space */
+ if (nspace >= 35) {
+
+ /* There is at least 1 full empty FITS block in the header. */
+ /* Physically write the END keyword at the beginning of the */
+ /* last block to preserve this extra space now rather than */
+ /* later. This is needed by the stream: driver which cannot */
+ /* seek back to the header to write the END keyword later. */
+
+ ffwend(outfptr, status);
+ }
+ }
+ }
+
+ 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;
+
+ 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;
+ LONGLONG indatastart, indataend, outdatastart;
+ char buffer[2880];
+
+ if (*status > 0)
+ return(*status);
+
+ if (infptr == outfptr)
+ return(*status = SAME_FILE);
+
+ ffghadll(infptr, NULL, &indatastart, &indataend, status);
+ ffghadll(outfptr, NULL, &outdatastart, NULL, status);
+
+ /* Calculate the number of blocks to be copied */
+ nb = (long) ((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 ffwrhdu(fitsfile *infptr, /* I - FITS file pointer to input file */
+ FILE *outstream, /* I - stream to write HDU to */
+ int *status) /* IO - error status */
+{
+/*
+ write the data unit from the CHDU of infptr to the output file stream
+*/
+ long nb, ii;
+ LONGLONG hdustart, hduend;
+ char buffer[2880];
+
+ if (*status > 0)
+ return(*status);
+
+ ffghadll(infptr, &hdustart, NULL, &hduend, status);
+
+ nb = (long) ((hduend - hdustart) / 2880); /* number of blocks to copy */
+
+ if (nb > 0)
+ {
+
+ /* move to the start of the HDU */
+ ffmbyt(infptr, hdustart, REPORT_EOF, status);
+
+ for (ii = 0; ii < nb; ii++)
+ {
+ ffgbyt(infptr, 2880L, buffer, status); /* read input block */
+ fwrite(buffer, 1, 2880, outstream ); /* write to output stream */
+ }
+ }
+ 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
+*/
+{
+ LONGLONG tnaxes[99];
+ int ii;
+
+ if (*status > 0)
+ return(*status);
+
+ if (naxis > 99) {
+ ffpmsg("NAXIS value is too large (>99) (ffiimg)");
+ return(*status = 212);
+ }
+
+ for (ii = 0; (ii < naxis); ii++)
+ tnaxes[ii] = naxes[ii];
+
+ ffiimgll(fptr, bitpix, naxis, tnaxes, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffiimgll(fitsfile *fptr, /* I - FITS file pointer */
+ int bitpix, /* I - bits per pixel */
+ int naxis, /* I - number of axes in the array */
+ LONGLONG *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;
+ LONGLONG 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 */
+ ffcrimll(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 || 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, (long) 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 = (long) (((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", 0, "required keyword", status); /* add PCOUNT and */
+ ffikyj(fptr, "GCOUNT", 1, "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 */
+ ffphprll(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 */
+ LONGLONG naxis1, /* I - width of row in the table */
+ LONGLONG 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 */
+ const char *extnmx, /* 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;
+ LONGLONG datasize, newstart;
+ char errmsg[81], extnm[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ extnm[0] = '\0';
+ if (extnmx)
+ strncat(extnm, extnmx, FLEN_VALUE-1);
+
+ 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 = (long) 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 = (LONGLONG)rowlen * naxis2; /* size of table in bytes */
+ nblocks = (long) (((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 */
+ LONGLONG 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 */
+ const char *extnmx, /* I - value of EXTNAME keyword, if any */
+ LONGLONG 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;
+ LONGLONG naxis1;
+ long nblocks, repeat, width;
+ LONGLONG datasize, newstart;
+ char errmsg[81], extnm[FLEN_VALUE];
+
+ if (*status > 0)
+ return(*status);
+
+ extnm[0] = '\0';
+ if (extnmx)
+ strncat(extnm, extnmx, FLEN_VALUE-1);
+
+ 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 = ((LONGLONG)naxis1 * naxis2) + pcount; /* size of table in bytes */
+ nblocks = (long) ((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 = (long) (( (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 = (long) (( (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/vendor/cfitsio/eval.l b/vendor/cfitsio/eval.l
new file mode 100644
index 00000000..c6e3cf8d
--- /dev/null
+++ b/vendor/cfitsio/eval.l
@@ -0,0 +1,545 @@
+%{
+/************************************************************************/
+/* */
+/* 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);
+ if (len >= 256) {
+ char errMsg[100];
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"Bit string exceeds maximum length: '");
+ strncat(errMsg, &(yytext[0]), 20);
+ strcat (errMsg,"...'");
+ ffpmsg (errMsg);
+ len = 0;
+ } else {
+ 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);
+ if (len >= 256) {
+ char errMsg[100];
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"Hex string exceeds maximum length: '");
+ strncat(errMsg, &(yytext[0]), 20);
+ strcat (errMsg,"...'");
+ ffpmsg (errMsg);
+ len = 0;
+ } else {
+ 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;
+ if (len >= MAX_STRLEN) {
+ char errMsg[100];
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"String exceeds maximum length: '");
+ strncat(errMsg, &(yytext[1]), 20);
+ strcat (errMsg,"...'");
+ ffpmsg (errMsg);
+ len = 0;
+ } else {
+ 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 if( FSTRCMP(fname,"STRSTR(")==0 )
+ return( IFUNCTION ); /* Returns integer */
+
+ 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/vendor/cfitsio/eval.y b/vendor/cfitsio/eval.y
new file mode 100644
index 00000000..1f5fd99e
--- /dev/null
+++ b/vendor/cfitsio/eval.y
@@ -0,0 +1,5837 @@
+%{
+/************************************************************************/
+/* */
+/* 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 */
+/* Craig B Markwardt Feb 2005 Add ANGSEP() function */
+/* Craig B Markwardt Aug 2005 CIRCLE, BOX, ELLIPSE, NEAR and REGFILTER*/
+/* functions now accept vector arguments */
+/* Craig B Markwardt Sum 2006 Add RANDOMN() and RANDOMP() functions */
+/* Craig B Markwardt Mar 2007 Allow arguments to RANDOM and RANDOMN to*/
+/* determine the output dimensions */
+/* Craig B Markwardt Aug 2009 Add substring STRMID() and string search*/
+/* STRSTR() functions; more overflow checks*/
+/* */
+/************************************************************************/
+
+#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 OPER(a) gParse.Nodes[ a ].operation
+#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_FuncSize( int returnType, funcOp Op, int nNodes,
+ int Node1, int Node2, int Node3, int Node4,
+ int Node5, int Node6, int Node7, int Size);
+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 int cstrmid(char *dest_str, int dest_len,
+ char *src_str, int src_len, int pos);
+
+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[MAX_STRLEN]; /* 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 /* Bit function */
+%token <str> IFUNCTION /* Integer function */
+%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
+ || OPER($3) != 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
+ {
+ if (SIZE($1)+SIZE($3) >= MAX_STRLEN) {
+ yyerror("Combined bit string size exceeds " MAX_STRLEN_S " bits");
+ YYERROR;
+ }
+ $$ = 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
+ || OPER($3) != 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) { /* Scalar RANDOM() */
+ srand( (unsigned int) time(NULL) );
+ $$ = New_Func( DOUBLE, rnd_fct, 0, 0, 0, 0, 0, 0, 0, 0 );
+ } else if (FSTRCMP($1,"RANDOMN(") == 0) {/*Scalar RANDOMN()*/
+ srand( (unsigned int) time(NULL) );
+ $$ = New_Func( DOUBLE, gasrnd_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 );
+ /* Note: $2 is a vector so the result can never
+ be a constant. Therefore it will never be set
+ inside New_Func(), and it is safe to set SIZE() */
+ 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 );
+ /* Note: $2 is a vector so the result can never
+ be a constant. Therefore it will never be set
+ inside New_Func(), and it is safe to set SIZE() */
+ 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 if (FSTRCMP($1,"RANDOM(") == 0) { /* Vector RANDOM() */
+ srand( (unsigned int) time(NULL) );
+ $$ = New_Func( 0, rnd_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ TEST($$);
+ TYPE($$) = DOUBLE;
+ } else if (FSTRCMP($1,"RANDOMN(") == 0) {
+ srand( (unsigned int) time(NULL) ); /* Vector RANDOMN() */
+ $$ = New_Func( 0, gasrnd_fct, 1, $2, 0, 0, 0, 0, 0, 0 );
+ TEST($$);
+ TYPE($$) = DOUBLE;
+ }
+ 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,"ROUND(") == 0)
+ $$ = New_Func( 0, round_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 if (FSTRCMP($1,"RANDOMP(") == 0) {
+ srand( (unsigned int) time(NULL) );
+ $$ = New_Func( 0, poirnd_fct, 1, $2,
+ 0, 0, 0, 0, 0, 0 );
+ TYPE($$) = LONG;
+ } else {
+ yyerror("Function(expr) not supported");
+ YYERROR;
+ }
+ }
+ TEST($$);
+ }
+ | IFUNCTION sexpr ',' sexpr ')'
+ {
+ if (FSTRCMP($1,"STRSTR(") == 0) {
+ $$ = New_Func( LONG, strpos_fct, 2, $2, $4, 0,
+ 0, 0, 0, 0 );
+ 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;
+ }
+#if 0
+ } else if (FSTRCMP($1,"STRSTR(") == 0) {
+ if( TYPE($2) != STRING || TYPE($4) != STRING) {
+ yyerror("Arguments to strstr(s,r) must be strings");
+ YYERROR;
+ }
+ $$ = New_Func( LONG, strpos_fct, 2, $2, $4, 0,
+ 0, 0, 0, 0 );
+ TEST($$);
+#endif
+ } else {
+ yyerror("Function(expr,expr) not supported");
+ YYERROR;
+ }
+ }
+ | FUNCTION expr ',' expr ',' expr ',' expr ')'
+ {
+ if (FSTRCMP($1,"ANGSEP(") == 0) {
+ 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( Test_Dims( $2, $4 ) && Test_Dims( $4, $6 ) &&
+ Test_Dims( $6, $8 ) ) {
+ $$ = New_Func( 0, angsep_fct, 4, $2, $4, $6, $8,0,0,0 );
+ TEST($$);
+ if( SIZE($2)<SIZE($4) ) Copy_Dims($$, $4);
+ if( SIZE($4)<SIZE($6) ) Copy_Dims($$, $6);
+ if( SIZE($6)<SIZE($8) ) Copy_Dims($$, $8);
+ } else {
+ yyerror("Dimensions of ANGSEP arguments "
+ "are not compatible");
+ YYERROR;
+ }
+ } else {
+ yyerror("Function(expr,expr,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
+ || OPER($3) != 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( 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( ! (Test_Dims( $2, $4 ) && Test_Dims( $4, $6 ) ) ) {
+ yyerror("Dimensions of NEAR arguments "
+ "are not compatible");
+ YYERROR;
+ } else {
+ 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($$);
+
+ if( SIZE($$)<SIZE($2) ) Copy_Dims($$, $2);
+ if( SIZE($2)<SIZE($4) ) Copy_Dims($$, $4);
+ if( SIZE($4)<SIZE($6) ) Copy_Dims($$, $6);
+ }
+ }
+ | BFUNCTION expr ',' expr ',' expr ',' expr ',' expr ')'
+ {
+ 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( ! (Test_Dims( $2, $4 ) && Test_Dims( $4, $6 ) &&
+ Test_Dims( $6, $8 ) && Test_Dims( $8, $10 )) ) {
+ yyerror("Dimensions of CIRCLE arguments "
+ "are not compatible");
+ YYERROR;
+ } else {
+ 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($$);
+ if( SIZE($$)<SIZE($2) ) Copy_Dims($$, $2);
+ if( SIZE($2)<SIZE($4) ) Copy_Dims($$, $4);
+ if( SIZE($4)<SIZE($6) ) Copy_Dims($$, $6);
+ if( SIZE($6)<SIZE($8) ) Copy_Dims($$, $8);
+ if( SIZE($8)<SIZE($10) ) Copy_Dims($$, $10);
+ }
+ }
+ | BFUNCTION expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
+ {
+ 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( ! (Test_Dims( $2, $4 ) && Test_Dims( $4, $6 ) &&
+ Test_Dims( $6, $8 ) && Test_Dims( $8, $10 ) &&
+ Test_Dims($10,$12 ) && Test_Dims($12, $14 ) ) ) {
+ yyerror("Dimensions of BOX or ELLIPSE arguments "
+ "are not compatible");
+ YYERROR;
+ } else {
+ 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($$);
+ if( SIZE($$)<SIZE($2) ) Copy_Dims($$, $2);
+ if( SIZE($2)<SIZE($4) ) Copy_Dims($$, $4);
+ if( SIZE($4)<SIZE($6) ) Copy_Dims($$, $6);
+ if( SIZE($6)<SIZE($8) ) Copy_Dims($$, $8);
+ if( SIZE($8)<SIZE($10) ) Copy_Dims($$, $10);
+ if( SIZE($10)<SIZE($12) ) Copy_Dims($$, $12);
+ if( SIZE($12)<SIZE($14) ) Copy_Dims($$, $14);
+ }
+ }
+
+ | 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
+ || OPER($3) != 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
+ {
+ if (SIZE($1)+SIZE($3) >= MAX_STRLEN) {
+ yyerror("Combined string size exceeds " MAX_STRLEN_S " characters");
+ YYERROR;
+ }
+ $$ = New_BinOp( STRING, $1, '+', $3 ); TEST($$);
+ SIZE($$) = SIZE($1) + SIZE($3);
+ }
+ | bexpr '?' sexpr ':' sexpr
+ {
+ int outSize;
+ if( SIZE($1)!=1 ) {
+ yyerror("Cannot have a vector string column");
+ YYERROR;
+ }
+ /* Since the output can be calculated now, as a constant
+ scalar, we must precalculate the output size, in
+ order to avoid an overflow. */
+ outSize = SIZE($3);
+ if (SIZE($5) > outSize) outSize = SIZE($5);
+ $$ = New_FuncSize( 0, ifthenelse_fct, 3, $3, $5, $1,
+ 0, 0, 0, 0, outSize);
+
+ TEST($$);
+ if( SIZE($3)<SIZE($5) ) Copy_Dims($$, $5);
+ }
+
+ | FUNCTION sexpr ',' sexpr ')'
+ {
+ if (FSTRCMP($1,"DEFNULL(") == 0) {
+ int outSize;
+ /* Since the output can be calculated now, as a constant
+ scalar, we must precalculate the output size, in
+ order to avoid an overflow. */
+ outSize = SIZE($2);
+ if (SIZE($4) > outSize) outSize = SIZE($4);
+
+ $$ = New_FuncSize( 0, defnull_fct, 2, $2, $4, 0,
+ 0, 0, 0, 0, outSize );
+ TEST($$);
+ if( SIZE($4)>SIZE($2) ) SIZE($$) = SIZE($4);
+ } else {
+ yyerror("Function(string,string) not supported");
+ YYERROR;
+ }
+ }
+ | FUNCTION sexpr ',' expr ',' expr ')'
+ {
+ if (FSTRCMP($1,"STRMID(") == 0) {
+ int len;
+ if( TYPE($4) != LONG || SIZE($4) != 1 ||
+ TYPE($6) != LONG || SIZE($6) != 1) {
+ yyerror("When using STRMID(S,P,N), P and N must be integers (and not vector columns)");
+ YYERROR;
+ }
+ if (OPER($6) == CONST_OP) {
+ /* Constant value: use that directly */
+ len = (gParse.Nodes[$6].value.data.lng);
+ } else {
+ /* Variable value: use the maximum possible (from $2) */
+ len = SIZE($2);
+ }
+ if (len <= 0 || len >= MAX_STRLEN) {
+ yyerror("STRMID(S,P,N), N must be 1-" MAX_STRLEN_S);
+ YYERROR;
+ }
+ $$ = New_FuncSize( 0, strmid_fct, 3, $2, $4,$6,0,0,0,0,len);
+ TEST($$);
+ } else {
+ yyerror("Function(string,expr,expr) not supported");
+ YYERROR;
+ }
+ }
+
+ ;
+
+%%
+
+/*************************************************************************/
+/* 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 )
+{
+ return New_FuncSize(returnType, Op, nNodes,
+ Node1, Node2, Node3, Node4,
+ Node5, Node6, Node7, 0);
+}
+
+static int New_FuncSize( int returnType, funcOp Op, int nNodes,
+ int Node1, int Node2, int Node3, int Node4,
+ int Node5, int Node6, int Node7, int Size )
+/* 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 */
+ if (Op == poirnd_fct) constant = 0; /* Nor is Poisson deviate */
+
+ while( i-- )
+ constant = ( constant && OPER(this->SubNodes[i]) == 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];
+ }
+ /* Force explicit size before evaluating */
+ if (Size > 0) this->value.nelem = Size;
+
+ 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( OPER(Node1)==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);
+
+ if( ! (Test_Dims( NodeX, NodeY ) ) ) {
+ yyerror("Dimensions of REGFILTER arguments are not compatible");
+ 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;
+
+ Copy_Dims(n, NodeX);
+ if( SIZE(NodeX)<SIZE(NodeY) ) Copy_Dims(n, NodeY);
+
+ /* 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( OPER(NodeX)==CONST_OP && OPER(NodeY)==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( OPER(i) > 0 || OPER(i) == CONST_OP ) continue;
+
+ column = -OPER(i);
+ 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 = calloc(size+1, elem);
+
+ 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;
+ long 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 = (long) 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;
+ long 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 = (long) 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
+
+/*
+ * angsep_calc - compute angular separation between celestial coordinates
+ *
+ * This routine computes the angular separation between to coordinates
+ * on the celestial sphere (i.e. RA and Dec). Note that all units are
+ * in DEGREES, unlike the other trig functions in the calculator.
+ *
+ * double ra1, dec1 - RA and Dec of the first position in degrees
+ * double ra2, dec2 - RA and Dec of the second position in degrees
+ *
+ * RETURNS: (double) angular separation in degrees
+ *
+ */
+double angsep_calc(double ra1, double dec1, double ra2, double dec2)
+{
+ double cd;
+ static double deg = 0;
+ double a, sdec, sra;
+
+ if (deg == 0) deg = ((double)4)*atan((double)1)/((double)180);
+ /* deg = 1.0; **** UNCOMMENT IF YOU WANT RADIANS */
+
+
+
+/*
+This (commented out) algorithm uses the Low of Cosines, which becomes
+ unstable for angles less than 0.1 arcsec.
+
+ cd = sin(dec1*deg)*sin(dec2*deg)
+ + cos(dec1*deg)*cos(dec2*deg)*cos((ra1-ra2)*deg);
+ if (cd < (-1)) cd = -1;
+ if (cd > (+1)) cd = +1;
+ return acos(cd)/deg;
+*/
+
+ /* The algorithm is the law of Haversines. This algorithm is
+ stable even when the points are close together. The normal
+ Law of Cosines fails for angles around 0.1 arcsec. */
+
+ sra = sin( (ra2 - ra1)*deg / 2 );
+ sdec = sin( (dec2 - dec1)*deg / 2);
+ a = sdec*sdec + cos(dec1*deg)*cos(dec2*deg)*sra*sra;
+
+ /* Sanity checking to avoid a range error in the sqrt()'s below */
+ if (a < 0) { a = 0; }
+ if (a > 1) { a = 1; }
+
+ return 2.0*atan2(sqrt(a), sqrt(1.0 - a)) / deg;
+}
+
+
+
+
+
+
+static double ran1()
+{
+ static double dval = 0.0;
+ double rndVal;
+
+ if (dval == 0.0) {
+ if( rand()<32768 && rand()<32768 )
+ dval = 32768.0;
+ else
+ dval = 2147483648.0;
+ }
+
+ rndVal = (double)rand();
+ while( rndVal > dval ) dval *= 2.0;
+ return rndVal/dval;
+}
+
+/* Gaussian deviate routine from Numerical Recipes */
+static double gasdev()
+{
+ static int iset = 0;
+ static double gset;
+ double fac, rsq, v1, v2;
+
+ if (iset == 0) {
+ do {
+ v1 = 2.0*ran1()-1.0;
+ v2 = 2.0*ran1()-1.0;
+ rsq = v1*v1 + v2*v2;
+ } while (rsq >= 1.0 || rsq == 0.0);
+ fac = sqrt(-2.0*log(rsq)/rsq);
+ gset = v1*fac;
+ iset = 1;
+ return v2*fac;
+ } else {
+ iset = 0;
+ return gset;
+ }
+
+}
+
+/* lgamma function - from Numerical Recipes */
+
+float gammaln(float xx)
+ /* Returns the value ln Gamma[(xx)] for xx > 0. */
+{
+ /*
+ Internal arithmetic will be done in double precision, a nicety
+ that you can omit if five-figure accuracy is good enough. */
+ double x,y,tmp,ser;
+ static double cof[6]={76.18009172947146,-86.50532032941677,
+ 24.01409824083091,-1.231739572450155,
+ 0.1208650973866179e-2,-0.5395239384953e-5};
+ int j;
+ y=x=xx;
+ tmp=x+5.5;
+ tmp -= (x+0.5)*log(tmp);
+ ser=1.000000000190015;
+ for (j=0;j<=5;j++) ser += cof[j]/++y;
+ return (float) -tmp+log(2.5066282746310005*ser/x);
+}
+
+/* Poisson deviate - derived from Numerical Recipes */
+static long poidev(double xm)
+{
+ static double sq, alxm, g, oldm = -1.0;
+ static double pi = 0;
+ double em, t, y;
+
+ if (pi == 0) pi = ((double)4)*atan((double)1);
+
+ if (xm < 20.0) {
+ if (xm != oldm) {
+ oldm = xm;
+ g = exp(-xm);
+ }
+ em = -1;
+ t = 1.0;
+ do {
+ em += 1;
+ t *= ran1();
+ } while (t > g);
+ } else {
+ if (xm != oldm) {
+ oldm = xm;
+ sq = sqrt(2.0*xm);
+ alxm = log(xm);
+ g = xm*alxm-gammaln( (float) (xm+1.0));
+ }
+ do {
+ do {
+ y = tan(pi*ran1());
+ em = sq*y+xm;
+ } while (em < 0.0);
+ em = floor(em);
+ t = 0.9*(1.0+y*y)*exp(em*alxm-gammaln( (float) (em+1.0) )-g);
+ } while (ran1() > t);
+ }
+
+ /* Return integer version */
+ return (long int) floor(em+0.5);
+}
+
+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;
+
+ 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 */
+ /* Random numbers are *never* constant !! */
+ if( this->operation == poirnd_fct ) allConst = 0;
+ if( this->operation == gasrnd_fct ) allConst = 0;
+ if( this->operation == rnd_fct ) allConst = 0;
+
+ 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 poirnd_fct:
+ if( theParams[0]->type==DOUBLE )
+ this->value.data.lng = poidev(pVals[0].data.dbl);
+ else
+ this->value.data.lng = poidev(pVals[0].data.lng);
+ 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;
+
+ /* Four-argument ANGSEP function */
+ case angsep_fct:
+ this->value.data.dbl =
+ angsep_calc(pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl);
+
+ /* 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... scalar or vector 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;
+
+ /* String functions */
+ case strmid_fct:
+ cstrmid(this->value.data.str, this->value.nelem,
+ pVals[0].data.str, pVals[0].nelem,
+ pVals[1].data.lng);
+ break;
+ case strpos_fct:
+ {
+ char *res = strstr(pVals[0].data.str, pVals[1].data.str);
+ if (res == NULL) {
+ this->value.data.lng = 0;
+ } else {
+ this->value.data.lng = (res - pVals[0].data.str) + 1;
+ }
+ 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:
+ while( elem-- ) {
+ this->value.data.dblptr[elem] = ran1();
+ this->value.undef[elem] = 0;
+ }
+ break;
+
+ case gasrnd_fct:
+ while( elem-- ) {
+ this->value.data.dblptr[elem] = gasdev();
+ this->value.undef[elem] = 0;
+ }
+ break;
+
+ case poirnd_fct:
+ if( theParams[0]->type==DOUBLE ) {
+ if (theParams[0]->operation == CONST_OP) {
+ while( elem-- ) {
+ this->value.undef[elem] = (pVals[0].data.dbl < 0);
+ if (! this->value.undef[elem]) {
+ this->value.data.lngptr[elem] = poidev(pVals[0].data.dbl);
+ }
+ }
+ } else {
+ while( elem-- ) {
+ this->value.undef[elem] = theParams[0]->value.undef[elem];
+ if (theParams[0]->value.data.dblptr[elem] < 0)
+ this->value.undef[elem] = 1;
+ if (! this->value.undef[elem]) {
+ this->value.data.lngptr[elem] =
+ poidev(theParams[0]->value.data.dblptr[elem]);
+ }
+ } /* while */
+ } /* ! CONST_OP */
+ } else {
+ /* LONG */
+ if (theParams[0]->operation == CONST_OP) {
+ while( elem-- ) {
+ this->value.undef[elem] = (pVals[0].data.lng < 0);
+ if (! this->value.undef[elem]) {
+ this->value.data.lngptr[elem] = poidev(pVals[0].data.lng);
+ }
+ }
+ } else {
+ while( elem-- ) {
+ this->value.undef[elem] = theParams[0]->value.undef[elem];
+ if (theParams[0]->value.data.lngptr[elem] < 0)
+ this->value.undef[elem] = 1;
+ if (! this->value.undef[elem]) {
+ this->value.data.lngptr[elem] =
+ poidev(theParams[0]->value.data.lngptr[elem]);
+ }
+ } /* while */
+ } /* ! CONST_OP */
+ } /* END LONG */
+ 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;
+
+ /* Four-argument ANGSEP Function */
+
+ case angsep_fct:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=4; 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] ||
+ pNull[2] || pNull[3]) ) )
+ this->value.data.dblptr[elem] =
+ angsep_calc(pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].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... scalar or vector dbls */
+
+ case near_fct:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=3; 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] ||
+ pNull[2]) ) )
+ this->value.data.logptr[elem] =
+ bnear( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl );
+ }
+ }
+ break;
+
+ case circle_fct:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=5; 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] ||
+ pNull[2] || pNull[3] ||
+ pNull[4]) ) )
+ this->value.data.logptr[elem] =
+ 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-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=7; 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] ||
+ pNull[2] || pNull[3] ||
+ pNull[4] || pNull[5] ||
+ pNull[6] ) ) )
+ this->value.data.logptr[elem] =
+ 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-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=7; 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] ||
+ pNull[2] || pNull[3] ||
+ pNull[4] || pNull[5] ||
+ pNull[6] ) ) )
+ this->value.data.logptr[elem] =
+ 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;
+
+ /* String functions */
+ case strmid_fct:
+ {
+ int strconst = theParams[0]->operation == CONST_OP;
+ int posconst = theParams[1]->operation == CONST_OP;
+ int lenconst = theParams[2]->operation == CONST_OP;
+ int dest_len = this->value.nelem;
+ int src_len = theParams[0]->value.nelem;
+
+ while (row--) {
+ int pos;
+ int len;
+ char *str;
+ int undef = 0;
+
+ if (posconst) {
+ pos = theParams[1]->value.data.lng;
+ } else {
+ pos = theParams[1]->value.data.lngptr[row];
+ if (theParams[1]->value.undef[row]) undef = 1;
+ }
+ if (strconst) {
+ str = theParams[0]->value.data.str;
+ if (src_len == 0) src_len = strlen(str);
+ } else {
+ str = theParams[0]->value.data.strptr[row];
+ if (theParams[0]->value.undef[row]) undef = 1;
+ }
+ if (lenconst) {
+ len = dest_len;
+ } else {
+ len = theParams[2]->value.data.lngptr[row];
+ if (theParams[2]->value.undef[row]) undef = 1;
+ }
+ this->value.data.strptr[row][0] = '\0';
+ if (pos == 0) undef = 1;
+ if (! undef ) {
+ if (cstrmid(this->value.data.strptr[row], len,
+ str, src_len, pos) < 0) break;
+ }
+ this->value.undef[row] = undef;
+ }
+ }
+ break;
+
+ /* String functions */
+ case strpos_fct:
+ {
+ int const1 = theParams[0]->operation == CONST_OP;
+ int const2 = theParams[1]->operation == CONST_OP;
+
+ while (row--) {
+ char *str1, *str2;
+ int undef = 0;
+
+ if (const1) {
+ str1 = theParams[0]->value.data.str;
+ } else {
+ str1 = theParams[0]->value.data.strptr[row];
+ if (theParams[0]->value.undef[row]) undef = 1;
+ }
+ if (const2) {
+ str2 = theParams[1]->value.data.str;
+ } else {
+ str2 = theParams[1]->value.data.strptr[row];
+ if (theParams[1]->value.undef[row]) undef = 1;
+ }
+ this->value.data.lngptr[row] = 0;
+ if (! undef ) {
+ char *res = strstr(str1, str2);
+ if (res == NULL) {
+ undef = 1;
+ this->value.data.lngptr[row] = 0;
+ } else {
+ this->value.data.lngptr[row] = (res - str1) + 1;
+ }
+ }
+ this->value.undef[row] = undef;
+ }
+ }
+ break;
+
+
+ } /* End switch(this->operation) */
+ } /* End if (!gParse.status) */
+ } /* End non-constant operations */
+
+ 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( OPER(this->SubNodes[node])>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 );
+}
+
+/*
+ * Extract substring
+ */
+int cstrmid(char *dest_str, int dest_len,
+ char *src_str, int src_len,
+ int pos)
+{
+ /* char fill_char = ' '; */
+ char fill_char = '\0';
+ if (src_len == 0) { src_len = strlen(src_str); } /* .. if constant */
+
+ /* Fill destination with blanks */
+ if (pos < 0) {
+ yyerror("STRMID(S,P,N) P must be 0 or greater");
+ return -1;
+ }
+ if (pos > src_len || pos == 0) {
+ /* pos==0: blank string requested */
+ memset(dest_str, fill_char, dest_len);
+ } else if (pos+dest_len > src_len) {
+ /* Copy a subset */
+ int nsub = src_len-pos+1;
+ int npad = dest_len - nsub;
+ memcpy(dest_str, src_str+pos-1, nsub);
+ /* Fill remaining string with blanks */
+ memset(dest_str+nsub, fill_char, npad);
+ } else {
+ /* Full string copy */
+ memcpy(dest_str, src_str+pos-1, dest_len);
+ }
+ dest_str[dest_len] = '\0'; /* Null-terminate */
+
+ 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/vendor/cfitsio/eval_defs.h b/vendor/cfitsio/eval_defs.h
new file mode 100644
index 00000000..09c066b1
--- /dev/null
+++ b/vendor/cfitsio/eval_defs.h
@@ -0,0 +1,163 @@
+#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"
+
+#define MAXDIMS 5
+#define MAXSUBS 10
+#define MAXVARNAME 80
+#define CONST_OP -1000
+#define pERROR -1
+#define MAX_STRLEN 256
+#define MAX_STRLEN_S "255"
+
+#ifndef FFBISON
+#include "eval_tab.h"
+#endif
+
+
+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[MAX_STRLEN];
+ 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;
+ PixelFilter *pixFilter;
+
+ long firstDataRow;
+ long nDataRows;
+ long totalRows;
+
+ int datatype;
+ int hdutype;
+
+ 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,
+ angsep_fct,
+ gasrnd_fct,
+ poirnd_fct,
+ strmid_fct,
+ strpos_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/vendor/cfitsio/eval_f.c b/vendor/cfitsio/eval_f.c
new file mode 100644
index 00000000..f9bdd051
--- /dev/null
+++ b/vendor/cfitsio/eval_f.c
@@ -0,0 +1,2823 @@
+/************************************************************************/
+/* */
+/* 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 );
+
+static int DEBUG_PIXFILTER;
+
+#define FREE(x) { if (x) free(x); else printf("invalid free(" #x ") at %s:%d\n", __FILE__, __LINE__); }
+
+/*---------------------------------------------------------------------------*/
+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 );
+
+ FFLOCK;
+ if( ffiprs( fptr, 0, expr, MAXDIMS, &Info.datatype, &nelem, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ FFUNLOCK;
+ 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.");
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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;
+ LONGLONG ntodo, inbyteloc, outbyteloc, hsize;
+ long freespace;
+ unsigned char *buffer, result;
+ struct {
+ LONGLONG rowLength, numRows, heapSize;
+ LONGLONG dataStart, heapStart;
+ } inExt, outExt;
+
+ if( *status ) return( *status );
+
+ FFLOCK;
+ if( ffiprs( infptr, 0, expr, MAXDIMS, &Info.datatype, &nelem, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ FFUNLOCK;
+ 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.");
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ return( *status = PARSE_BAD_OUTPUT );
+ }
+
+ /***********************************/
+ /* Fill out Info data for parser */
+ /***********************************/
+
+ Info.dataPtr = (char *)malloc( (size_t) ((inExt.numRows + 1) * sizeof(char)) );
+ Info.nullPtr = NULL;
+ Info.maxRows = (long) inExt.numRows;
+ if( !Info.dataPtr ) {
+ ffpmsg("Unable to allocate memory for row selection");
+ ffcprs();
+ FFUNLOCK;
+ 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 = (long) (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 = (long) inExt.rowLength;
+ buffer = (unsigned char *)malloc(maxvalue(500000,rdlen) * sizeof(char) );
+ if( buffer==NULL ) {
+ ffcprs();
+ FFUNLOCK;
+ 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 = (long) (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 = (long) (( ( (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, (long) 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 = (long) 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 ) {
+ LONGLONG 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++ ) {
+ ffgdesll( 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 */
+ FFUNLOCK;
+ 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 );
+
+ FFLOCK;
+ if( ffiprs( fptr, 0, expr, MAXDIMS, &Info.datatype, &nelem1, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ FFUNLOCK;
+ return( *status );
+ }
+ if( nelem1<0 ) nelem1 = - nelem1;
+
+ if( nelements<nelem1 ) {
+ ffcprs();
+ ffpmsg("Array not large enough to hold at least one row of data.");
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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];
+
+ if( *status ) return( *status );
+
+ FFLOCK;
+ if( ffiprs( infptr, 0, expr, MAXDIMS, &Info.datatype, &nelem, &naxis,
+ naxes, status ) ) {
+
+ ffcprs();
+ FFUNLOCK;
+ 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)" );
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ return( *status );
+ }
+
+ } else
+ colNo = -1;
+
+ if( colNo<0 ) {
+
+ /* Case (4): Create new column */
+
+ *status = 0;
+ ffgncl( outfptr, &colNo, status );
+ colNo++;
+ if( parInfo==NULL || *parInfo=='\0' ) {
+ /* Figure out best default column type */
+ if( gParse.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;
+ case TLONGLONG: strcat(tform,"K"); break;
+ }
+ } else {
+ switch( Info.datatype ) {
+ case TLOGICAL:
+ ffcprs();
+ ffpmsg("Cannot create LOGICAL column in ASCII table");
+ FFUNLOCK;
+ return( *status = NOT_BTABLE );
+ 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)) && gParse.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( gParse.hdutype==BINARY_TBL ) {
+ LONGLONG 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;
+ else if( typecode==TLONGLONG )
+ nullVal = LONGLONG_MIN;
+
+ if( nullVal ) {
+ ffpkyj( outfptr, nullKwd, nullVal, "Null value", status );
+ fits_set_btblnull( outfptr, colNo, nullVal, status );
+ newNullKwd = 1;
+ }
+ } else if( gParse.hdutype==ASCII_TBL ) {
+ ffpkys( outfptr, nullKwd, "NULL", "Null value string", status );
+ fits_set_atblnull( outfptr, colNo, "NULL", status );
+ newNullKwd = 1;
+ }
+ }
+
+ }
+
+ } else if( *status ) {
+ ffcprs();
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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. */
+/*--------------------------------------------------------------------------*/
+{
+ FFLOCK;
+ ffiprs( fptr, 0, expr, maxdim, datatype, nelem, naxis, naxes, status );
+ ffcprs();
+ FFUNLOCK;
+ 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;
+ int xaxis, bitpix;
+ long xaxes[9];
+ static iteratorCol dmyCol;
+
+ if( *status ) return( *status );
+
+ /* make sure all internal structures for this HDU are current */
+ if ( ffrdef(fptr, 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.hdutype = 0;
+ gParse.status = 0;
+
+ fits_get_hdu_type(fptr, &gParse.hdutype, status );
+
+ if (gParse.hdutype == IMAGE_HDU) {
+
+ fits_get_img_param(fptr, 9, &bitpix, &xaxis, xaxes, status);
+ if (*status) {
+ ffpmsg("ffiprs: unable to get image dimensions");
+ return( *status );
+ }
+ gParse.totalRows = xaxis > 0 ? 1 : 0;
+ for (i = 0; i < xaxis; ++i)
+ gParse.totalRows *= xaxes[i];
+ if (DEBUG_PIXFILTER)
+ printf("naxis=%d, gParse.totalRows=%ld\n", xaxis, gParse.totalRows);
+ }
+ else 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 needed 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-- ) {
+ if( gParse.Nodes[node].operation==gtifilt_fct ) {
+ i = gParse.Nodes[node].SubNodes[0];
+ if (gParse.Nodes[ i ].value.data.ptr)
+ FREE( gParse.Nodes[ i ].value.data.ptr );
+ }
+ else if( gParse.Nodes[node].operation==regfilt_fct ) {
+ i = gParse.Nodes[node].SubNodes[0];
+ fits_free_region( (SAORegion *)gParse.Nodes[ i ].value.data.ptr );
+ }
+ }
+ gParse.nNodes = 0;
+ }
+ if( gParse.Nodes ) free( gParse.Nodes );
+ gParse.Nodes = NULL;
+
+ gParse.hdutype = ANY_HDU;
+ gParse.pixFilter = 0;
+}
+
+/*---------------------------------------------------------------------------*/
+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;
+ iteratorCol * outcol;
+
+ /* declare variables static to preserve their values between calls */
+ static void *Data, *Null;
+ static int datasize;
+ static long lastRow, repeat, resDataSize;
+ static LONGLONG jnull;
+ static parseInfo *userInfo;
+ static long zeros[4] = {0,0,0,0};
+
+ if (DEBUG_PIXFILTER)
+ printf("parse_data(total=%ld, offset=%ld, first=%ld, rows=%ld, cols=%d)\n",
+ totalrows, offset, firstrow, nrows, nCols);
+ /*--------------------------------------------------------*/
+ /* Initialization procedures: execute on the first call */
+ /*--------------------------------------------------------*/
+ outcol = colData + (nCols - 1);
+ 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( outcol->iotype == InputCol ) {
+ ffpmsg("Output column for parser results not found!");
+ return( PARSE_NO_OUTPUT );
+ }
+ /* Data gets set later */
+ Null = outcol->array;
+ userInfo->datatype = outcol->datatype;
+
+ /* Check for a TNULL/BLANK keyword for output column/image */
+
+ status = 0;
+ jnull = 0;
+ if (gParse.hdutype == IMAGE_HDU) {
+ if (gParse.pixFilter->blank)
+ jnull = (LONGLONG) gParse.pixFilter->blank;
+ }
+ else {
+ ffgknjj( outcol->fptr, "TNULL", outcol->colnum,
+ 1, &jnull, (int*)&jj, &status );
+
+ if( status==BAD_INTKEY ) {
+ /* Probably ASCII table with text TNULL keyword */
+ switch( userInfo->datatype ) {
+ case TSHORT: jnull = (LONGLONG) SHRT_MIN; break;
+ case TINT: jnull = (LONGLONG) INT_MIN; break;
+ case TLONG: jnull = (LONGLONG) LONG_MIN; break;
+ }
+ }
+ }
+ repeat = outcol->repeat;
+ if (DEBUG_PIXFILTER)
+ printf("parse_data: using null value %ld\n", jnull);
+ } 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 TLONGLONG: datasize = sizeof(LONGLONG); 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 (DEBUG_PIXFILTER)
+ printf("parse_data: using null value %ld\n", jnull);
+
+
+ if( userInfo->dataPtr == NULL ) {
+ /* First, reset Data pointer to start of output array */
+ Data = (char*) outcol->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 TLONGLONG: *(LONGLONG *)Null = (LONGLONG )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 the calling routine specified that only a limited number */
+ /* of rows in the table should be processed, return a value of -1 */
+ /* once all the rows have been done, if no other error occurred. */
+
+ if (gParse.hdutype != IMAGE_HDU && 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;
+ char msg[80];
+
+ gParse.firstDataRow = fRow;
+ gParse.nDataRows = nRows;
+
+ /* Resize and fill in UNDEF arrays for each column */
+
+ for( i=0; i<nCols; i++ ) {
+
+ iteratorCol *icol = cols + i;
+ DataInfo *varData = gParse.varData + i;
+
+ if( icol->iotype == OutputCol ) continue;
+
+ nelem = varData->nelem;
+ len = nelem * nRows;
+
+ switch ( varData->type ) {
+
+ case BITSTR:
+ /* No need for UNDEF array, but must make string DATA array */
+ len = (nelem+1)*nRows; /* Count '\0' */
+ bitStrs = (char**)varData->data;
+ if( bitStrs ) FREE( bitStrs[0] );
+ free( bitStrs );
+ bitStrs = (char**)malloc( nRows*sizeof(char*) );
+ if( bitStrs==NULL ) {
+ varData->data = varData->undef = NULL;
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ bitStrs[0] = (char*)malloc( len*sizeof(char) );
+ if( bitStrs[0]==NULL ) {
+ free( bitStrs );
+ varData->data = varData->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*)icol->array)[idx] & (1<<(7-len%8)) )
+ bitStrs[row][len] = '1';
+ else
+ bitStrs[row][len] = '0';
+ if( len%8==7 ) idx++;
+ }
+ bitStrs[row][len] = '\0';
+ }
+ varData->undef = (char*)bitStrs;
+ varData->data = (char*)bitStrs;
+ break;
+
+ case STRING:
+ sptr = (char**)icol->array;
+ if (varData->undef)
+ free( varData->undef );
+ varData->undef = (char*)malloc( nRows*sizeof(char) );
+ if( varData->undef==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ row = nRows;
+ while( row-- )
+ varData->undef[row] =
+ ( **sptr != '\0' && FSTRCMP( sptr[0], sptr[row+1] )==0 );
+ varData->data = sptr + 1;
+ break;
+
+ case BOOLEAN:
+ barray = (char*)icol->array;
+ if (varData->undef)
+ free( varData->undef );
+ varData->undef = (char*)malloc( len*sizeof(char) );
+ if( varData->undef==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ while( len-- ) {
+ varData->undef[len] =
+ ( barray[0]!=0 && barray[0]==barray[len+1] );
+ }
+ varData->data = barray + 1;
+ break;
+
+ case LONG:
+ iarray = (long*)icol->array;
+ if (varData->undef)
+ free( varData->undef );
+ varData->undef = (char*)malloc( len*sizeof(char) );
+ if( varData->undef==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ while( len-- ) {
+ varData->undef[len] =
+ ( iarray[0]!=0L && iarray[0]==iarray[len+1] );
+ }
+ varData->data = iarray + 1;
+ break;
+
+ case DOUBLE:
+ rarray = (double*)icol->array;
+ if (varData->undef)
+ free( varData->undef );
+ varData->undef = (char*)malloc( len*sizeof(char) );
+ if( varData->undef==NULL ) {
+ gParse.status = MEMORY_ALLOCATION;
+ break;
+ }
+ while( len-- ) {
+ varData->undef[len] =
+ ( rarray[0]!=0.0 && rarray[0]==rarray[len+1]);
+ }
+ varData->data = rarray + 1;
+ break;
+
+ default:
+ sprintf(msg, "SetupDataArrays, unhandled type %d\n",
+ varData->type);
+ ffpmsg(msg);
+ }
+
+ if( gParse.status ) { /* Deallocate NULL arrays of previous columns */
+ while( i-- ) {
+ varData = gParse.varData + i;
+ if( varData->type==BITSTR )
+ FREE( ((char**)varData->data)[0] );
+ FREE( varData->undef );
+ varData->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 );
+ 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 );
+ 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 TLONGLONG:
+ switch( inputType ) {
+ case TLOGICAL:
+ case TBYTE:
+ for( i=0; i<ntodo; i++ )
+ ((LONGLONG*)output)[i] = ((unsigned char*)input)[i];
+ break;
+ case TSHORT:
+ for( i=0; i<ntodo; i++ )
+ ((LONGLONG*)output)[i] = ((short*)input)[i];
+ break;
+ case TLONG:
+ for( i=0; i<ntodo; i++ )
+ ((LONGLONG*)output)[i] = ((long*)input)[i];
+ break;
+ case TFLOAT:
+ fffr4i8((float*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (LONGLONG*)output,status);
+ break;
+ case TDOUBLE:
+ fffr8i8((double*)input,ntodo,1.,0.,0,0,NULL,NULL,
+ (LONGLONG*)output,status);
+
+ break;
+ default:
+ *status = BAD_DATATYPE;
+ break;
+ }
+ for(i=0;i<ntodo;i++) {
+ if( undef[i] ) {
+ ((LONGLONG*)output)[i] = *(LONGLONG*)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] = (float) ((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 );
+
+ FFLOCK;
+ if( ffiprs( fptr, 0, expr, MAXDIMS, &dtype, &nelem, &naxis,
+ naxes, status ) ) {
+ ffcprs();
+ FFUNLOCK;
+ 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.");
+ FFUNLOCK;
+ 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();
+ FFUNLOCK;
+ 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 );
+}
+
+
+static int set_image_col_types (fitsfile * fptr, const char * name, int bitpix,
+ DataInfo * varInfo, iteratorCol *colIter) {
+
+ int istatus;
+ double tscale, tzero;
+ char temp[80];
+
+ switch (bitpix) {
+ case BYTE_IMG:
+ case SHORT_IMG:
+ case LONG_IMG:
+ istatus = 0;
+ if (fits_read_key(fptr, TDOUBLE, "BZERO", &tzero, NULL, &istatus))
+ tzero = 0.0;
+
+ istatus = 0;
+ if (fits_read_key(fptr, TDOUBLE, "BSCALE", &tscale, NULL, &istatus))
+ tscale = 1.0;
+
+ if (tscale == 1.0 && (tzero == 0.0 || tzero == 32768.0 )) {
+ varInfo->type = LONG;
+ colIter->datatype = TLONG;
+ }
+ else {
+ varInfo->type = DOUBLE;
+ colIter->datatype = TDOUBLE;
+ if (DEBUG_PIXFILTER)
+ printf("use DOUBLE for %s with BSCALE=%g/BZERO=%g\n",
+ name, tscale, tzero);
+ }
+ break;
+
+ case LONGLONG_IMG:
+ case FLOAT_IMG:
+ case DOUBLE_IMG:
+ varInfo->type = DOUBLE;
+ colIter->datatype = TDOUBLE;
+ break;
+ default:
+ sprintf(temp, "set_image_col_types: unrecognized image bitpix [%d]\n",
+ bitpix);
+ ffpmsg(temp);
+ return gParse.status = PARSE_BAD_TYPE;
+ }
+ return 0;
+}
+
+
+/*************************************************************************
+
+ 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;
+ long repeat, width;
+ fitsfile *fptr;
+ char temp[80];
+ double tzero,tscale;
+ int istatus;
+ DataInfo *varInfo;
+ iteratorCol *colIter;
+
+if (DEBUG_PIXFILTER)
+ printf("find_column(%s)\n", colName);
+
+ if( *colName == '#' )
+ return( find_keywd( colName + 1, itslval ) );
+
+ fptr = gParse.def_fptr;
+
+ status = 0;
+ col_cnt = gParse.nCols;
+
+if (gParse.hdutype == IMAGE_HDU) {
+ int i;
+ if (!gParse.pixFilter) {
+ gParse.status = COL_NOT_FOUND;
+ ffpmsg("find_column: IMAGE_HDU but no PixelFilter");
+ return pERROR;
+ }
+
+ colnum = -1;
+ for (i = 0; i < gParse.pixFilter->count; ++i) {
+ if (!strcasecmp(colName, gParse.pixFilter->tag[i]))
+ colnum = i;
+ }
+ if (colnum < 0) {
+ sprintf(temp, "find_column: PixelFilter tag %s not found", colName);
+ ffpmsg(temp);
+ gParse.status = COL_NOT_FOUND;
+ return pERROR;
+ }
+
+ if( allocateCol( col_cnt, &gParse.status ) ) return pERROR;
+
+ varInfo = gParse.varData + col_cnt;
+ colIter = gParse.colData + col_cnt;
+
+ fptr = gParse.pixFilter->ifptr[colnum];
+ fits_get_img_param(fptr,
+ MAXDIMS,
+ &typecode, /* actually bitpix */
+ &varInfo->naxis,
+ &varInfo->naxes[0],
+ &status);
+ varInfo->nelem = 1;
+ type = COLUMN;
+ if (set_image_col_types(fptr, colName, typecode, varInfo, colIter))
+ return pERROR;
+ colIter->fptr = fptr;
+ colIter->iotype = InputCol;
+}
+else { /* HDU holds a table */
+ 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;
+ }
+
+ if( allocateCol( col_cnt, &gParse.status ) ) return pERROR;
+
+ varInfo = gParse.varData + col_cnt;
+ colIter = gParse.colData + col_cnt;
+
+ fits_iter_set_by_num( colIter, fptr, colnum, 0, InputCol );
+}
+
+ /* Make sure we don't overflow variable name array */
+ strncpy(varInfo->name,colName,MAXVARNAME);
+ varInfo->name[MAXVARNAME] = '\0';
+
+if (gParse.hdutype != IMAGE_HDU) {
+ switch( typecode ) {
+ case TBIT:
+ varInfo->type = BITSTR;
+ colIter->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 )) {
+ varInfo->type = LONG;
+ colIter->datatype = TLONG;
+/* Reading an unsigned long column as a long can cause overflow errors.
+ Treat the column as a double instead.
+ } else if (tscale == 1.0 && tzero == 2147483648.0 ) {
+ varInfo->type = LONG;
+ colIter->datatype = TULONG;
+ */
+
+ }
+ else {
+ varInfo->type = DOUBLE;
+ colIter->datatype = TDOUBLE;
+ }
+ type = COLUMN;
+ break;
+/*
+ For now, treat 8-byte integer columns as type double.
+ This can lose precision, so the better long term solution
+ will be to add support for TLONGLONG as a separate datatype.
+*/
+ case TLONGLONG:
+ case TFLOAT:
+ case TDOUBLE:
+ varInfo->type = DOUBLE;
+ colIter->datatype = TDOUBLE;
+ type = COLUMN;
+ break;
+ case TLOGICAL:
+ varInfo->type = BOOLEAN;
+ colIter->datatype = TLOGICAL;
+ type = BCOLUMN;
+ break;
+ case TSTRING:
+ varInfo->type = STRING;
+ colIter->datatype = TSTRING;
+ type = SCOLUMN;
+ if ( width >= MAX_STRLEN ) {
+ sprintf(temp, "column %d is wider than maximum %d characters",
+ colnum, MAX_STRLEN-1);
+ ffpmsg(temp);
+ gParse.status = PARSE_LRG_VECTOR;
+ return pERROR;
+ }
+ if( gParse.hdutype == ASCII_TBL ) repeat = width;
+ break;
+ default:
+ if (typecode < 0) {
+ sprintf(temp, "variable-length array columns are not supported. typecode = %d", typecode);
+ ffpmsg(temp);
+ }
+ gParse.status = PARSE_BAD_TYPE;
+ return pERROR;
+ }
+ varInfo->nelem = repeat;
+ if( repeat>1 && typecode!=TSTRING ) {
+ if( fits_read_tdim( fptr, colnum, MAXDIMS,
+ &varInfo->naxis,
+ &varInfo->naxes[0], &status )
+ ) {
+ gParse.status = status;
+ return pERROR;
+ }
+ } else {
+ varInfo->naxis = 1;
+ varInfo->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, msg[80];
+ unsigned char *bytes;
+ int status = 0, anynul;
+
+ if (gParse.hdutype == IMAGE_HDU) {
+ /* This test would need to be on a per varNum basis to support
+ * cross HDU operations */
+ fits_read_imgnull(var->fptr, var->datatype, fRow, nRows,
+ data, undef, &anynul, &status);
+ if (DEBUG_PIXFILTER)
+ printf("load_column: IMAGE_HDU fRow=%ld, nRows=%ld => %d\n",
+ fRow, nRows, status);
+ } else {
+
+ 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;
+ default:
+ sprintf(msg,"load_column: unexpected datatype %d", var->datatype);
+ ffpmsg(msg);
+ }
+ }
+ if( status ) {
+ gParse.status = status;
+ return pERROR;
+ }
+
+ return 0;
+}
+
+
+/*--------------------------------------------------------------------------*/
+int fits_pixel_filter (PixelFilter * filter, int * status)
+/* Evaluate an expression using the data in the input FITS file(s) */
+/*--------------------------------------------------------------------------*/
+{
+ parseInfo Info = { 0 };
+ int naxis, bitpix;
+ long nelem, naxes[MAXDIMS];
+ int col_cnt;
+ Node *result;
+ int datatype;
+ fitsfile * infptr;
+ fitsfile * outfptr;
+ char * DEFAULT_TAGS[] = { "X" };
+ char msg[256];
+ int writeBlankKwd = 0; /* write BLANK if any output nulls? */
+
+ DEBUG_PIXFILTER = getenv("DEBUG_PIXFILTER") ? 1 : 0;
+
+ if (*status)
+ return (*status);
+
+ FFLOCK;
+ if (!filter->tag || !filter->tag[0] || !filter->tag[0][0]) {
+ filter->tag = DEFAULT_TAGS;
+ if (DEBUG_PIXFILTER)
+ printf("using default tag '%s'\n", filter->tag[0]);
+ }
+
+ infptr = filter->ifptr[0];
+ outfptr = filter->ofptr;
+ gParse.pixFilter = filter;
+
+ if (ffiprs(infptr, 0, filter->expression, MAXDIMS,
+ &Info.datatype, &nelem, &naxis, naxes, status)) {
+ goto CLEANUP;
+ }
+
+ if (nelem < 0) {
+ nelem = -nelem;
+ }
+
+ {
+ /* validate result type */
+ const char * type = 0;
+ switch (Info.datatype) {
+ case TLOGICAL: type = "LOGICAL"; break;
+ case TLONG: type = "LONG"; break;
+ case TDOUBLE: type = "DOUBLE"; break;
+ case TSTRING: type = "STRING";
+ *status = pERROR;
+ ffpmsg("pixel_filter: cannot have string image");
+ case TBIT: type = "BIT";
+ if (DEBUG_PIXFILTER)
+ printf("hmm, image from bits?\n");
+ break;
+ default: type = "UNKNOWN?!";
+ *status = pERROR;
+ ffpmsg("pixel_filter: unexpected result datatype");
+ }
+ if (DEBUG_PIXFILTER)
+ printf("result type is %s [%d]\n", type, Info.datatype);
+ if (*status)
+ goto CLEANUP;
+ }
+
+ if (fits_get_img_param(infptr, MAXDIMS,
+ &bitpix, &naxis, &naxes[0], status)) {
+ ffpmsg("pixel_filter: unable to read input image parameters");
+ goto CLEANUP;
+ }
+
+ if (DEBUG_PIXFILTER)
+ printf("input bitpix %d\n", bitpix);
+
+ if (Info.datatype == TDOUBLE) {
+ /* for floating point expressions, set the default output image to
+ bitpix = -32 (float) unless the default is already a double */
+ if (bitpix != DOUBLE_IMG)
+ bitpix = FLOAT_IMG;
+ }
+
+ /* override output image bitpix if specified by caller */
+ if (filter->bitpix)
+ bitpix = filter->bitpix;
+ if (DEBUG_PIXFILTER)
+ printf("output bitpix %d\n", bitpix);
+
+ if (fits_create_img(outfptr, bitpix, naxis, naxes, status)) {
+ ffpmsg("pixel_filter: unable to create output image");
+ goto CLEANUP;
+ }
+
+ /* transfer keycards */
+ {
+ int i, ncards, more;
+ if (fits_get_hdrspace(infptr, &ncards, &more, status)) {
+ ffpmsg("pixel_filter: unable to determine number of keycards");
+ goto CLEANUP;
+ }
+
+ for (i = 1; i <= ncards; ++i) {
+
+ int keyclass;
+ char card[FLEN_CARD];
+
+ if (fits_read_record(infptr, i, card, status)) {
+ sprintf(msg, "pixel_filter: unable to read keycard %d", i);
+ ffpmsg(msg);
+ goto CLEANUP;
+ }
+
+ keyclass = fits_get_keyclass(card);
+ if (keyclass == TYP_STRUC_KEY) {
+ /* output structure defined by fits_create_img */
+ }
+ else if (keyclass == TYP_COMM_KEY && i < 12) {
+ /* assume this is one of the FITS standard comments */
+ }
+ else if (keyclass == TYP_NULL_KEY && bitpix < 0) {
+ /* do not transfer BLANK to real output image */
+ }
+ else if (keyclass == TYP_SCAL_KEY && bitpix < 0) {
+ /* do not transfer BZERO, BSCALE to real output image */
+ }
+ else if (fits_write_record(outfptr, card, status)) {
+ sprintf(msg, "pixel_filter: unable to write keycard '%s' [%d]\n",
+ card, *status);
+ ffpmsg(msg);
+ goto CLEANUP;
+ }
+ }
+ }
+
+ switch (bitpix) {
+ case BYTE_IMG: datatype = TLONG; Info.datatype = TBYTE; break;
+ case SHORT_IMG: datatype = TLONG; Info.datatype = TSHORT; break;
+ case LONG_IMG: datatype = TLONG; Info.datatype = TLONG; break;
+ case FLOAT_IMG: datatype = TDOUBLE; Info.datatype = TFLOAT; break;
+ case DOUBLE_IMG: datatype = TDOUBLE; Info.datatype = TDOUBLE; break;
+
+ default:
+ sprintf(msg, "pixel_filter: unexpected output bitpix %d\n", bitpix);
+ ffpmsg(msg);
+ *status = pERROR;
+ goto CLEANUP;
+ }
+
+ if (bitpix > 0) { /* arrange for NULLs in output */
+ long nullVal = filter->blank;
+ if (!filter->blank) {
+ int tstatus = 0;
+ if (fits_read_key_lng(infptr, "BLANK", &nullVal, 0, &tstatus)) {
+
+ writeBlankKwd = 1;
+
+ if (bitpix == BYTE_IMG)
+ nullVal = UCHAR_MAX;
+ else if (bitpix == SHORT_IMG)
+ nullVal = SHRT_MIN;
+ else if (bitpix == LONG_IMG)
+ nullVal = LONG_MIN;
+ else
+ printf("unhandled positive output BITPIX %d\n", bitpix);
+ }
+
+ filter->blank = nullVal;
+ }
+
+ fits_set_imgnull(outfptr, filter->blank, status);
+ if (DEBUG_PIXFILTER)
+ printf("using blank %ld\n", nullVal);
+
+ }
+
+ if (!filter->keyword[0]) {
+ iteratorCol * colIter;
+ DataInfo * varInfo;
+
+ /*************************************/
+ /* Create new iterator Output Column */
+ /*************************************/
+ col_cnt = gParse.nCols;
+ if (allocateCol(col_cnt, status))
+ goto CLEANUP;
+ gParse.nCols++;
+
+ colIter = &gParse.colData[col_cnt];
+ colIter->fptr = filter->ofptr;
+ colIter->iotype = OutputCol;
+ varInfo = &gParse.varData[col_cnt];
+ set_image_col_types(colIter->fptr, "CREATED", bitpix, varInfo, colIter);
+
+ Info.maxRows = -1;
+
+ if (ffiter(gParse.nCols, gParse.colData, 0,
+ 0, parse_data, &Info, status) == -1)
+ *status = 0;
+ else if (*status)
+ goto CLEANUP;
+
+ if (Info.anyNull) {
+ if (writeBlankKwd) {
+ fits_update_key_lng(outfptr, "BLANK", filter->blank, "NULL pixel value", status);
+ if (*status)
+ ffpmsg("pixel_filter: unable to write BLANK keyword");
+ if (DEBUG_PIXFILTER) {
+ printf("output has NULLs\n");
+ printf("wrote blank [%d]\n", *status);
+ }
+ }
+ }
+ else if (bitpix > 0) /* never used a null */
+ if (fits_set_imgnull(outfptr, -1234554321, status))
+ ffpmsg("pixel_filter: unable to reset imgnull");
+ }
+ else {
+
+ /* Put constant result into keyword */
+ char * parName = filter->keyword;
+ char * parInfo = filter->comment;
+
+ 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;
+ default:
+ sprintf(msg, "pixel_filter: unexpected constant result type [%d]\n",
+ Info.datatype);
+ ffpmsg(msg);
+ }
+ }
+
+CLEANUP:
+ ffcprs();
+ FFUNLOCK;
+ return (*status);
+}
diff --git a/vendor/cfitsio/eval_l.c b/vendor/cfitsio/eval_l.c
new file mode 100644
index 00000000..7dcb5dc1
--- /dev/null
+++ b/vendor/cfitsio/eval_l.c
@@ -0,0 +1,2252 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /software/lheasoft/lheavc/hip/cfitsio/eval_l.c,v 3.47 2009/09/04 18:35:05 pence 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);
+ if (len >= 256) {
+ char errMsg[100];
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"Bit string exceeds maximum length: '");
+ strncat(errMsg, &(fftext[0]), 20);
+ strcat (errMsg,"...'");
+ ffpmsg (errMsg);
+ len = 0;
+ } else {
+ 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 215 "eval.l"
+{
+ int len;
+ char tmpstring[256];
+ char bitstring[256];
+ len = strlen(fftext);
+ if (len >= 256) {
+ char errMsg[100];
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"Hex string exceeds maximum length: '");
+ strncat(errMsg, &(fftext[0]), 20);
+ strcat (errMsg,"...'");
+ ffpmsg (errMsg);
+ len = 0;
+ } else {
+ 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 306 "eval.l"
+{
+ fflval.lng = atol(fftext);
+ return( LONG );
+ }
+ FF_BREAK
+case 6:
+FF_RULE_SETUP
+#line 310 "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 317 "eval.l"
+{
+ fflval.dbl = atof(fftext);
+ return( DOUBLE );
+ }
+ FF_BREAK
+case 8:
+FF_RULE_SETUP
+#line 321 "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 349 "eval.l"
+{
+ int len;
+ len = strlen(fftext) - 2;
+ if (len >= MAX_STRLEN) {
+ char errMsg[100];
+ gParse.status = PARSE_SYNTAX_ERR;
+ strcpy (errMsg,"String exceeds maximum length: '");
+ strncat(errMsg, &(fftext[1]), 20);
+ strcat (errMsg,"...'");
+ ffpmsg (errMsg);
+ len = 0;
+ } else {
+ strncpy(fflval.str,&fftext[1],len);
+ }
+ fflval.str[len] = '\0';
+ return( STRING );
+ }
+ FF_BREAK
+case 10:
+FF_RULE_SETUP
+#line 366 "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 378 "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 if( FSTRCMP(fname,"STRSTR(")==0 )
+ return( IFUNCTION ); /* Returns integer */
+
+ else
+ return( FUNCTION );
+ }
+ FF_BREAK
+case 12:
+FF_RULE_SETUP
+#line 405 "eval.l"
+{ return( INTCAST ); }
+ FF_BREAK
+case 13:
+FF_RULE_SETUP
+#line 406 "eval.l"
+{ return( FLTCAST ); }
+ FF_BREAK
+case 14:
+FF_RULE_SETUP
+#line 407 "eval.l"
+{ return( POWER ); }
+ FF_BREAK
+case 15:
+FF_RULE_SETUP
+#line 408 "eval.l"
+{ return( NOT ); }
+ FF_BREAK
+case 16:
+FF_RULE_SETUP
+#line 409 "eval.l"
+{ return( OR ); }
+ FF_BREAK
+case 17:
+FF_RULE_SETUP
+#line 410 "eval.l"
+{ return( AND ); }
+ FF_BREAK
+case 18:
+FF_RULE_SETUP
+#line 411 "eval.l"
+{ return( EQ ); }
+ FF_BREAK
+case 19:
+FF_RULE_SETUP
+#line 412 "eval.l"
+{ return( NE ); }
+ FF_BREAK
+case 20:
+FF_RULE_SETUP
+#line 413 "eval.l"
+{ return( GT ); }
+ FF_BREAK
+case 21:
+FF_RULE_SETUP
+#line 414 "eval.l"
+{ return( LT ); }
+ FF_BREAK
+case 22:
+FF_RULE_SETUP
+#line 415 "eval.l"
+{ return( GTE ); }
+ FF_BREAK
+case 23:
+FF_RULE_SETUP
+#line 416 "eval.l"
+{ return( LTE ); }
+ FF_BREAK
+case 24:
+FF_RULE_SETUP
+#line 417 "eval.l"
+{ return( '\n' ); }
+ FF_BREAK
+case 25:
+FF_RULE_SETUP
+#line 418 "eval.l"
+{ return( fftext[0] ); }
+ FF_BREAK
+case 26:
+FF_RULE_SETUP
+#line 419 "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 419 "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/vendor/cfitsio/eval_tab.h b/vendor/cfitsio/eval_tab.h
new file mode 100644
index 00000000..aed44591
--- /dev/null
+++ b/vendor/cfitsio/eval_tab.h
@@ -0,0 +1,42 @@
+typedef union {
+ int Node; /* Index of Node */
+ double dbl; /* real value */
+ long lng; /* integer value */
+ char log; /* logical value */
+ char str[MAX_STRLEN]; /* 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 IFUNCTION 265
+#define GTIFILTER 266
+#define REGFILTER 267
+#define COLUMN 268
+#define BCOLUMN 269
+#define SCOLUMN 270
+#define BITCOL 271
+#define ROWREF 272
+#define NULLREF 273
+#define SNULLREF 274
+#define OR 275
+#define AND 276
+#define EQ 277
+#define NE 278
+#define GT 279
+#define LT 280
+#define LTE 281
+#define GTE 282
+#define POWER 283
+#define NOT 284
+#define INTCAST 285
+#define FLTCAST 286
+#define UMINUS 287
+#define ACCUM 288
+#define DIFF 289
+
+
+extern FFSTYPE fflval;
diff --git a/vendor/cfitsio/eval_y.c b/vendor/cfitsio/eval_y.c
new file mode 100644
index 00000000..e18cf115
--- /dev/null
+++ b/vendor/cfitsio/eval_y.c
@@ -0,0 +1,7333 @@
+
+/* 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 IFUNCTION 265
+#define GTIFILTER 266
+#define REGFILTER 267
+#define COLUMN 268
+#define BCOLUMN 269
+#define SCOLUMN 270
+#define BITCOL 271
+#define ROWREF 272
+#define NULLREF 273
+#define SNULLREF 274
+#define OR 275
+#define AND 276
+#define EQ 277
+#define NE 278
+#define GT 279
+#define LT 280
+#define LTE 281
+#define GTE 282
+#define POWER 283
+#define NOT 284
+#define INTCAST 285
+#define FLTCAST 286
+#define UMINUS 287
+#define ACCUM 288
+#define DIFF 289
+
+#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 */
+/* Craig B Markwardt Feb 2005 Add ANGSEP() function */
+/* Craig B Markwardt Aug 2005 CIRCLE, BOX, ELLIPSE, NEAR and REGFILTER*/
+/* functions now accept vector arguments */
+/* Craig B Markwardt Sum 2006 Add RANDOMN() and RANDOMP() functions */
+/* Craig B Markwardt Mar 2007 Allow arguments to RANDOM and RANDOMN to*/
+/* determine the output dimensions */
+/* Craig B Markwardt Aug 2009 Add substring STRMID() and string search*/
+/* STRSTR() functions; more overflow checks*/
+/* */
+/************************************************************************/
+
+#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 OPER(a) gParse.Nodes[ a ].operation
+#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_FuncSize( int returnType, funcOp Op, int nNodes,
+ int Node1, int Node2, int Node3, int Node4,
+ int Node5, int Node6, int Node7, int Size);
+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 int cstrmid(char *dest_str, int dest_len,
+ char *src_str, int src_len, int pos);
+
+static void fferror(char *msg);
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#line 189 "eval.y"
+typedef union {
+ int Node; /* Index of Node */
+ double dbl; /* real value */
+ long lng; /* integer value */
+ char log; /* logical value */
+ char str[MAX_STRLEN]; /* string value */
+} FFSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define FFFINAL 290
+#define FFFLAG -32768
+#define FFNTBASE 54
+
+#define FFTRANSLATE(x) ((unsigned)(x) <= 289 ? fftranslate[x] : 62)
+
+static const char fftranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 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, 37, 41, 2, 52,
+ 53, 38, 35, 20, 36, 2, 39, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 22, 2, 2,
+ 21, 2, 25, 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,
+ 47, 2, 51, 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, 23, 40, 24, 30, 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, 19, 26, 27, 28, 29, 31, 32,
+ 33, 34, 42, 43, 44, 45, 46, 48, 49
+};
+
+#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, 228, 238, 243, 250,
+ 259, 270, 283, 286, 289, 292, 295, 297, 299, 304,
+ 308, 312, 316, 320, 324, 328, 332, 336, 340, 344,
+ 348, 352, 356, 360, 364, 368, 372, 376, 380, 384,
+ 388, 392, 396, 402, 408, 412, 416, 420, 426, 434,
+ 446, 462, 465, 469, 475, 485, 489, 497, 507, 512,
+ 519, 528, 539, 552, 555, 559, 561, 563, 568, 570,
+ 574, 578, 584, 590
+};
+
+static const short ffrhs[] = { -1,
+ 54, 55, 0, 50, 0, 58, 50, 0, 59, 50,
+ 0, 61, 50, 0, 60, 50, 0, 1, 50, 0,
+ 23, 59, 0, 56, 20, 59, 0, 23, 58, 0,
+ 57, 20, 58, 0, 57, 20, 59, 0, 56, 20,
+ 58, 0, 57, 24, 0, 56, 24, 0, 7, 0,
+ 16, 0, 16, 23, 58, 24, 0, 60, 41, 60,
+ 0, 60, 40, 60, 0, 60, 35, 60, 0, 60,
+ 47, 58, 51, 0, 60, 47, 58, 20, 58, 51,
+ 0, 60, 47, 58, 20, 58, 20, 58, 51, 0,
+ 60, 47, 58, 20, 58, 20, 58, 20, 58, 51,
+ 0, 60, 47, 58, 20, 58, 20, 58, 20, 58,
+ 20, 58, 51, 0, 43, 60, 0, 52, 60, 53,
+ 0, 4, 0, 5, 0, 13, 0, 13, 23, 58,
+ 24, 0, 17, 0, 18, 0, 58, 37, 58, 0,
+ 58, 35, 58, 0, 58, 36, 58, 0, 58, 38,
+ 58, 0, 58, 39, 58, 0, 58, 42, 58, 0,
+ 35, 58, 0, 36, 58, 0, 52, 58, 53, 0,
+ 58, 38, 59, 0, 59, 38, 58, 0, 59, 25,
+ 58, 22, 58, 0, 59, 25, 59, 22, 58, 0,
+ 59, 25, 58, 22, 59, 0, 8, 53, 0, 8,
+ 59, 53, 0, 8, 61, 53, 0, 8, 60, 53,
+ 0, 8, 58, 53, 0, 10, 61, 20, 61, 53,
+ 0, 8, 58, 20, 58, 53, 0, 8, 58, 20,
+ 58, 20, 58, 20, 58, 53, 0, 58, 47, 58,
+ 51, 0, 58, 47, 58, 20, 58, 51, 0, 58,
+ 47, 58, 20, 58, 20, 58, 51, 0, 58, 47,
+ 58, 20, 58, 20, 58, 20, 58, 51, 0, 58,
+ 47, 58, 20, 58, 20, 58, 20, 58, 20, 58,
+ 51, 0, 44, 58, 0, 44, 59, 0, 45, 58,
+ 0, 45, 59, 0, 3, 0, 14, 0, 14, 23,
+ 58, 24, 0, 60, 28, 60, 0, 60, 29, 60,
+ 0, 60, 32, 60, 0, 60, 33, 60, 0, 60,
+ 31, 60, 0, 60, 34, 60, 0, 58, 31, 58,
+ 0, 58, 32, 58, 0, 58, 34, 58, 0, 58,
+ 33, 58, 0, 58, 30, 58, 0, 58, 28, 58,
+ 0, 58, 29, 58, 0, 61, 28, 61, 0, 61,
+ 29, 61, 0, 61, 31, 61, 0, 61, 34, 61,
+ 0, 61, 32, 61, 0, 61, 33, 61, 0, 59,
+ 27, 59, 0, 59, 26, 59, 0, 59, 28, 59,
+ 0, 59, 29, 59, 0, 58, 21, 58, 22, 58,
+ 0, 59, 25, 59, 22, 59, 0, 9, 58, 53,
+ 0, 9, 59, 53, 0, 9, 61, 53, 0, 8,
+ 59, 20, 59, 53, 0, 9, 58, 20, 58, 20,
+ 58, 53, 0, 9, 58, 20, 58, 20, 58, 20,
+ 58, 20, 58, 53, 0, 9, 58, 20, 58, 20,
+ 58, 20, 58, 20, 58, 20, 58, 20, 58, 53,
+ 0, 11, 53, 0, 11, 6, 53, 0, 11, 6,
+ 20, 58, 53, 0, 11, 6, 20, 58, 20, 6,
+ 20, 6, 53, 0, 12, 6, 53, 0, 12, 6,
+ 20, 58, 20, 58, 53, 0, 12, 6, 20, 58,
+ 20, 58, 20, 6, 53, 0, 59, 47, 58, 51,
+ 0, 59, 47, 58, 20, 58, 51, 0, 59, 47,
+ 58, 20, 58, 20, 58, 51, 0, 59, 47, 58,
+ 20, 58, 20, 58, 20, 58, 51, 0, 59, 47,
+ 58, 20, 58, 20, 58, 20, 58, 20, 58, 51,
+ 0, 43, 59, 0, 52, 59, 53, 0, 6, 0,
+ 15, 0, 15, 23, 58, 24, 0, 19, 0, 52,
+ 61, 53, 0, 61, 35, 61, 0, 59, 25, 61,
+ 22, 61, 0, 8, 61, 20, 61, 53, 0, 8,
+ 61, 20, 58, 20, 58, 53, 0
+};
+
+#endif
+
+#if FFDEBUG != 0
+static const short ffrline[] = { 0,
+ 241, 242, 245, 246, 252, 258, 264, 270, 273, 275,
+ 288, 290, 303, 314, 328, 332, 336, 340, 342, 351,
+ 354, 357, 366, 368, 370, 372, 374, 376, 379, 383,
+ 385, 387, 389, 398, 400, 402, 405, 408, 411, 414,
+ 417, 420, 422, 424, 426, 430, 434, 453, 472, 491,
+ 504, 518, 530, 561, 659, 667, 729, 753, 755, 757,
+ 759, 761, 763, 765, 767, 769, 773, 775, 777, 786,
+ 789, 792, 795, 798, 801, 804, 807, 810, 813, 816,
+ 819, 822, 825, 828, 831, 834, 837, 840, 843, 845,
+ 847, 849, 852, 859, 876, 889, 902, 913, 929, 953,
+ 981, 1018, 1022, 1026, 1029, 1033, 1037, 1040, 1044, 1046,
+ 1048, 1050, 1052, 1054, 1056, 1060, 1063, 1065, 1074, 1076,
+ 1078, 1087, 1106, 1125
+};
+#endif
+
+
+#if FFDEBUG != 0 || defined (FFERROR_VERBOSE)
+
+static const char * const fftname[] = { "$","error","$undefined.","BOOLEAN",
+"LONG","DOUBLE","STRING","BITSTR","FUNCTION","BFUNCTION","IFUNCTION","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,
+ 54, 54, 55, 55, 55, 55, 55, 55, 56, 56,
+ 57, 57, 57, 57, 58, 59, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 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, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 61, 61, 61, 61, 61,
+ 61, 61, 61, 61
+};
+
+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, 5, 9, 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, 7
+};
+
+static const short ffdefact[] = { 1,
+ 0, 0, 67, 30, 31, 116, 17, 0, 0, 0,
+ 0, 0, 32, 68, 117, 18, 34, 35, 119, 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, 0, 0, 0, 102, 0,
+ 0, 0, 0, 0, 11, 9, 0, 42, 43, 114,
+ 28, 63, 64, 65, 66, 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, 95, 96, 97, 0, 0, 103,
+ 0, 106, 0, 0, 0, 0, 44, 115, 29, 120,
+ 14, 10, 12, 13, 0, 81, 82, 80, 76, 77,
+ 79, 78, 37, 38, 36, 39, 45, 40, 41, 0,
+ 0, 0, 0, 90, 89, 91, 92, 46, 0, 0,
+ 0, 70, 71, 74, 72, 73, 75, 22, 21, 20,
+ 0, 83, 84, 85, 87, 88, 86, 121, 0, 0,
+ 0, 0, 0, 0, 0, 0, 33, 69, 118, 19,
+ 0, 0, 58, 0, 0, 0, 0, 109, 28, 0,
+ 0, 23, 0, 56, 98, 0, 123, 0, 55, 0,
+ 104, 0, 93, 0, 47, 49, 48, 94, 122, 0,
+ 0, 0, 0, 0, 0, 0, 0, 59, 0, 110,
+ 0, 24, 0, 124, 0, 99, 0, 0, 107, 0,
+ 0, 0, 0, 0, 0, 0, 0, 60, 0, 111,
+ 0, 25, 57, 0, 105, 108, 0, 0, 0, 0,
+ 0, 61, 0, 112, 0, 26, 0, 100, 0, 0,
+ 0, 0, 62, 113, 27, 0, 0, 101, 0, 0
+};
+
+static const short ffdefgoto[] = { 1,
+ 28, 29, 30, 45, 46, 43, 57
+};
+
+static const short ffpact[] = {-32768,
+ 301, -41,-32768,-32768,-32768,-32768,-32768, 351, 402, 402,
+ -5, 12, 8, 33, 34, 41,-32768,-32768,-32768, 402,
+ 402, 402, 402, 402, 402,-32768, 402,-32768, -18, 9,
+ 1092, 403, 1438, 79,-32768,-32768, 428, 143, 294, 10,
+ 456, 224, 1478, 125, 1390, 1436, 1523, -6,-32768, 2,
+ 402, 402, 402, 402, 1390, 1436, 1129, 19, 19, 20,
+ 21, 19, 20, 19, 20, 623, 240, 344, 1120, 402,
+-32768, 402,-32768, 402, 402, 402, 402, 402, 402, 402,
+ 402, 402, 402, 402, 402, 402, 402, 402,-32768, 402,
+ 402, 402, 402, 402, 402, 402,-32768, -3, -3, -3,
+ -3, -3, -3, -3, -3, -3, 402,-32768, 402, 402,
+ 402, 402, 402, 402, 402,-32768, 402,-32768, 402,-32768,
+-32768, 402,-32768, 402,-32768,-32768,-32768, 402, 402,-32768,
+ 402,-32768, 1266, 1286, 1306, 1326,-32768,-32768,-32768,-32768,
+ 1390, 1436, 1390, 1436, 1348, 1503, 1503, 1503, 23, 23,
+ 23, 23, 160, 160, 160, -15, 20, -15, -15, 732,
+ 1370, 1413, 1531, 146, -13, -35, -35, -15, 756, -3,
+ -3, -30, -30, -30, -30, -30, -30, 50, 21, 21,
+ 780, 67, 67, 11, 11, 11, 11,-32768, 484, 1118,
+ 1146, 1415, 1166, 1424, 512, 1186,-32768,-32768,-32768,-32768,
+ 402, 402,-32768, 402, 402, 402, 402,-32768, 21, 1480,
+ 402,-32768, 402,-32768,-32768, 402,-32768, 402,-32768, 66,
+-32768, 402, 1461, 804, 1461, 1436, 1461, 1436, 1129, 828,
+ 852, 1206, 650, 540, 68, 568, 402,-32768, 402,-32768,
+ 402,-32768, 402,-32768, 402,-32768, 86, 87,-32768, 876,
+ 900, 924, 677, 1226, 52, 56, 402,-32768, 402,-32768,
+ 402,-32768,-32768, 402,-32768,-32768, 948, 972, 996, 596,
+ 402,-32768, 402,-32768, 402,-32768, 402,-32768, 1020, 1044,
+ 1068, 1246,-32768,-32768,-32768, 402, 704,-32768, 126,-32768
+};
+
+static const short ffpgoto[] = {-32768,
+-32768,-32768,-32768, -1, 95, 124, 27
+};
+
+
+#define FFLAST 1566
+
+
+static const short fftable[] = { 31,
+ 48, 70, 95, 7, 104, 71, 37, 41, 35, 105,
+ 106, 96, 16, 129, 93, 94, 107, 50, 55, 58,
+ 59, 131, 62, 64, 95, 66, 87, 34, 72, 122,
+ 51, 88, 73, 96, 40, 44, 47, 109, 110, 170,
+ 111, 112, 113, 114, 115, 115, 130, 49, 171, 133,
+ 134, 135, 136, 69, 132, 52, 53, 82, 83, 84,
+ 85, 86, 123, 54, 87, 88, 96, 107, 141, 88,
+ 143, 235, 145, 146, 147, 148, 149, 150, 151, 152,
+ 153, 154, 155, 156, 158, 159, 160, 247, 161, 105,
+ 106, 255, 256, 168, 169, 32, 107, 111, 112, 113,
+ 114, 115, 38, 42, 265, 181, 109, 110, 266, 111,
+ 112, 113, 114, 115, 56, 189, 163, 60, 63, 65,
+ 191, 67, 193, 0, 33, 290, 0, 195, 116, 196,
+ 0, 39, 0, 0, 0, 182, 183, 184, 185, 186,
+ 187, 188, 0, 0, 0, 0, 61, 0, 192, 0,
+ 68, 0, 109, 110, 194, 111, 112, 113, 114, 115,
+ 0, 0, 119, 0, 142, 0, 144, 90, 91, 92,
+ 93, 94, 92, 93, 94, 0, 0, 127, 0, 157,
+ 95, 0, 0, 95, 162, 164, 165, 166, 167, 96,
+ 0, 0, 96, 0, 0, 120, 0, 85, 86, 223,
+ 224, 87, 225, 227, 0, 230, 88, 0, 0, 231,
+ 0, 232, 0, 190, 233, 0, 234, 0, 0, 0,
+ 236, 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 0, 0, 229, 0, 0, 250, 0, 251, 0, 252,
+ 0, 253, 0, 254, 0, 0, 0, 0, 90, 91,
+ 92, 93, 94, 0, 0, 267, 0, 268, 0, 269,
+ 0, 95, 270, 0, 90, 91, 92, 93, 94, 279,
+ 96, 280, 0, 281, 0, 282, 126, 95, 0, 0,
+ 0, 0, 0, 0, 287, 0, 96, 0, 0, 0,
+ 0, 0, 138, 209, 210, 0, 0, 0, 226, 228,
+ 289, 2, 0, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 0, 98, 99, 20, 100, 101, 102, 103, 104, 0,
+ 0, 0, 0, 105, 106, 21, 22, 0, 0, 0,
+ 107, 0, 0, 23, 24, 25, 121, 0, 0, 0,
+ 26, 0, 27, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 0, 98, 99, 20, 100, 101, 102, 103, 104, 0,
+ 0, 0, 0, 105, 106, 21, 22, 0, 0, 0,
+ 107, 0, 0, 23, 24, 25, 139, 0, 0, 0,
+ 0, 0, 27, 36, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 0, 0, 0, 20, 0, 0, 90, 91, 92,
+ 93, 94, 0, 0, 0, 0, 21, 22, 0, 0,
+ 95, 0, 0, 0, 23, 24, 25, 117, 74, 96,
+ 0, 0, 97, 27, 0, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 0, 0, 87,
+ 0, 0, 0, 0, 88, 124, 74, 0, 0, 0,
+ 118, 0, 0, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 0, 87, 0, 0,
+ 0, 0, 88, 213, 74, 0, 0, 0, 125, 0,
+ 0, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 0, 0, 87, 0, 0, 0, 0,
+ 88, 220, 74, 0, 0, 0, 214, 0, 0, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ 86, 0, 0, 87, 0, 0, 0, 0, 88, 245,
+ 74, 0, 0, 0, 221, 0, 0, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 0, 87, 0, 0, 0, 0, 88, 248, 74, 0,
+ 0, 0, 246, 0, 0, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 0, 0, 87,
+ 0, 0, 0, 0, 88, 277, 74, 0, 0, 0,
+ 249, 0, 0, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 0, 87, 0, 0,
+ 0, 0, 88, 74, 0, 0, 0, 0, 278, 0,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 0, 0, 87, 0, 0, 0, 0, 88,
+ 74, 0, 0, 0, 0, 137, 0, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 0, 87, 0, 0, 0, 0, 88, 74, 0, 0,
+ 0, 0, 244, 0, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 0, 0, 87, 0,
+ 0, 0, 0, 88, 74, 0, 0, 0, 0, 263,
+ 0, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 0, 0, 87, 0, 0, 0, 0,
+ 88, 202, 74, 0, 0, 0, 288, 0, 0, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ 86, 0, 0, 87, 0, 207, 74, 0, 88, 0,
+ 0, 0, 203, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 0, 87, 0, 211,
+ 74, 0, 88, 0, 0, 0, 208, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 0, 87, 0, 237, 74, 0, 88, 0, 0, 0,
+ 212, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 0, 0, 87, 0, 239, 74, 0,
+ 88, 0, 0, 0, 238, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 0, 0, 87,
+ 0, 241, 74, 0, 88, 0, 0, 0, 240, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ 86, 0, 0, 87, 0, 257, 74, 0, 88, 0,
+ 0, 0, 242, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 0, 87, 0, 259,
+ 74, 0, 88, 0, 0, 0, 258, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 0, 87, 0, 261, 74, 0, 88, 0, 0, 0,
+ 260, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 0, 0, 87, 0, 271, 74, 0,
+ 88, 0, 0, 0, 262, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 0, 0, 87,
+ 0, 273, 74, 0, 88, 0, 0, 0, 272, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ 86, 0, 0, 87, 0, 275, 74, 0, 88, 0,
+ 0, 0, 274, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 0, 87, 0, 0,
+ 74, 0, 88, 0, 0, 0, 276, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 0, 87, 0, 0, 74, 0, 88, 0, 0, 0,
+ 283, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 0, 0, 87, 0, 0, 74, 0,
+ 88, 0, 0, 0, 284, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 0, 0, 87,
+ 0, 0, 74, 0, 88, 0, 0, 0, 285, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+ 86, 0, 0, 87, 0, 0, 0, 0, 88, 0,
+ 0, 89, 90, 91, 92, 93, 94, 109, 110, 0,
+ 111, 112, 113, 114, 115, 95, 109, 110, 0, 111,
+ 112, 113, 114, 115, 96, 216, 74, 0, 0, 0,
+ 215, 0, 140, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 218, 74, 87, 0, 0,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 222, 74, 87, 0, 0,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 243, 74, 87, 0, 0,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 264, 74, 87, 0, 0,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 286, 74, 87, 0, 0,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 74, 87, 0, 197,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 74, 87, 0, 198,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 74, 87, 0, 199,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 74, 87, 0, 200,
+ 0, 0, 88, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 0, 0, 87, 74, 201,
+ 0, 0, 88, 0, 0, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 0, 0, 87,
+ 74, 204, 0, 0, 88, 0, 0, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 74, 87, 0, 0, 0, 0, 88, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 0,
+ 0, 87, 0, 0, 205, 0, 88, 90, 91, 92,
+ 93, 94, 109, 110, 0, 111, 112, 113, 114, 115,
+ 95, 109, 110, 0, 111, 112, 113, 114, 115, 96,
+ 90, 91, 92, 93, 94, 98, 99, 217, 100, 101,
+ 102, 103, 104, 95, 0, 0, 219, 105, 106, 0,
+ 0, 0, 96, 0, 107, 0, 0, 108, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+ 0, 0, 87, 0, 0, 98, 99, 88, 100, 101,
+ 102, 103, 104, 0, 104, 0, 0, 105, 106, 105,
+ 106, 0, 0, 0, 107, 0, 107, 0, 0, 0,
+ 0, 0, 139, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 128, 0, 87, 0, 0, 0, 0, 88,
+ 109, 110, 206, 111, 112, 113, 114, 115, 109, 110,
+ 0, 111, 112, 113, 114, 115
+};
+
+static const short ffcheck[] = { 1,
+ 6, 20, 38, 7, 35, 24, 8, 9, 50, 40,
+ 41, 47, 16, 20, 28, 29, 47, 6, 20, 21,
+ 22, 20, 24, 25, 38, 27, 42, 1, 20, 20,
+ 23, 47, 24, 47, 8, 9, 10, 28, 29, 43,
+ 31, 32, 33, 34, 35, 35, 53, 53, 52, 51,
+ 52, 53, 54, 27, 53, 23, 23, 35, 36, 37,
+ 38, 39, 53, 23, 42, 47, 47, 47, 70, 47,
+ 72, 6, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 20, 90, 40,
+ 41, 6, 6, 95, 96, 1, 47, 31, 32, 33,
+ 34, 35, 8, 9, 53, 107, 28, 29, 53, 31,
+ 32, 33, 34, 35, 20, 117, 90, 23, 24, 25,
+ 122, 27, 124, -1, 1, 0, -1, 129, 50, 131,
+ -1, 8, -1, -1, -1, 109, 110, 111, 112, 113,
+ 114, 115, -1, -1, -1, -1, 23, -1, 122, -1,
+ 27, -1, 28, 29, 128, 31, 32, 33, 34, 35,
+ -1, -1, 20, -1, 70, -1, 72, 25, 26, 27,
+ 28, 29, 27, 28, 29, -1, -1, 53, -1, 85,
+ 38, -1, -1, 38, 90, 91, 92, 93, 94, 47,
+ -1, -1, 47, -1, -1, 53, -1, 38, 39, 201,
+ 202, 42, 204, 205, -1, 207, 47, -1, -1, 211,
+ -1, 213, -1, 119, 216, -1, 218, -1, -1, -1,
+ 222, 98, 99, 100, 101, 102, 103, 104, 105, 106,
+ -1, -1, 206, -1, -1, 237, -1, 239, -1, 241,
+ -1, 243, -1, 245, -1, -1, -1, -1, 25, 26,
+ 27, 28, 29, -1, -1, 257, -1, 259, -1, 261,
+ -1, 38, 264, -1, 25, 26, 27, 28, 29, 271,
+ 47, 273, -1, 275, -1, 277, 53, 38, -1, -1,
+ -1, -1, -1, -1, 286, -1, 47, -1, -1, -1,
+ -1, -1, 53, 170, 171, -1, -1, -1, 204, 205,
+ 0, 1, -1, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ -1, 28, 29, 23, 31, 32, 33, 34, 35, -1,
+ -1, -1, -1, 40, 41, 35, 36, -1, -1, -1,
+ 47, -1, -1, 43, 44, 45, 53, -1, -1, -1,
+ 50, -1, 52, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ -1, 28, 29, 23, 31, 32, 33, 34, 35, -1,
+ -1, -1, -1, 40, 41, 35, 36, -1, -1, -1,
+ 47, -1, -1, 43, 44, 45, 53, -1, -1, -1,
+ -1, -1, 52, 53, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, -1, -1, -1, 23, -1, -1, 25, 26, 27,
+ 28, 29, -1, -1, -1, -1, 35, 36, -1, -1,
+ 38, -1, -1, -1, 43, 44, 45, 20, 21, 47,
+ -1, -1, 50, 52, -1, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, 42,
+ -1, -1, -1, -1, 47, 20, 21, -1, -1, -1,
+ 53, -1, -1, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, -1, 42, -1, -1,
+ -1, -1, 47, 20, 21, -1, -1, -1, 53, -1,
+ -1, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, -1, -1, 42, -1, -1, -1, -1,
+ 47, 20, 21, -1, -1, -1, 53, -1, -1, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, -1, -1, 42, -1, -1, -1, -1, 47, 20,
+ 21, -1, -1, -1, 53, -1, -1, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ -1, 42, -1, -1, -1, -1, 47, 20, 21, -1,
+ -1, -1, 53, -1, -1, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, 42,
+ -1, -1, -1, -1, 47, 20, 21, -1, -1, -1,
+ 53, -1, -1, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, -1, 42, -1, -1,
+ -1, -1, 47, 21, -1, -1, -1, -1, 53, -1,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, -1, -1, 42, -1, -1, -1, -1, 47,
+ 21, -1, -1, -1, -1, 53, -1, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ -1, 42, -1, -1, -1, -1, 47, 21, -1, -1,
+ -1, -1, 53, -1, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, -1, -1, 42, -1,
+ -1, -1, -1, 47, 21, -1, -1, -1, -1, 53,
+ -1, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, -1, -1, 42, -1, -1, -1, -1,
+ 47, 20, 21, -1, -1, -1, 53, -1, -1, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, -1, -1, 42, -1, 20, 21, -1, 47, -1,
+ -1, -1, 51, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, -1, 42, -1, 20,
+ 21, -1, 47, -1, -1, -1, 51, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ -1, 42, -1, 20, 21, -1, 47, -1, -1, -1,
+ 51, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, -1, -1, 42, -1, 20, 21, -1,
+ 47, -1, -1, -1, 51, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, 42,
+ -1, 20, 21, -1, 47, -1, -1, -1, 51, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, -1, -1, 42, -1, 20, 21, -1, 47, -1,
+ -1, -1, 51, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, -1, 42, -1, 20,
+ 21, -1, 47, -1, -1, -1, 51, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ -1, 42, -1, 20, 21, -1, 47, -1, -1, -1,
+ 51, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, -1, -1, 42, -1, 20, 21, -1,
+ 47, -1, -1, -1, 51, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, 42,
+ -1, 20, 21, -1, 47, -1, -1, -1, 51, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, -1, -1, 42, -1, 20, 21, -1, 47, -1,
+ -1, -1, 51, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, -1, 42, -1, -1,
+ 21, -1, 47, -1, -1, -1, 51, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ -1, 42, -1, -1, 21, -1, 47, -1, -1, -1,
+ 51, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, -1, -1, 42, -1, -1, 21, -1,
+ 47, -1, -1, -1, 51, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, 42,
+ -1, -1, 21, -1, 47, -1, -1, -1, 51, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, -1, -1, 42, -1, -1, -1, -1, 47, -1,
+ -1, 50, 25, 26, 27, 28, 29, 28, 29, -1,
+ 31, 32, 33, 34, 35, 38, 28, 29, -1, 31,
+ 32, 33, 34, 35, 47, 20, 21, -1, -1, -1,
+ 53, -1, 53, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 20, 21, 42, -1, -1,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 20, 21, 42, -1, -1,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 20, 21, 42, -1, -1,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 20, 21, 42, -1, -1,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 20, 21, 42, -1, -1,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, 21, 42, -1, 24,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, 21, 42, -1, 24,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, 21, 42, -1, 24,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, 21, 42, -1, 24,
+ -1, -1, 47, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, -1, -1, 42, 21, 22,
+ -1, -1, 47, -1, -1, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, -1, -1, 42,
+ 21, 22, -1, -1, 47, -1, -1, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ 21, 42, -1, -1, -1, -1, 47, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
+ -1, 42, -1, -1, 22, -1, 47, 25, 26, 27,
+ 28, 29, 28, 29, -1, 31, 32, 33, 34, 35,
+ 38, 28, 29, -1, 31, 32, 33, 34, 35, 47,
+ 25, 26, 27, 28, 29, 28, 29, 53, 31, 32,
+ 33, 34, 35, 38, -1, -1, 53, 40, 41, -1,
+ -1, -1, 47, -1, 47, -1, -1, 50, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ -1, -1, 42, -1, -1, 28, 29, 47, 31, 32,
+ 33, 34, 35, -1, 35, -1, -1, 40, 41, 40,
+ 41, -1, -1, -1, 47, -1, 47, -1, -1, -1,
+ -1, -1, 53, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 20, -1, 42, -1, -1, -1, -1, 47,
+ 28, 29, 22, 31, 32, 33, 34, 35, 28, 29,
+ -1, 31, 32, 33, 34, 35
+};
+/* -*-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 245 "eval.y"
+{;
+ break;}
+case 4:
+#line 247 "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 253 "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 259 "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 265 "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 270 "eval.y"
+{ fferrok; ;
+ break;}
+case 9:
+#line 274 "eval.y"
+{ ffval.Node = New_Vector( ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 10:
+#line 276 "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 289 "eval.y"
+{ ffval.Node = New_Vector( ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 12:
+#line 291 "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 304 "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 315 "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 329 "eval.y"
+{ ffval.Node = Close_Vec( ffvsp[-1].Node ); TEST(ffval.Node); ;
+ break;}
+case 16:
+#line 333 "eval.y"
+{ ffval.Node = Close_Vec( ffvsp[-1].Node ); TEST(ffval.Node); ;
+ break;}
+case 17:
+#line 337 "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 341 "eval.y"
+{ ffval.Node = New_Column( ffvsp[0].lng ); TEST(ffval.Node); ;
+ break;}
+case 19:
+#line 343 "eval.y"
+{
+ if( TYPE(ffvsp[-1].Node) != LONG
+ || OPER(ffvsp[-1].Node) != 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 352 "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 355 "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 358 "eval.y"
+{
+ if (SIZE(ffvsp[-2].Node)+SIZE(ffvsp[0].Node) >= MAX_STRLEN) {
+ fferror("Combined bit string size exceeds " MAX_STRLEN_S " bits");
+ FFERROR;
+ }
+ 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 367 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-3].Node, 1, ffvsp[-1].Node, 0, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 24:
+#line 369 "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 371 "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 373 "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 375 "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 377 "eval.y"
+{ ffval.Node = New_Unary( BITSTR, NOT, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 29:
+#line 380 "eval.y"
+{ ffval.Node = ffvsp[-1].Node; ;
+ break;}
+case 30:
+#line 384 "eval.y"
+{ ffval.Node = New_Const( LONG, &(ffvsp[0].lng), sizeof(long) ); TEST(ffval.Node); ;
+ break;}
+case 31:
+#line 386 "eval.y"
+{ ffval.Node = New_Const( DOUBLE, &(ffvsp[0].dbl), sizeof(double) ); TEST(ffval.Node); ;
+ break;}
+case 32:
+#line 388 "eval.y"
+{ ffval.Node = New_Column( ffvsp[0].lng ); TEST(ffval.Node); ;
+ break;}
+case 33:
+#line 390 "eval.y"
+{
+ if( TYPE(ffvsp[-1].Node) != LONG
+ || OPER(ffvsp[-1].Node) != 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 399 "eval.y"
+{ ffval.Node = New_Func( LONG, row_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); ;
+ break;}
+case 35:
+#line 401 "eval.y"
+{ ffval.Node = New_Func( LONG, null_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); ;
+ break;}
+case 36:
+#line 403 "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 406 "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 409 "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 412 "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 415 "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 418 "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 421 "eval.y"
+{ ffval.Node = ffvsp[0].Node; ;
+ break;}
+case 43:
+#line 423 "eval.y"
+{ ffval.Node = New_Unary( TYPE(ffvsp[0].Node), UMINUS, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 44:
+#line 425 "eval.y"
+{ ffval.Node = ffvsp[-1].Node; ;
+ break;}
+case 45:
+#line 427 "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 431 "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 435 "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 454 "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 473 "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 492 "eval.y"
+{ if (FSTRCMP(ffvsp[-1].str,"RANDOM(") == 0) { /* Scalar RANDOM() */
+ srand( (unsigned int) time(NULL) );
+ ffval.Node = New_Func( DOUBLE, rnd_fct, 0, 0, 0, 0, 0, 0, 0, 0 );
+ } else if (FSTRCMP(ffvsp[-1].str,"RANDOMN(") == 0) {/*Scalar RANDOMN()*/
+ srand( (unsigned int) time(NULL) );
+ ffval.Node = New_Func( DOUBLE, gasrnd_fct, 0, 0, 0, 0, 0, 0, 0, 0 );
+ } else {
+ fferror("Function() not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 51:
+#line 505 "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 519 "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 531 "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 );
+ /* Note: $2 is a vector so the result can never
+ be a constant. Therefore it will never be set
+ inside New_Func(), and it is safe to set SIZE() */
+ 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 );
+ /* Note: $2 is a vector so the result can never
+ be a constant. Therefore it will never be set
+ inside New_Func(), and it is safe to set SIZE() */
+ SIZE(ffval.Node) = 1;
+ } else {
+ fferror("Function(bits) not supported");
+ FFERROR;
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 54:
+#line 562 "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 if (FSTRCMP(ffvsp[-2].str,"RANDOM(") == 0) { /* Vector RANDOM() */
+ srand( (unsigned int) time(NULL) );
+ ffval.Node = New_Func( 0, rnd_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ TYPE(ffval.Node) = DOUBLE;
+ } else if (FSTRCMP(ffvsp[-2].str,"RANDOMN(") == 0) {
+ srand( (unsigned int) time(NULL) ); /* Vector RANDOMN() */
+ ffval.Node = New_Func( 0, gasrnd_fct, 1, ffvsp[-1].Node, 0, 0, 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ TYPE(ffval.Node) = DOUBLE;
+ }
+ 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,"ROUND(") == 0)
+ ffval.Node = New_Func( 0, round_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 if (FSTRCMP(ffvsp[-2].str,"RANDOMP(") == 0) {
+ srand( (unsigned int) time(NULL) );
+ ffval.Node = New_Func( 0, poirnd_fct, 1, ffvsp[-1].Node,
+ 0, 0, 0, 0, 0, 0 );
+ TYPE(ffval.Node) = LONG;
+ } else {
+ fferror("Function(expr) not supported");
+ FFERROR;
+ }
+ }
+ TEST(ffval.Node);
+ ;
+ break;}
+case 55:
+#line 660 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-4].str,"STRSTR(") == 0) {
+ ffval.Node = New_Func( LONG, strpos_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+ }
+ ;
+ break;}
+case 56:
+#line 668 "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;
+ }
+#if 0
+ } else if (FSTRCMP(ffvsp[-4].str,"STRSTR(") == 0) {
+ if( TYPE(ffvsp[-3].Node) != STRING || TYPE(ffvsp[-1].Node) != STRING) {
+ fferror("Arguments to strstr(s,r) must be strings");
+ FFERROR;
+ }
+ ffval.Node = New_Func( LONG, strpos_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0,
+ 0, 0, 0, 0 );
+ TEST(ffval.Node);
+#endif
+ } else {
+ fferror("Function(expr,expr) not supported");
+ FFERROR;
+ }
+ ;
+ break;}
+case 57:
+#line 730 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-8].str,"ANGSEP(") == 0) {
+ 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( Test_Dims( ffvsp[-7].Node, ffvsp[-5].Node ) && Test_Dims( ffvsp[-5].Node, ffvsp[-3].Node ) &&
+ Test_Dims( ffvsp[-3].Node, ffvsp[-1].Node ) ) {
+ ffval.Node = New_Func( 0, angsep_fct, 4, ffvsp[-7].Node, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].Node,0,0,0 );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-7].Node)<SIZE(ffvsp[-5].Node) ) Copy_Dims(ffval.Node, ffvsp[-5].Node);
+ if( SIZE(ffvsp[-5].Node)<SIZE(ffvsp[-3].Node) ) Copy_Dims(ffval.Node, ffvsp[-3].Node);
+ if( SIZE(ffvsp[-3].Node)<SIZE(ffvsp[-1].Node) ) Copy_Dims(ffval.Node, ffvsp[-1].Node);
+ } else {
+ fferror("Dimensions of ANGSEP arguments "
+ "are not compatible");
+ FFERROR;
+ }
+ } else {
+ fferror("Function(expr,expr,expr,expr) not supported");
+ FFERROR;
+ }
+ ;
+ break;}
+case 58:
+#line 754 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-3].Node, 1, ffvsp[-1].Node, 0, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 59:
+#line 756 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-5].Node, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 60:
+#line 758 "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 61:
+#line 760 "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 62:
+#line 762 "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 63:
+#line 764 "eval.y"
+{ ffval.Node = New_Unary( LONG, INTCAST, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 64:
+#line 766 "eval.y"
+{ ffval.Node = New_Unary( LONG, INTCAST, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 65:
+#line 768 "eval.y"
+{ ffval.Node = New_Unary( DOUBLE, FLTCAST, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 66:
+#line 770 "eval.y"
+{ ffval.Node = New_Unary( DOUBLE, FLTCAST, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 67:
+#line 774 "eval.y"
+{ ffval.Node = New_Const( BOOLEAN, &(ffvsp[0].log), sizeof(char) ); TEST(ffval.Node); ;
+ break;}
+case 68:
+#line 776 "eval.y"
+{ ffval.Node = New_Column( ffvsp[0].lng ); TEST(ffval.Node); ;
+ break;}
+case 69:
+#line 778 "eval.y"
+{
+ if( TYPE(ffvsp[-1].Node) != LONG
+ || OPER(ffvsp[-1].Node) != 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 70:
+#line 787 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, EQ, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 71:
+#line 790 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, NE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 72:
+#line 793 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LT, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 73:
+#line 796 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LTE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 74:
+#line 799 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GT, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 75:
+#line 802 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GTE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 76:
+#line 805 "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 77:
+#line 808 "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 78:
+#line 811 "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 79:
+#line 814 "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 80:
+#line 817 "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 81:
+#line 820 "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 82:
+#line 823 "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 83:
+#line 826 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, EQ, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 84:
+#line 829 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, NE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 85:
+#line 832 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GT, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 86:
+#line 835 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, GTE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 87:
+#line 838 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LT, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 88:
+#line 841 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, LTE, ffvsp[0].Node ); TEST(ffval.Node);
+ SIZE(ffval.Node) = 1; ;
+ break;}
+case 89:
+#line 844 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, AND, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 90:
+#line 846 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, OR, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 91:
+#line 848 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, EQ, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 92:
+#line 850 "eval.y"
+{ ffval.Node = New_BinOp( BOOLEAN, ffvsp[-2].Node, NE, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 93:
+#line 853 "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 94:
+#line 860 "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 95:
+#line 877 "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 96:
+#line 890 "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 97:
+#line 903 "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 98:
+#line 914 "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 99:
+#line 930 "eval.y"
+{
+ 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( ! (Test_Dims( ffvsp[-5].Node, ffvsp[-3].Node ) && Test_Dims( ffvsp[-3].Node, ffvsp[-1].Node ) ) ) {
+ fferror("Dimensions of NEAR arguments "
+ "are not compatible");
+ FFERROR;
+ } else {
+ 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);
+
+ if( SIZE(ffval.Node)<SIZE(ffvsp[-5].Node) ) Copy_Dims(ffval.Node, ffvsp[-5].Node);
+ if( SIZE(ffvsp[-5].Node)<SIZE(ffvsp[-3].Node) ) Copy_Dims(ffval.Node, ffvsp[-3].Node);
+ if( SIZE(ffvsp[-3].Node)<SIZE(ffvsp[-1].Node) ) Copy_Dims(ffval.Node, ffvsp[-1].Node);
+ }
+ ;
+ break;}
+case 100:
+#line 954 "eval.y"
+{
+ 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( ! (Test_Dims( ffvsp[-9].Node, ffvsp[-7].Node ) && Test_Dims( ffvsp[-7].Node, ffvsp[-5].Node ) &&
+ Test_Dims( ffvsp[-5].Node, ffvsp[-3].Node ) && Test_Dims( ffvsp[-3].Node, ffvsp[-1].Node )) ) {
+ fferror("Dimensions of CIRCLE arguments "
+ "are not compatible");
+ FFERROR;
+ } else {
+ 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);
+ if( SIZE(ffval.Node)<SIZE(ffvsp[-9].Node) ) Copy_Dims(ffval.Node, ffvsp[-9].Node);
+ if( SIZE(ffvsp[-9].Node)<SIZE(ffvsp[-7].Node) ) Copy_Dims(ffval.Node, ffvsp[-7].Node);
+ if( SIZE(ffvsp[-7].Node)<SIZE(ffvsp[-5].Node) ) Copy_Dims(ffval.Node, ffvsp[-5].Node);
+ if( SIZE(ffvsp[-5].Node)<SIZE(ffvsp[-3].Node) ) Copy_Dims(ffval.Node, ffvsp[-3].Node);
+ if( SIZE(ffvsp[-3].Node)<SIZE(ffvsp[-1].Node) ) Copy_Dims(ffval.Node, ffvsp[-1].Node);
+ }
+ ;
+ break;}
+case 101:
+#line 982 "eval.y"
+{
+ 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( ! (Test_Dims( ffvsp[-13].Node, ffvsp[-11].Node ) && Test_Dims( ffvsp[-11].Node, ffvsp[-9].Node ) &&
+ Test_Dims( ffvsp[-9].Node, ffvsp[-7].Node ) && Test_Dims( ffvsp[-7].Node, ffvsp[-5].Node ) &&
+ Test_Dims(ffvsp[-5].Node,ffvsp[-3].Node ) && Test_Dims(ffvsp[-3].Node, ffvsp[-1].Node ) ) ) {
+ fferror("Dimensions of BOX or ELLIPSE arguments "
+ "are not compatible");
+ FFERROR;
+ } else {
+ 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);
+ if( SIZE(ffval.Node)<SIZE(ffvsp[-13].Node) ) Copy_Dims(ffval.Node, ffvsp[-13].Node);
+ if( SIZE(ffvsp[-13].Node)<SIZE(ffvsp[-11].Node) ) Copy_Dims(ffval.Node, ffvsp[-11].Node);
+ if( SIZE(ffvsp[-11].Node)<SIZE(ffvsp[-9].Node) ) Copy_Dims(ffval.Node, ffvsp[-9].Node);
+ if( SIZE(ffvsp[-9].Node)<SIZE(ffvsp[-7].Node) ) Copy_Dims(ffval.Node, ffvsp[-7].Node);
+ if( SIZE(ffvsp[-7].Node)<SIZE(ffvsp[-5].Node) ) Copy_Dims(ffval.Node, ffvsp[-5].Node);
+ if( SIZE(ffvsp[-5].Node)<SIZE(ffvsp[-3].Node) ) Copy_Dims(ffval.Node, ffvsp[-3].Node);
+ if( SIZE(ffvsp[-3].Node)<SIZE(ffvsp[-1].Node) ) Copy_Dims(ffval.Node, ffvsp[-1].Node);
+ }
+ ;
+ break;}
+case 102:
+#line 1019 "eval.y"
+{ /* Use defaults for all elements */
+ ffval.Node = New_GTI( "", -99, "*START*", "*STOP*" );
+ TEST(ffval.Node); ;
+ break;}
+case 103:
+#line 1023 "eval.y"
+{ /* Use defaults for all except filename */
+ ffval.Node = New_GTI( ffvsp[-1].str, -99, "*START*", "*STOP*" );
+ TEST(ffval.Node); ;
+ break;}
+case 104:
+#line 1027 "eval.y"
+{ ffval.Node = New_GTI( ffvsp[-3].str, ffvsp[-1].Node, "*START*", "*STOP*" );
+ TEST(ffval.Node); ;
+ break;}
+case 105:
+#line 1030 "eval.y"
+{ ffval.Node = New_GTI( ffvsp[-7].str, ffvsp[-5].Node, ffvsp[-3].str, ffvsp[-1].str );
+ TEST(ffval.Node); ;
+ break;}
+case 106:
+#line 1034 "eval.y"
+{ /* Use defaults for all except filename */
+ ffval.Node = New_REG( ffvsp[-1].str, -99, -99, "" );
+ TEST(ffval.Node); ;
+ break;}
+case 107:
+#line 1038 "eval.y"
+{ ffval.Node = New_REG( ffvsp[-5].str, ffvsp[-3].Node, ffvsp[-1].Node, "" );
+ TEST(ffval.Node); ;
+ break;}
+case 108:
+#line 1041 "eval.y"
+{ ffval.Node = New_REG( ffvsp[-7].str, ffvsp[-5].Node, ffvsp[-3].Node, ffvsp[-1].str );
+ TEST(ffval.Node); ;
+ break;}
+case 109:
+#line 1045 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-3].Node, 1, ffvsp[-1].Node, 0, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 110:
+#line 1047 "eval.y"
+{ ffval.Node = New_Deref( ffvsp[-5].Node, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0, 0, 0 ); TEST(ffval.Node); ;
+ break;}
+case 111:
+#line 1049 "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 112:
+#line 1051 "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 113:
+#line 1053 "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 114:
+#line 1055 "eval.y"
+{ ffval.Node = New_Unary( BOOLEAN, NOT, ffvsp[0].Node ); TEST(ffval.Node); ;
+ break;}
+case 115:
+#line 1057 "eval.y"
+{ ffval.Node = ffvsp[-1].Node; ;
+ break;}
+case 116:
+#line 1061 "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 117:
+#line 1064 "eval.y"
+{ ffval.Node = New_Column( ffvsp[0].lng ); TEST(ffval.Node); ;
+ break;}
+case 118:
+#line 1066 "eval.y"
+{
+ if( TYPE(ffvsp[-1].Node) != LONG
+ || OPER(ffvsp[-1].Node) != 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 119:
+#line 1075 "eval.y"
+{ ffval.Node = New_Func( STRING, null_fct, 0, 0, 0, 0, 0, 0, 0, 0 ); ;
+ break;}
+case 120:
+#line 1077 "eval.y"
+{ ffval.Node = ffvsp[-1].Node; ;
+ break;}
+case 121:
+#line 1079 "eval.y"
+{
+ if (SIZE(ffvsp[-2].Node)+SIZE(ffvsp[0].Node) >= MAX_STRLEN) {
+ fferror("Combined string size exceeds " MAX_STRLEN_S " characters");
+ FFERROR;
+ }
+ 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 122:
+#line 1088 "eval.y"
+{
+ int outSize;
+ if( SIZE(ffvsp[-4].Node)!=1 ) {
+ fferror("Cannot have a vector string column");
+ FFERROR;
+ }
+ /* Since the output can be calculated now, as a constant
+ scalar, we must precalculate the output size, in
+ order to avoid an overflow. */
+ outSize = SIZE(ffvsp[-2].Node);
+ if (SIZE(ffvsp[0].Node) > outSize) outSize = SIZE(ffvsp[0].Node);
+ ffval.Node = New_FuncSize( 0, ifthenelse_fct, 3, ffvsp[-2].Node, ffvsp[0].Node, ffvsp[-4].Node,
+ 0, 0, 0, 0, outSize);
+
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-2].Node)<SIZE(ffvsp[0].Node) ) Copy_Dims(ffval.Node, ffvsp[0].Node);
+ ;
+ break;}
+case 123:
+#line 1107 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-4].str,"DEFNULL(") == 0) {
+ int outSize;
+ /* Since the output can be calculated now, as a constant
+ scalar, we must precalculate the output size, in
+ order to avoid an overflow. */
+ outSize = SIZE(ffvsp[-3].Node);
+ if (SIZE(ffvsp[-1].Node) > outSize) outSize = SIZE(ffvsp[-1].Node);
+
+ ffval.Node = New_FuncSize( 0, defnull_fct, 2, ffvsp[-3].Node, ffvsp[-1].Node, 0,
+ 0, 0, 0, 0, outSize );
+ TEST(ffval.Node);
+ if( SIZE(ffvsp[-1].Node)>SIZE(ffvsp[-3].Node) ) SIZE(ffval.Node) = SIZE(ffvsp[-1].Node);
+ } else {
+ fferror("Function(string,string) not supported");
+ FFERROR;
+ }
+ ;
+ break;}
+case 124:
+#line 1126 "eval.y"
+{
+ if (FSTRCMP(ffvsp[-6].str,"STRMID(") == 0) {
+ int len;
+ if( TYPE(ffvsp[-3].Node) != LONG || SIZE(ffvsp[-3].Node) != 1 ||
+ TYPE(ffvsp[-1].Node) != LONG || SIZE(ffvsp[-1].Node) != 1) {
+ fferror("When using STRMID(S,P,N), P and N must be integers (and not vector columns)");
+ FFERROR;
+ }
+ if (OPER(ffvsp[-1].Node) == CONST_OP) {
+ /* Constant value: use that directly */
+ len = (gParse.Nodes[ffvsp[-1].Node].value.data.lng);
+ } else {
+ /* Variable value: use the maximum possible (from $2) */
+ len = SIZE(ffvsp[-5].Node);
+ }
+ if (len <= 0 || len >= MAX_STRLEN) {
+ fferror("STRMID(S,P,N), N must be 1-" MAX_STRLEN_S);
+ FFERROR;
+ }
+ ffval.Node = New_FuncSize( 0, strmid_fct, 3, ffvsp[-5].Node, ffvsp[-3].Node,ffvsp[-1].Node,0,0,0,0,len);
+ TEST(ffval.Node);
+ } else {
+ fferror("Function(string,expr,expr) not supported");
+ FFERROR;
+ }
+ ;
+ 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 1155 "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 )
+{
+ return New_FuncSize(returnType, Op, nNodes,
+ Node1, Node2, Node3, Node4,
+ Node5, Node6, Node7, 0);
+}
+
+static int New_FuncSize( int returnType, funcOp Op, int nNodes,
+ int Node1, int Node2, int Node3, int Node4,
+ int Node5, int Node6, int Node7, int Size )
+/* 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 */
+ if (Op == poirnd_fct) constant = 0; /* Nor is Poisson deviate */
+
+ while( i-- )
+ constant = ( constant && OPER(this->SubNodes[i]) == 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];
+ }
+ /* Force explicit size before evaluating */
+ if (Size > 0) this->value.nelem = Size;
+
+ 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( OPER(Node1)==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);
+
+ if( ! (Test_Dims( NodeX, NodeY ) ) ) {
+ fferror("Dimensions of REGFILTER arguments are not compatible");
+ 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;
+
+ Copy_Dims(n, NodeX);
+ if( SIZE(NodeX)<SIZE(NodeY) ) Copy_Dims(n, NodeY);
+
+ /* 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( OPER(NodeX)==CONST_OP && OPER(NodeY)==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( OPER(i) > 0 || OPER(i) == CONST_OP ) continue;
+
+ column = -OPER(i);
+ 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 = calloc(size+1, elem);
+
+ 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;
+ long 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 = (long) 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;
+ long 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 = (long) 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
+
+/*
+ * angsep_calc - compute angular separation between celestial coordinates
+ *
+ * This routine computes the angular separation between to coordinates
+ * on the celestial sphere (i.e. RA and Dec). Note that all units are
+ * in DEGREES, unlike the other trig functions in the calculator.
+ *
+ * double ra1, dec1 - RA and Dec of the first position in degrees
+ * double ra2, dec2 - RA and Dec of the second position in degrees
+ *
+ * RETURNS: (double) angular separation in degrees
+ *
+ */
+double angsep_calc(double ra1, double dec1, double ra2, double dec2)
+{
+ double cd;
+ static double deg = 0;
+ double a, sdec, sra;
+
+ if (deg == 0) deg = ((double)4)*atan((double)1)/((double)180);
+ /* deg = 1.0; **** UNCOMMENT IF YOU WANT RADIANS */
+
+
+
+/*
+This (commented out) algorithm uses the Low of Cosines, which becomes
+ unstable for angles less than 0.1 arcsec.
+
+ cd = sin(dec1*deg)*sin(dec2*deg)
+ + cos(dec1*deg)*cos(dec2*deg)*cos((ra1-ra2)*deg);
+ if (cd < (-1)) cd = -1;
+ if (cd > (+1)) cd = +1;
+ return acos(cd)/deg;
+*/
+
+ /* The algorithm is the law of Haversines. This algorithm is
+ stable even when the points are close together. The normal
+ Law of Cosines fails for angles around 0.1 arcsec. */
+
+ sra = sin( (ra2 - ra1)*deg / 2 );
+ sdec = sin( (dec2 - dec1)*deg / 2);
+ a = sdec*sdec + cos(dec1*deg)*cos(dec2*deg)*sra*sra;
+
+ /* Sanity checking to avoid a range error in the sqrt()'s below */
+ if (a < 0) { a = 0; }
+ if (a > 1) { a = 1; }
+
+ return 2.0*atan2(sqrt(a), sqrt(1.0 - a)) / deg;
+}
+
+
+
+
+
+
+static double ran1()
+{
+ static double dval = 0.0;
+ double rndVal;
+
+ if (dval == 0.0) {
+ if( rand()<32768 && rand()<32768 )
+ dval = 32768.0;
+ else
+ dval = 2147483648.0;
+ }
+
+ rndVal = (double)rand();
+ while( rndVal > dval ) dval *= 2.0;
+ return rndVal/dval;
+}
+
+/* Gaussian deviate routine from Numerical Recipes */
+static double gasdev()
+{
+ static int iset = 0;
+ static double gset;
+ double fac, rsq, v1, v2;
+
+ if (iset == 0) {
+ do {
+ v1 = 2.0*ran1()-1.0;
+ v2 = 2.0*ran1()-1.0;
+ rsq = v1*v1 + v2*v2;
+ } while (rsq >= 1.0 || rsq == 0.0);
+ fac = sqrt(-2.0*log(rsq)/rsq);
+ gset = v1*fac;
+ iset = 1;
+ return v2*fac;
+ } else {
+ iset = 0;
+ return gset;
+ }
+
+}
+
+/* lgamma function - from Numerical Recipes */
+
+float gammaln(float xx)
+ /* Returns the value ln Gamma[(xx)] for xx > 0. */
+{
+ /*
+ Internal arithmetic will be done in double precision, a nicety
+ that you can omit if five-figure accuracy is good enough. */
+ double x,y,tmp,ser;
+ static double cof[6]={76.18009172947146,-86.50532032941677,
+ 24.01409824083091,-1.231739572450155,
+ 0.1208650973866179e-2,-0.5395239384953e-5};
+ int j;
+ y=x=xx;
+ tmp=x+5.5;
+ tmp -= (x+0.5)*log(tmp);
+ ser=1.000000000190015;
+ for (j=0;j<=5;j++) ser += cof[j]/++y;
+ return (float) -tmp+log(2.5066282746310005*ser/x);
+}
+
+/* Poisson deviate - derived from Numerical Recipes */
+static long poidev(double xm)
+{
+ static double sq, alxm, g, oldm = -1.0;
+ static double pi = 0;
+ double em, t, y;
+
+ if (pi == 0) pi = ((double)4)*atan((double)1);
+
+ if (xm < 20.0) {
+ if (xm != oldm) {
+ oldm = xm;
+ g = exp(-xm);
+ }
+ em = -1;
+ t = 1.0;
+ do {
+ em += 1;
+ t *= ran1();
+ } while (t > g);
+ } else {
+ if (xm != oldm) {
+ oldm = xm;
+ sq = sqrt(2.0*xm);
+ alxm = log(xm);
+ g = xm*alxm-gammaln( (float) (xm+1.0));
+ }
+ do {
+ do {
+ y = tan(pi*ran1());
+ em = sq*y+xm;
+ } while (em < 0.0);
+ em = floor(em);
+ t = 0.9*(1.0+y*y)*exp(em*alxm-gammaln( (float) (em+1.0) )-g);
+ } while (ran1() > t);
+ }
+
+ /* Return integer version */
+ return (long int) floor(em+0.5);
+}
+
+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;
+
+ 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 */
+ /* Random numbers are *never* constant !! */
+ if( this->operation == poirnd_fct ) allConst = 0;
+ if( this->operation == gasrnd_fct ) allConst = 0;
+ if( this->operation == rnd_fct ) allConst = 0;
+
+ 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 poirnd_fct:
+ if( theParams[0]->type==DOUBLE )
+ this->value.data.lng = poidev(pVals[0].data.dbl);
+ else
+ this->value.data.lng = poidev(pVals[0].data.lng);
+ 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;
+
+ /* Four-argument ANGSEP function */
+ case angsep_fct:
+ this->value.data.dbl =
+ angsep_calc(pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].data.dbl);
+
+ /* 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... scalar or vector 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;
+
+ /* String functions */
+ case strmid_fct:
+ cstrmid(this->value.data.str, this->value.nelem,
+ pVals[0].data.str, pVals[0].nelem,
+ pVals[1].data.lng);
+ break;
+ case strpos_fct:
+ {
+ char *res = strstr(pVals[0].data.str, pVals[1].data.str);
+ if (res == NULL) {
+ this->value.data.lng = 0;
+ } else {
+ this->value.data.lng = (res - pVals[0].data.str) + 1;
+ }
+ 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:
+ while( elem-- ) {
+ this->value.data.dblptr[elem] = ran1();
+ this->value.undef[elem] = 0;
+ }
+ break;
+
+ case gasrnd_fct:
+ while( elem-- ) {
+ this->value.data.dblptr[elem] = gasdev();
+ this->value.undef[elem] = 0;
+ }
+ break;
+
+ case poirnd_fct:
+ if( theParams[0]->type==DOUBLE ) {
+ if (theParams[0]->operation == CONST_OP) {
+ while( elem-- ) {
+ this->value.undef[elem] = (pVals[0].data.dbl < 0);
+ if (! this->value.undef[elem]) {
+ this->value.data.lngptr[elem] = poidev(pVals[0].data.dbl);
+ }
+ }
+ } else {
+ while( elem-- ) {
+ this->value.undef[elem] = theParams[0]->value.undef[elem];
+ if (theParams[0]->value.data.dblptr[elem] < 0)
+ this->value.undef[elem] = 1;
+ if (! this->value.undef[elem]) {
+ this->value.data.lngptr[elem] =
+ poidev(theParams[0]->value.data.dblptr[elem]);
+ }
+ } /* while */
+ } /* ! CONST_OP */
+ } else {
+ /* LONG */
+ if (theParams[0]->operation == CONST_OP) {
+ while( elem-- ) {
+ this->value.undef[elem] = (pVals[0].data.lng < 0);
+ if (! this->value.undef[elem]) {
+ this->value.data.lngptr[elem] = poidev(pVals[0].data.lng);
+ }
+ }
+ } else {
+ while( elem-- ) {
+ this->value.undef[elem] = theParams[0]->value.undef[elem];
+ if (theParams[0]->value.data.lngptr[elem] < 0)
+ this->value.undef[elem] = 1;
+ if (! this->value.undef[elem]) {
+ this->value.data.lngptr[elem] =
+ poidev(theParams[0]->value.data.lngptr[elem]);
+ }
+ } /* while */
+ } /* ! CONST_OP */
+ } /* END LONG */
+ 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;
+
+ /* Four-argument ANGSEP Function */
+
+ case angsep_fct:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=4; 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] ||
+ pNull[2] || pNull[3]) ) )
+ this->value.data.dblptr[elem] =
+ angsep_calc(pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl, pVals[3].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... scalar or vector dbls */
+
+ case near_fct:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=3; 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] ||
+ pNull[2]) ) )
+ this->value.data.logptr[elem] =
+ bnear( pVals[0].data.dbl, pVals[1].data.dbl,
+ pVals[2].data.dbl );
+ }
+ }
+ break;
+
+ case circle_fct:
+ while( row-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=5; 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] ||
+ pNull[2] || pNull[3] ||
+ pNull[4]) ) )
+ this->value.data.logptr[elem] =
+ 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-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=7; 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] ||
+ pNull[2] || pNull[3] ||
+ pNull[4] || pNull[5] ||
+ pNull[6] ) ) )
+ this->value.data.logptr[elem] =
+ 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-- ) {
+ nelem = this->value.nelem;
+ while( nelem-- ) {
+ elem--;
+ i=7; 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] ||
+ pNull[2] || pNull[3] ||
+ pNull[4] || pNull[5] ||
+ pNull[6] ) ) )
+ this->value.data.logptr[elem] =
+ 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;
+
+ /* String functions */
+ case strmid_fct:
+ {
+ int strconst = theParams[0]->operation == CONST_OP;
+ int posconst = theParams[1]->operation == CONST_OP;
+ int lenconst = theParams[2]->operation == CONST_OP;
+ int dest_len = this->value.nelem;
+ int src_len = theParams[0]->value.nelem;
+
+ while (row--) {
+ int pos;
+ int len;
+ char *str;
+ int undef = 0;
+
+ if (posconst) {
+ pos = theParams[1]->value.data.lng;
+ } else {
+ pos = theParams[1]->value.data.lngptr[row];
+ if (theParams[1]->value.undef[row]) undef = 1;
+ }
+ if (strconst) {
+ str = theParams[0]->value.data.str;
+ if (src_len == 0) src_len = strlen(str);
+ } else {
+ str = theParams[0]->value.data.strptr[row];
+ if (theParams[0]->value.undef[row]) undef = 1;
+ }
+ if (lenconst) {
+ len = dest_len;
+ } else {
+ len = theParams[2]->value.data.lngptr[row];
+ if (theParams[2]->value.undef[row]) undef = 1;
+ }
+ this->value.data.strptr[row][0] = '\0';
+ if (pos == 0) undef = 1;
+ if (! undef ) {
+ if (cstrmid(this->value.data.strptr[row], len,
+ str, src_len, pos) < 0) break;
+ }
+ this->value.undef[row] = undef;
+ }
+ }
+ break;
+
+ /* String functions */
+ case strpos_fct:
+ {
+ int const1 = theParams[0]->operation == CONST_OP;
+ int const2 = theParams[1]->operation == CONST_OP;
+
+ while (row--) {
+ char *str1, *str2;
+ int undef = 0;
+
+ if (const1) {
+ str1 = theParams[0]->value.data.str;
+ } else {
+ str1 = theParams[0]->value.data.strptr[row];
+ if (theParams[0]->value.undef[row]) undef = 1;
+ }
+ if (const2) {
+ str2 = theParams[1]->value.data.str;
+ } else {
+ str2 = theParams[1]->value.data.strptr[row];
+ if (theParams[1]->value.undef[row]) undef = 1;
+ }
+ this->value.data.lngptr[row] = 0;
+ if (! undef ) {
+ char *res = strstr(str1, str2);
+ if (res == NULL) {
+ undef = 1;
+ this->value.data.lngptr[row] = 0;
+ } else {
+ this->value.data.lngptr[row] = (res - str1) + 1;
+ }
+ }
+ this->value.undef[row] = undef;
+ }
+ }
+ break;
+
+
+ } /* End switch(this->operation) */
+ } /* End if (!gParse.status) */
+ } /* End non-constant operations */
+
+ 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( OPER(this->SubNodes[node])>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 );
+}
+
+/*
+ * Extract substring
+ */
+int cstrmid(char *dest_str, int dest_len,
+ char *src_str, int src_len,
+ int pos)
+{
+ /* char fill_char = ' '; */
+ char fill_char = '\0';
+ if (src_len == 0) { src_len = strlen(src_str); } /* .. if constant */
+
+ /* Fill destination with blanks */
+ if (pos < 0) {
+ fferror("STRMID(S,P,N) P must be 0 or greater");
+ return -1;
+ }
+ if (pos > src_len || pos == 0) {
+ /* pos==0: blank string requested */
+ memset(dest_str, fill_char, dest_len);
+ } else if (pos+dest_len > src_len) {
+ /* Copy a subset */
+ int nsub = src_len-pos+1;
+ int npad = dest_len - nsub;
+ memcpy(dest_str, src_str+pos-1, nsub);
+ /* Fill remaining string with blanks */
+ memset(dest_str+nsub, fill_char, npad);
+ } else {
+ /* Full string copy */
+ memcpy(dest_str, src_str+pos-1, dest_len);
+ }
+ dest_str[dest_len] = '\0'; /* Null-terminate */
+
+ 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/vendor/cfitsio/f77.inc b/vendor/cfitsio/f77.inc
new file mode 100644
index 00000000..51e05e49
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/f77_wrap.h b/vendor/cfitsio/f77_wrap.h
new file mode 100644
index 00000000..d512855b
--- /dev/null
+++ b/vendor/cfitsio/f77_wrap.h
@@ -0,0 +1,288 @@
+#define UNSIGNED_BYTE
+
+#include "cfortran.h"
+
+/************************************************************************
+ Some platforms creates longs as 8-byte integers. On other machines, ints
+ and longs are both 4-bytes, so both are compatible with Fortrans
+ default integer which is 4-bytes. To support 8-byte longs, 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__)) \
+ || defined(__ia64__) \
+ || defined (__sparcv9) || (defined(__sparc__) && defined(__arch64__)) \
+ || defined (__x86_64__) \
+ || defined (_SX) \
+ || defined (__powerpc64__)\
+ || defined (__s390x__)
+
+#define LONG8BYTES_INT4BYTES
+
+#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,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) \
+ }
+
diff --git a/vendor/cfitsio/f77_wrap1.c b/vendor/cfitsio/f77_wrap1.c
new file mode 100644
index 00000000..db7001b3
--- /dev/null
+++ b/vendor/cfitsio/f77_wrap1.c
@@ -0,0 +1,345 @@
+/************************************************************************
+
+ f77_wrap1.c and f77_wrap2.c have now been split into 4 files to
+ prevent compile-time memory errors (from expansion of compiler commands).
+ f77_wrap1.c was split into f77_wrap1.c and f77_wrap3.c, and
+ f77_wrap2.c was split into f77_wrap2.c and f77_wrap4.c:
+
+ f77_wrap1.c contains routines operating on whole files and some
+ utility routines.
+
+ f77_wrap2.c contains routines operating on primary array, image,
+ or column elements.
+
+ f77_wrap3.c contains routines operating on headers & keywords.
+
+ f77_wrap4.c contains miscellaneous routines.
+
+ Peter's original comments:
+
+ 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 )
+ /* 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 );
+}
+
+
+fitsfile* CUnit2FITS(int unit)
+{
+ if( unit<1 || unit>=MAXFITSFILES )
+ return(0);
+
+ return(gFitsFiles[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(ffexist,FTEXIST,ftexist,STRING,PINT,PINT)
+FCALLSCSUB3(ffextn,FTEXTN,ftextn,STRING,PINT,PINT)
+FCALLSCSUB7(ffrwrg,FTRWRG,ftrwrg,STRING,LONG,INT,PINT,PLONG,PLONG,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 Cffdkopn( fitsfile **fptr, const char *filename, int iomode, int *blocksize, int *status );
+void Cffdkopn( fitsfile **fptr, const char *filename, int iomode, int *blocksize, int *status )
+{
+ int hdutype;
+
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ ffdkopn( fptr, filename, iomode, status );
+ ffmahd( *fptr, 1, &hdutype, status );
+ *blocksize = 1;
+ } else {
+ *status = FILE_NOT_OPENED;
+ ffpmsg("Cffdkopn tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB5(Cffdkopn,FTDKOPN,ftdkopn,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 Cffdopn( fitsfile **fptr, const char *filename, int iomode, int *status );
+void Cffdopn( fitsfile **fptr, const char *filename, int iomode, int *status )
+{
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ ffdopn( fptr, filename, iomode, status );
+ } else {
+ *status = FILE_NOT_OPENED;
+ ffpmsg("Cffdopn tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB4(Cffdopn,FTDOPN,ftdopn,PFITSUNIT,STRING,INT,PINT)
+
+void Cfftopn( fitsfile **fptr, const char *filename, int iomode, int *status );
+void Cfftopn( fitsfile **fptr, const char *filename, int iomode, int *status )
+{
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ fftopn( fptr, filename, iomode, status );
+ } else {
+ *status = FILE_NOT_OPENED;
+ ffpmsg("Cfftopn tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB4(Cfftopn,FTTOPN,fttopn,PFITSUNIT,STRING,INT,PINT)
+
+void Cffiopn( fitsfile **fptr, const char *filename, int iomode, int *status );
+void Cffiopn( fitsfile **fptr, const char *filename, int iomode, int *status )
+{
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ ffiopn( fptr, filename, iomode, status );
+ } else {
+ *status = FILE_NOT_OPENED;
+ ffpmsg("Cffiopn tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB4(Cffiopn,FTIOPN,ftiopn,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 Cffdkinit( fitsfile **fptr, const char *filename, int blocksize, int *status );
+void Cffdkinit( fitsfile **fptr, const char *filename, int blocksize, int *status )
+{
+ if( *fptr==NULL || *fptr==(fitsfile*)1 ) {
+ ffdkinit( fptr, filename, status );
+ } else {
+ *status = FILE_NOT_CREATED;
+ ffpmsg("Cffdkinit tried to use an already opened unit.");
+ }
+}
+FCALLSCSUB4(Cffdkinit,FTDKINIT,ftdkinit,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)
+FCALLSCSUB3(ffflsh,FTFLSH,ftflsh,FITSUNIT, INT, 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)
+FCALLSCSUB0(ffpmrk,FTPMRK,ftpmrk)
+FCALLSCSUB0(ffcmrk,FTCMRK,ftcmrk)
+
+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)
+
diff --git a/vendor/cfitsio/f77_wrap2.c b/vendor/cfitsio/f77_wrap2.c
new file mode 100644
index 00000000..8b7de365
--- /dev/null
+++ b/vendor/cfitsio/f77_wrap2.c
@@ -0,0 +1,711 @@
+/************************************************************************
+
+ f77_wrap1.c and f77_wrap2.c have now been split into 4 files to
+ prevent compile-time memory errors (from expansion of compiler commands).
+ f77_wrap1.c was split into f77_wrap1.c and f77_wrap3.c, and
+ f77_wrap2.c was split into f77_wrap2.c and f77_wrap4.c:
+
+ f77_wrap1.c contains routines operating on whole files and some
+ utility routines.
+
+ f77_wrap2.c contains routines operating on primary array, image,
+ or column elements.
+
+ f77_wrap3.c contains routines operating on headers & keywords.
+
+ f77_wrap4.c contains miscellaneous routines.
+
+ Peter's original comments:
+
+ 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"
+
+
+FCALLSCSUB5(ffgextn,FTGEXTN,ftgextn,FITSUNIT,LONG,LONG,BYTEV,PINT)
+FCALLSCSUB5(ffpextn,FTPEXTN,ftpextn,FITSUNIT,LONG,LONG,BYTEV,PINT)
+
+/*------------ 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(ffgpvjj,FTGPVK,ftgpvk,FITSUNIT,LONG,LONG,LONG,LONGLONG,LONGLONGV,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(ffgpfjj,FTGPFK,ftgpfk,FITSUNIT,LONG,LONG,LONG,LONGLONGV,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(ffg2djj,FTG2DK,ftg2dk,FITSUNIT,LONG,LONGLONG,LONG,LONG,LONG,LONGLONGV,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(ffg3djj,FTG3DK,ftg3dk,FITSUNIT,LONG,LONGLONG,LONG,LONG,LONG,LONG,LONG,LONGLONGV,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(ffgsvjj,FTGSVK,ftgsvk,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,LONGLONG,LONGLONGV,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 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 Cffgsfjj( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, LONGLONG *array, int *flagval, int *anynul, int *status );
+void Cffgsfjj( fitsfile *fptr, int colnum, int naxis, long *naxes, long *blc, long *trc, long *inc, LONGLONG *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 );
+ ffgsfjj( 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(Cffgsfjj,FTGSFK,ftgsfk,FITSUNIT,INT,INT,LONGV,LONGV,LONGV,LONGV,LONGLONGV,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(ffggpjj,FTGGPK,ftggpk,FITSUNIT,LONG,LONG,LONG,LONGLONGV,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 ftgcvsll_STRV_A7 NUM_ELEMS(velem)
+CFextern VOID_cfF(FTGCVSLL,ftgcvsll)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,LONGLONG,LONGLONG,LONG,STRING,PSTRINGV,PLOGICAL,PINT,CF_0,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGCVSLL,ftgcvsll)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,LONGLONG,LONGLONG,LONG,STRING,PSTRINGV,PLOGICAL,PINT,CF_0,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(INT,2)
+ QCF(LONGLONG,3)
+ QCF(LONGLONG,4)
+ QCF(LONG,5)
+ QCF(STRING,6)
+ QCF(PSTRINGV,7)
+ QCF(PLOGICAL,8)
+ QCF(PINT,9)
+
+ fitsfile *fptr;
+ int colnum, *anynul, *status, velem, type;
+ LONGLONG firstrow, firstelem;
+ long nelem;
+ long repeat;
+ unsigned long gMinStrLen=80L; /* gMin = width */
+ char *nulval, **array;
+
+ fptr = TCF(ftgcvsll,FITSUNIT,1,0);
+ colnum = TCF(ftgcvsll,INT,2,0);
+ firstrow = TCF(ftgcvsll,LONGLONG,3,0);
+ firstelem = TCF(ftgcvsll,LONGLONG,4,0);
+ nelem = TCF(ftgcvsll,LONG,5,0);
+ nulval = TCF(ftgcvsll,STRING,6,0);
+ /* put off variable 7 (array) until column type is learned */
+ anynul = TCF(ftgcvsll,PLOGICAL,8,0);
+ status = TCF(ftgcvsll,PINT,9,0);
+
+ ffgtcl( fptr, colnum, &type, &repeat, (long *)&gMinStrLen, status );
+ if( type<0 ) velem = 1; /* Variable length column */
+ else velem = nelem;
+
+ array = TCF(ftgcvsll,PSTRINGV,7,0);
+
+ ffgcvs( fptr, colnum, firstrow, firstelem, nelem, nulval, array,
+ anynul, status );
+
+ RCF(FITSUNIT,1)
+ RCF(INT,2)
+ RCF(LONGLONG,3)
+ RCF(LONGLONG,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(ffgcvjj,FTGCVK,ftgcvk,FITSUNIT,INT,LONG,LONG,LONG,LONGLONG,LONGLONGV,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 ftgcvlll_LOGV_A7 A5
+FCALLSCSUB9(ffgcvl,FTGCVLLL,ftgcvlll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,LOGICAL,LOGICALV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvb,FTGCVBLL,ftgcvbll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,BYTE,BYTEV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvi,FTGCVILL,ftgcvill,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,SHORT,SHORTV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvk,FTGCVJLL,ftgcvjll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,INT,INTV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvjj,FTGCVKLL,ftgcvkll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,LONGLONG,LONGLONGV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcve,FTGCVELL,ftgcvell,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,FLOAT,FLOATV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvd,FTGCVDLL,ftgcvdll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,DOUBLE,DOUBLEV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvc,FTGCVCLL,ftgcvcll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,FLOAT,FLOATV,PLOGICAL,PINT)
+FCALLSCSUB9(ffgcvm,FTGCVMLL,ftgcvmll,FITSUNIT,INT,LONGLONG,LONGLONG,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(ffgcfjj,FTGCFK,ftgcfk,FITSUNIT,INT,LONG,LONG,LONG,LONGLONGV,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)
+
+
+#define ftgcfbll_LOGV_A7 A5
+FCALLSCSUB9(ffgcfb,FTGCFBLL,ftgcfbll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,BYTEV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfill_LOGV_A7 A5
+FCALLSCSUB9(ffgcfi,FTGCFILL,ftgcfill,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,SHORTV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfjll_LOGV_A7 A5
+FCALLSCSUB9(ffgcfk,FTGCFJLL,ftgcfjll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,INTV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfkll_LOGV_A7 A5
+FCALLSCSUB9(ffgcfjj,FTGCFKLL,ftgcfkll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,LONGLONGV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfell_LOGV_A7 A5
+FCALLSCSUB9(ffgcfe,FTGCFELL,ftgcfell,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,FLOATV,LOGICALV,PLOGICAL,PINT)
+
+#define ftgcfdll_LOGV_A7 A5
+FCALLSCSUB9(ffgcfd,FTGCFDLL,ftgcfdll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,DOUBLEV,LOGICALV,PLOGICAL,PINT)
+
+FCALLSCSUB6(ffgdes,FTGDES,ftgdes,FITSUNIT,INT,LONG,PLONG,PLONG,PINT)
+FCALLSCSUB6(ffgdesll,FTGDESLL,ftgdesll,FITSUNIT,INT,LONG,PLONGLONG,PLONGLONG,PINT)
+
+#define ftgdess_LONGV_A5 A4
+#define ftgdess_LONGV_A6 A4
+FCALLSCSUB7(ffgdess,FTGDESS,ftgdess,FITSUNIT,INT,LONG,LONG,LONGV,LONGV,PINT)
+#define ftgdessll_LONGV_A5 A4
+#define ftgdessll_LONGV_A6 A4FCALLSCSUB7(ffgdessll,FTGDESSLL,ftgdessll,FITSUNIT,INT,LONG,LONG,LONGLONGV,LONGLONGV,PINT)
+FCALLSCSUB7(ffgdessll,FTGDESSLL,ftgdessll,FITSUNIT,INT,LONG,LONG,LONGLONGV,LONGLONGV,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(ffpprjj,FTPPRK,ftpprk,FITSUNIT,LONG,LONG,LONG,LONGLONGV,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(ffppnjj,FTPPNK,ftppnk,FITSUNIT,LONG,LONG,LONG,LONGLONGV,LONGLONG,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(ffp2djj,FTP2DK,ftp2dk,FITSUNIT,LONG,LONG,LONG,LONG,LONGLONGV,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(ffp3djj,FTP3DK,ftp3dk,FITSUNIT,LONG,LONG,LONG,LONG,LONG,LONG,LONGLONGV,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(ffpssjj,FTPSSK,ftpssk,FITSUNIT,LONG,LONG,LONGV,LONGV,LONGV,LONGLONGV,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(ffpgpjj,FTPGPK,ftpgpk,FITSUNIT,LONG,LONG,LONG,LONGLONGV,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(ffpcljj,FTPCLK,ftpclk,FITSUNIT,INT,LONG,LONG,LONG,LONGLONGV,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)
+FCALLSCSUB4(ffprwu,FTPRWU,ftprwu,FITSUNIT,LONG,LONG,PINT)
+
+#define ftpclsll_STRV_A6 NUM_ELEM_ARG(5)
+FCALLSCSUB7(ffpcls,FTPCLSLL,ftpclsll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,STRINGV,PINT)
+
+#define ftpcllll_LOGV_A6 A5
+FCALLSCSUB7(ffpcll,FTPCLLLL,ftpcllll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,LOGICALV,PINT)
+FCALLSCSUB7(ffpclb,FTPCLBLL,ftpclbll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,BYTEV,PINT)
+FCALLSCSUB7(ffpcli,FTPCLILL,ftpclill,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,SHORTV,PINT)
+FCALLSCSUB7(ffpclk,FTPCLJLL,ftpcljll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,INTV,PINT)
+FCALLSCSUB7(ffpcljj,FTPCLKLL,ftpclkll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,LONGLONGV,PINT)
+FCALLSCSUB7(ffpcle,FTPCLELL,ftpclell,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,FLOATV,PINT)
+FCALLSCSUB7(ffpcld,FTPCLDLL,ftpcldll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,DOUBLEV,PINT)
+FCALLSCSUB7(ffpclc,FTPCLCLL,ftpclcll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,FLOATV,PINT)
+FCALLSCSUB7(ffpclm,FTPCLMLL,ftpclmll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,DOUBLEV,PINT)
+FCALLSCSUB6(ffpclu,FTPCLULL,ftpclull,FITSUNIT,INT,LONGLONG,LONGLONG,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(ffpcnjj,FTPCNK,ftpcnk,FITSUNIT,INT,LONG,LONG,LONG,LONGLONGV,LONGLONG,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)
+
+#define ftpcnsll_STRV_A6 NUM_ELEM_ARG(5)
+FCALLSCSUB8(ffpcns,FTPCNSLL,ftpcnsll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,STRINGV,STRING,PINT)
+
+FCALLSCSUB8(ffpcnb,FTPCNBLL,ftpcnbll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,BYTEV,BYTE,PINT)
+FCALLSCSUB8(ffpcni,FTPCNILL,ftpcnill,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,SHORTV,SHORT,PINT)
+FCALLSCSUB8(ffpcnk,FTPCNJLL,ftpcnjll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,INTV,INT,PINT)
+FCALLSCSUB8(ffpcnjj,FTPCNKLL,ftpcnkll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,LONGLONGV,LONGLONG,PINT)
+FCALLSCSUB8(ffpcne,FTPCNELL,ftpcnell,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,FLOATV,FLOAT,PINT)
+FCALLSCSUB8(ffpcnd,FTPCNDLL,ftpcndll,FITSUNIT,INT,LONGLONG,LONGLONG,LONG,DOUBLEV,DOUBLE,PINT)
+
+FCALLSCSUB6(ffpdes,FTPDES,ftpdes,FITSUNIT,INT,LONG,LONG,LONG,PINT)
+FCALLSCSUB6(ffpdes,FTPDESLL,ftpdesll,FITSUNIT,INT,LONG,LONGLONG,LONGLONG,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(ffirow,FTIROWLL,ftirowll,FITSUNIT,LONGLONG,LONGLONG,PINT)
+FCALLSCSUB4(ffdrow,FTDROW,ftdrow,FITSUNIT,LONG,LONG,PINT)
+FCALLSCSUB4(ffdrow,FTDROWLL,ftdrowll,FITSUNIT,LONGLONG,LONGLONG,PINT)
+FCALLSCSUB3(ffdrrg,FTDRRG,ftdrrg,FITSUNIT,STRING,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)
diff --git a/vendor/cfitsio/f77_wrap3.c b/vendor/cfitsio/f77_wrap3.c
new file mode 100644
index 00000000..e64ef279
--- /dev/null
+++ b/vendor/cfitsio/f77_wrap3.c
@@ -0,0 +1,853 @@
+/************************************************************************
+
+ f77_wrap1.c and f77_wrap2.c have now been split into 4 files to
+ prevent compile-time memory errors (from expansion of compiler commands).
+ f77_wrap1.c was split into f77_wrap1.c and f77_wrap3.c, and
+ f77_wrap2.c was split into f77_wrap2.c and f77_wrap4.c:
+
+ f77_wrap1.c contains routines operating on whole files and some
+ utility routines.
+
+ f77_wrap2.c contains routines operating on primary array, image,
+ or column elements.
+
+ f77_wrap3.c contains routines operating on headers & keywords.
+
+ f77_wrap4.c contains miscellaneous routines.
+
+ Peter's original comments:
+
+ 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"
+
+/*----------------- 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)
+FCALLSCSUB5(ffpkyj,FTPKYK,ftpkyk,FITSUNIT,STRING,LONGLONG,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 ftpknk_STRV_A6 NUM_ELEM_ARG(4)
+#define ftpknk_LONGLONGV_A5 A4
+FCALLSCSUB7(ffpknjj,FTPKNK,ftpknk,FITSUNIT,STRING,INT,INT,LONGLONGV,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 ftphext_LONGV_A5 A4
+FCALLSCSUB8(ffphext,FTPHEXT,ftphext,FITSUNIT,STRING,INT,INT,LONGV,LONG,LONG,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(ffgkyjj,FTGKYK,ftgkyk,FITSUNIT,STRING,PLONGLONG,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)
+
+#define ftgknk_LONGLONGV_A5 A4
+FCALLSCSUB7(ffgknjj,FTGKNK,ftgknk,FITSUNIT,STRING,INT,INT,LONGLONGV,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,10)
+ QCF(PINT,11)
+
+ fitsfile *fptr;
+ long tfields;
+ int maxdim,*status;
+
+ fptr = TCF(ftghtb,FITSUNIT,1,0);
+ status = TCF(ftghtb,PINT,11,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,10,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,10)
+ RCF(PINT,11)
+}
+
+#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,10)
+
+ fitsfile *fptr;
+ long tfields;
+ int maxdim,*status;
+
+ fptr = TCF(ftghbn,FITSUNIT,1,0);
+ status = TCF(ftghbn,PINT,10,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,10)
+}
+
+ /* LONGLONG version of the ftghbn routine: */
+
+#define ftghbnll_STRV_A5 NUM_ELEMS(maxdim)
+#define ftghbnll_STRV_A6 NUM_ELEMS(maxdim)
+#define ftghbnll_STRV_A7 NUM_ELEMS(maxdim)
+CFextern VOID_cfF(FTGHBNLL,ftghbnll)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,PLONGLONG,PINT,PSTRINGV,PSTRINGV,PSTRINGV,PSTRING,PLONGLONG,PINT,CF_0,CF_0,CF_0,CF_0));
+CFextern VOID_cfF(FTGHBNLL,ftghbnll)
+CFARGT14(NCF,DCF,ABSOFT_cf2(VOID),FITSUNIT,INT,PLONGLONG,PINT,PSTRINGV,PSTRINGV,PSTRINGV,PSTRING,PLONGLONG,PINT,CF_0,CF_0,CF_0,CF_0))
+{
+ QCF(FITSUNIT,1)
+ QCF(INT,2)
+ QCF(PLONGLONG,3)
+ QCF(PINT,4)
+ QCF(PSTRINGV,5)
+ QCF(PSTRINGV,6)
+ QCF(PSTRINGV,7)
+ QCF(PSTRING,8)
+ QCF(PLONGLONG,9)
+ QCF(PINT,10)
+
+ fitsfile *fptr;
+ LONGLONG tfields;
+ int maxdim,*status;
+
+ fptr = TCF(ftghbnll,FITSUNIT,1,0);
+ status = TCF(ftghbnll,PINT,10,0);
+ maxdim = TCF(ftghbnll,INT,2,0);
+ ffgkyjj( fptr, "TFIELDS", &tfields, 0, status );
+ maxdim = (maxdim<0) ? tfields : _cfMIN(tfields,maxdim);
+
+ ffghbnll( fptr, maxdim
+ TCF(ftghbnll,PLONGLONG,3,1)
+ TCF(ftghbnll,PINT,4,1)
+ TCF(ftghbnll,PSTRINGV,5,1)
+ TCF(ftghbnll,PSTRINGV,6,1)
+ TCF(ftghbnll,PSTRINGV,7,1)
+ TCF(ftghbnll,PSTRING,8,1)
+ TCF(ftghbnll,PLONGLONG,9,1)
+ , status );
+
+ RCF(FITSUNIT,1)
+ RCF(INT,2)
+ RCF(PLONGLONG,3)
+ RCF(PINT,4)
+ RCF(PSTRINGV,5)
+ RCF(PSTRINGV,6)
+ RCF(PSTRINGV,7)
+ RCF(PSTRING,8)
+ RCF(PLONGLONG,9)
+ RCF(PINT,10)
+}
+
+ /* 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(LONG8BYTES_INT4BYTES)
+
+ /* On platforms with 8-byte longs, 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 ftgprh_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,10)
+
+ fitsfile *fptr;
+ long tfields;
+ int *status;
+
+ fptr = TCF(ftgtbh,FITSUNIT,1,0);
+ status = TCF(ftgtbh,PINT,10,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,10)
+}
+
+#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)
+FCALLSCSUB5(ffukyj,FTUKYK,ftukyk,FITSUNIT,STRING,LONGLONG,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)
+FCALLSCSUB5(ffmkyj,FTMKYK,ftmkyk,FITSUNIT,STRING,LONGLONG,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)
+FCALLSCSUB3(ffikey,FTIKEY,ftkey,FITSUNIT,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)
+FCALLSCSUB5(ffikyj,FTIKYK,ftikyk,FITSUNIT,STRING,LONGLONG,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(ffgiet,FTGIET,ftgiet,FITSUNIT,PINT,PINT)
+FCALLSCSUB3(ffgidm,FTGIDM,ftgidm,FITSUNIT,PINT,PINT)
+
+#define ftgisz_LONGV_A3 A2
+FCALLSCSUB4(ffgisz,FTGISZ,ftgisz,FITSUNIT,INT,LONGV,PINT)
+
+#define ftgiszll_LONGLONGV_A3 A2
+FCALLSCSUB4(ffgiszll,FTGISZLL,ftgiszll,FITSUNIT,INT,LONGLONGV,PINT)
+
+#define ftgipr_LONGV_A5 A2
+FCALLSCSUB6(ffgipr,FTGIPR,ftgipr,FITSUNIT,INT,PINT,PINT,LONGV,PINT)
+
+#define ftgiprll_LONGLONGV_A5 A2
+FCALLSCSUB6(ffgiprll,FTGIPRLL,ftgiprll,FITSUNIT,INT,PINT,PINT,LONGLONGV,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 ftiimgll_LONGLONGV_A4 A3
+FCALLSCSUB5(ffiimgll,FTIIMGLL,ftiimgll,FITSUNIT,INT,INT,LONGLONGV,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 ftitabll_STRV_A5 NUM_ELEM_ARG(4)
+#define ftitabll_LONGV_A6 A4
+#define ftitabll_STRV_A7 NUM_ELEM_ARG(4)
+#define ftitabll_STRV_A8 NUM_ELEM_ARG(4)
+FCALLSCSUB10(ffitab,FTITABLL,ftitabll,FITSUNIT,LONGLONG,LONGLONG,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 ftibinll_STRV_A4 NUM_ELEM_ARG(3)
+#define ftibinll_STRV_A5 NUM_ELEM_ARG(3)
+#define ftibinll_STRV_A6 NUM_ELEM_ARG(3)
+FCALLSCSUB9(ffibin,FTIBINLL,ftibinll,FITSUNIT,LONGLONG,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)
+FCALLSCSUB6(ffcpfl,FTCPFL,ftcpfl,FITSUNIT,FITSUNIT,INT,INT,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)
+
+FCALLSCSUB6(fits_copy_image2cell,FTIM2CELL,ftim2cell,FITSUNIT,FITSUNIT,STRING,LONG,INT,PINT)
+FCALLSCSUB5(fits_copy_cell2image,FTCELL2IM,ftcell2im,FITSUNIT,FITSUNIT,STRING,LONG,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)
+FCALLSCSUB3(ffpnul,FTPNULLL,ftpnulll,FITSUNIT,LONGLONG,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(ffgnrwll,FTGNRWLL,ftgnrwll,FITSUNIT,PLONGLONG,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)
+FCALLSCSUB6(ffeqty,FTEQTY,fteqty,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/vendor/cfitsio/f77_wrap4.c b/vendor/cfitsio/f77_wrap4.c
new file mode 100644
index 00000000..92668c78
--- /dev/null
+++ b/vendor/cfitsio/f77_wrap4.c
@@ -0,0 +1,572 @@
+/************************************************************************
+
+ f77_wrap1.c and f77_wrap2.c have now been split into 4 files to
+ prevent compile-time memory errors (from expansion of compiler commands).
+ f77_wrap1.c was split into f77_wrap1.c and f77_wrap3.c, and
+ f77_wrap2.c was split into f77_wrap2.c and f77_wrap4.c:
+
+ f77_wrap1.c contains routines operating on whole files and some
+ utility routines.
+
+ f77_wrap2.c contains routines operating on primary array, image,
+ or column elements.
+
+ f77_wrap3.c contains routines operating on headers & keywords.
+
+ f77_wrap4.c contains miscellaneous routines.
+
+ Peter's original comments:
+
+ 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"
+
+/*********************************************************************/
+/* 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)
+FCALLSCSUB11(ffgicsa,FTGICSA,ftgicsa,FITSUNIT,BYTE,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(ffffrw,FTFFRW,ftffrw,FITSUNIT,STRING,PLONG,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/vendor/cfitsio/fits_hcompress.c b/vendor/cfitsio/fits_hcompress.c
new file mode 100644
index 00000000..96a6b126
--- /dev/null
+++ b/vendor/cfitsio/fits_hcompress.c
@@ -0,0 +1,1858 @@
+/* #########################################################################
+These routines to apply the H-compress compression algorithm to a 2-D Fits
+image were written by R. White at the STScI and were obtained from the STScI at
+http://www.stsci.edu/software/hcompress.html
+
+This source file is a concatination of the following sources files in the
+original distribution
+ htrans.c
+ digitize.c
+ encode.c
+ qwrite.c
+ doencode.c
+ bit_output.c
+ qtree_encode.c
+
+The following modifications have been made to the original code:
+
+ - commented out redundant "include" statements
+ - added the noutchar global variable
+ - changed all the 'extern' declarations to 'static', since all the routines are in
+ the same source file
+ - changed the first parameter in encode (and in lower level routines from a file stream
+ to a char array
+ - modifid the encode routine to return the size of the compressed array of bytes
+ - changed calls to printf and perror to call the CFITSIO ffpmsg routine
+ - modified the mywrite routine, and lower level byte writing routines, to copy
+ the output bytes to a char array, instead of writing them to a file stream
+ - replace "exit" statements with "return" statements
+ - changed the function declarations to the more modern ANSI C style
+
+ ############################################################################ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+static long noutchar;
+static long noutmax;
+
+static int htrans(int a[],int nx,int ny);
+static void digitize(int a[], int nx, int ny, int scale);
+static int encode(char *outfile, long *nlen, int a[], int nx, int ny, int scale);
+static void shuffle(int a[], int n, int n2, int tmp[]);
+
+static int htrans64(LONGLONG a[],int nx,int ny);
+static void digitize64(LONGLONG a[], int nx, int ny, int scale);
+static int encode64(char *outfile, long *nlen, LONGLONG a[], int nx, int ny, int scale);
+static void shuffle64(LONGLONG a[], int n, int n2, LONGLONG tmp[]);
+
+static void writeint(char *outfile, int a);
+static void writelonglong(char *outfile, LONGLONG a);
+static int doencode(char *outfile, int a[], int nx, int ny, unsigned char nbitplanes[3]);
+static int doencode64(char *outfile, LONGLONG a[], int nx, int ny, unsigned char nbitplanes[3]);
+static int qwrite(char *file, char buffer[], int n);
+
+static int qtree_encode(char *outfile, int a[], int n, int nqx, int nqy, int nbitplanes);
+static int qtree_encode64(char *outfile, LONGLONG a[], int n, int nqx, int nqy, int nbitplanes);
+static void start_outputing_bits(void);
+static void done_outputing_bits(char *outfile);
+static void output_nbits(char *outfile, int bits, int n);
+
+static void qtree_onebit(int a[], int n, int nx, int ny, unsigned char b[], int bit);
+static void qtree_onebit64(LONGLONG a[], int n, int nx, int ny, unsigned char b[], int bit);
+static void qtree_reduce(unsigned char a[], int n, int nx, int ny, unsigned char b[]);
+static int bufcopy(unsigned char a[], int n, unsigned char buffer[], int *b, int bmax);
+static void write_bdirect(char *outfile, int a[], int n,int nqx, int nqy, unsigned char scratch[], int bit);
+static void write_bdirect64(char *outfile, LONGLONG a[], int n,int nqx, int nqy, unsigned char scratch[], int bit);
+
+/* #define output_nybble(outfile,c) output_nbits(outfile,c,4) */
+static void output_nybble(char *outfile, int bits);
+static void output_nnybble(char *outfile, int n, unsigned char array[]);
+
+#define output_huffman(outfile,c) output_nbits(outfile,code[c],ncode[c])
+
+/* ---------------------------------------------------------------------- */
+int fits_hcompress(int *a, int ny, int nx, int scale, char *output,
+ long *nbytes, int *status)
+{
+ /*
+ compress the input image using the H-compress algorithm
+
+ a - input image array
+ nx - size of X axis of image
+ ny - size of Y axis of image
+ scale - quantization scale factor. Larger values results in more (lossy) compression
+ scale = 0 does lossless compression
+ output - pre-allocated array to hold the output compressed stream of bytes
+ nbyts - input value = size of the output buffer;
+ returned value = size of the compressed byte stream, in bytes
+
+ NOTE: the nx and ny dimensions as defined within this code are reversed from
+ the usual FITS notation. ny is the fastest varying dimension, which is
+ usually considered the X axis in the FITS image display
+
+ */
+
+ int stat;
+
+ if (*status > 0) return(*status);
+
+ /* H-transform */
+ stat = htrans(a, nx, ny);
+ if (stat) {
+ *status = stat;
+ return(*status);
+ }
+
+ /* digitize */
+ digitize(a, nx, ny, scale);
+
+ /* encode and write to output array */
+
+ FFLOCK;
+ noutmax = *nbytes; /* input value is the allocated size of the array */
+ *nbytes = 0; /* reset */
+
+ stat = encode(output, nbytes, a, nx, ny, scale);
+ FFUNLOCK;
+
+ *status = stat;
+ return(*status);
+}
+/* ---------------------------------------------------------------------- */
+int fits_hcompress64(LONGLONG *a, int ny, int nx, int scale, char *output,
+ long *nbytes, int *status)
+{
+ /*
+ compress the input image using the H-compress algorithm
+
+ a - input image array
+ nx - size of X axis of image
+ ny - size of Y axis of image
+ scale - quantization scale factor. Larger values results in more (lossy) compression
+ scale = 0 does lossless compression
+ output - pre-allocated array to hold the output compressed stream of bytes
+ nbyts - size of the compressed byte stream, in bytes
+
+ NOTE: the nx and ny dimensions as defined within this code are reversed from
+ the usual FITS notation. ny is the fastest varying dimension, which is
+ usually considered the X axis in the FITS image display
+
+ */
+
+ int stat;
+
+ if (*status > 0) return(*status);
+
+ /* H-transform */
+ stat = htrans64(a, nx, ny);
+ if (stat) {
+ *status = stat;
+ return(*status);
+ }
+
+ /* digitize */
+ digitize64(a, nx, ny, scale);
+
+ /* encode and write to output array */
+
+ FFLOCK;
+ noutmax = *nbytes; /* input value is the allocated size of the array */
+ *nbytes = 0; /* reset */
+
+ stat = encode64(output, nbytes, a, nx, ny, scale);
+ FFUNLOCK;
+
+ *status = stat;
+ return(*status);
+}
+
+
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* htrans.c H-transform of NX x NY integer image
+ *
+ * Programmer: R. White Date: 11 May 1992
+ */
+
+/* ######################################################################### */
+static int htrans(int a[],int nx,int ny)
+{
+int nmax, log2n, h0, hx, hy, hc, nxtop, nytop, i, j, k;
+int oddx, oddy;
+int shift, mask, mask2, prnd, prnd2, nrnd2;
+int s10, s00;
+int *tmp;
+
+ /*
+ * log2n is log2 of max(nx,ny) rounded up to next power of 2
+ */
+ nmax = (nx>ny) ? nx : ny;
+ log2n = (int) (log((float) nmax)/log(2.0)+0.5);
+ if ( nmax > (1<<log2n) ) {
+ log2n += 1;
+ }
+ /*
+ * get temporary storage for shuffling elements
+ */
+ tmp = (int *) malloc(((nmax+1)/2)*sizeof(int));
+ if(tmp == (int *) NULL) {
+ ffpmsg("htrans: insufficient memory");
+ return(DATA_COMPRESSION_ERR);
+ }
+ /*
+ * set up rounding and shifting masks
+ */
+ shift = 0;
+ mask = -2;
+ mask2 = mask << 1;
+ prnd = 1;
+ prnd2 = prnd << 1;
+ nrnd2 = prnd2 - 1;
+ /*
+ * do log2n reductions
+ *
+ * We're indexing a as a 2-D array with dimensions (nx,ny).
+ */
+ nxtop = nx;
+ nytop = ny;
+
+ for (k = 0; k<log2n; k++) {
+ oddx = nxtop % 2;
+ oddy = nytop % 2;
+ for (i = 0; i<nxtop-oddx; i += 2) {
+ s00 = i*ny; /* s00 is index of a[i,j] */
+ s10 = s00+ny; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<nytop-oddy; j += 2) {
+ /*
+ * Divide h0,hx,hy,hc by 2 (1 the first time through).
+ */
+ h0 = (a[s10+1] + a[s10] + a[s00+1] + a[s00]) >> shift;
+ hx = (a[s10+1] + a[s10] - a[s00+1] - a[s00]) >> shift;
+ hy = (a[s10+1] - a[s10] + a[s00+1] - a[s00]) >> shift;
+ hc = (a[s10+1] - a[s10] - a[s00+1] + a[s00]) >> shift;
+
+ /*
+ * Throw away the 2 bottom bits of h0, bottom bit of hx,hy.
+ * To get rounding to be same for positive and negative
+ * numbers, nrnd2 = prnd2 - 1.
+ */
+ a[s10+1] = hc;
+ a[s10 ] = ( (hx>=0) ? (hx+prnd) : hx ) & mask ;
+ a[s00+1] = ( (hy>=0) ? (hy+prnd) : hy ) & mask ;
+ a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2;
+ s00 += 2;
+ s10 += 2;
+ }
+ if (oddy) {
+ /*
+ * do last element in row if row length is odd
+ * s00+1, s10+1 are off edge
+ */
+ h0 = (a[s10] + a[s00]) << (1-shift);
+ hx = (a[s10] - a[s00]) << (1-shift);
+ a[s10 ] = ( (hx>=0) ? (hx+prnd) : hx ) & mask ;
+ a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2;
+ s00 += 1;
+ s10 += 1;
+ }
+ }
+ if (oddx) {
+ /*
+ * do last row if column length is odd
+ * s10, s10+1 are off edge
+ */
+ s00 = i*ny;
+ for (j = 0; j<nytop-oddy; j += 2) {
+ h0 = (a[s00+1] + a[s00]) << (1-shift);
+ hy = (a[s00+1] - a[s00]) << (1-shift);
+ a[s00+1] = ( (hy>=0) ? (hy+prnd) : hy ) & mask ;
+ a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2;
+ s00 += 2;
+ }
+ if (oddy) {
+ /*
+ * do corner element if both row and column lengths are odd
+ * s00+1, s10, s10+1 are off edge
+ */
+ h0 = a[s00] << (2-shift);
+ a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2;
+ }
+ }
+ /*
+ * now shuffle in each dimension to group coefficients by order
+ */
+ for (i = 0; i<nxtop; i++) {
+ shuffle(&a[ny*i],nytop,1,tmp);
+ }
+ for (j = 0; j<nytop; j++) {
+ shuffle(&a[j],nxtop,ny,tmp);
+ }
+ /*
+ * image size reduced by 2 (round up if odd)
+ */
+ nxtop = (nxtop+1)>>1;
+ nytop = (nytop+1)>>1;
+ /*
+ * divisor doubles after first reduction
+ */
+ shift = 1;
+ /*
+ * masks, rounding values double after each iteration
+ */
+ mask = mask2;
+ prnd = prnd2;
+ mask2 = mask2 << 1;
+ prnd2 = prnd2 << 1;
+ nrnd2 = prnd2 - 1;
+ }
+ free(tmp);
+ return(0);
+}
+/* ######################################################################### */
+
+static int htrans64(LONGLONG a[],int nx,int ny)
+{
+int nmax, log2n, nxtop, nytop, i, j, k;
+int oddx, oddy;
+int shift;
+int s10, s00;
+LONGLONG h0, hx, hy, hc, prnd, prnd2, nrnd2, mask, mask2;
+LONGLONG *tmp;
+
+ /*
+ * log2n is log2 of max(nx,ny) rounded up to next power of 2
+ */
+ nmax = (nx>ny) ? nx : ny;
+ log2n = (int) (log((float) nmax)/log(2.0)+0.5);
+ if ( nmax > (1<<log2n) ) {
+ log2n += 1;
+ }
+ /*
+ * get temporary storage for shuffling elements
+ */
+ tmp = (LONGLONG *) malloc(((nmax+1)/2)*sizeof(LONGLONG));
+ if(tmp == (LONGLONG *) NULL) {
+ ffpmsg("htrans64: insufficient memory");
+ return(DATA_COMPRESSION_ERR);
+ }
+ /*
+ * set up rounding and shifting masks
+ */
+ shift = 0;
+ mask = (LONGLONG) -2;
+ mask2 = mask << 1;
+ prnd = (LONGLONG) 1;
+ prnd2 = prnd << 1;
+ nrnd2 = prnd2 - 1;
+ /*
+ * do log2n reductions
+ *
+ * We're indexing a as a 2-D array with dimensions (nx,ny).
+ */
+ nxtop = nx;
+ nytop = ny;
+
+ for (k = 0; k<log2n; k++) {
+ oddx = nxtop % 2;
+ oddy = nytop % 2;
+ for (i = 0; i<nxtop-oddx; i += 2) {
+ s00 = i*ny; /* s00 is index of a[i,j] */
+ s10 = s00+ny; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<nytop-oddy; j += 2) {
+ /*
+ * Divide h0,hx,hy,hc by 2 (1 the first time through).
+ */
+ h0 = (a[s10+1] + a[s10] + a[s00+1] + a[s00]) >> shift;
+ hx = (a[s10+1] + a[s10] - a[s00+1] - a[s00]) >> shift;
+ hy = (a[s10+1] - a[s10] + a[s00+1] - a[s00]) >> shift;
+ hc = (a[s10+1] - a[s10] - a[s00+1] + a[s00]) >> shift;
+
+ /*
+ * Throw away the 2 bottom bits of h0, bottom bit of hx,hy.
+ * To get rounding to be same for positive and negative
+ * numbers, nrnd2 = prnd2 - 1.
+ */
+ a[s10+1] = hc;
+ a[s10 ] = ( (hx>=0) ? (hx+prnd) : hx ) & mask ;
+ a[s00+1] = ( (hy>=0) ? (hy+prnd) : hy ) & mask ;
+ a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2;
+ s00 += 2;
+ s10 += 2;
+ }
+ if (oddy) {
+ /*
+ * do last element in row if row length is odd
+ * s00+1, s10+1 are off edge
+ */
+ h0 = (a[s10] + a[s00]) << (1-shift);
+ hx = (a[s10] - a[s00]) << (1-shift);
+ a[s10 ] = ( (hx>=0) ? (hx+prnd) : hx ) & mask ;
+ a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2;
+ s00 += 1;
+ s10 += 1;
+ }
+ }
+ if (oddx) {
+ /*
+ * do last row if column length is odd
+ * s10, s10+1 are off edge
+ */
+ s00 = i*ny;
+ for (j = 0; j<nytop-oddy; j += 2) {
+ h0 = (a[s00+1] + a[s00]) << (1-shift);
+ hy = (a[s00+1] - a[s00]) << (1-shift);
+ a[s00+1] = ( (hy>=0) ? (hy+prnd) : hy ) & mask ;
+ a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2;
+ s00 += 2;
+ }
+ if (oddy) {
+ /*
+ * do corner element if both row and column lengths are odd
+ * s00+1, s10, s10+1 are off edge
+ */
+ h0 = a[s00] << (2-shift);
+ a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2;
+ }
+ }
+ /*
+ * now shuffle in each dimension to group coefficients by order
+ */
+ for (i = 0; i<nxtop; i++) {
+ shuffle64(&a[ny*i],nytop,1,tmp);
+ }
+ for (j = 0; j<nytop; j++) {
+ shuffle64(&a[j],nxtop,ny,tmp);
+ }
+ /*
+ * image size reduced by 2 (round up if odd)
+ */
+ nxtop = (nxtop+1)>>1;
+ nytop = (nytop+1)>>1;
+ /*
+ * divisor doubles after first reduction
+ */
+ shift = 1;
+ /*
+ * masks, rounding values double after each iteration
+ */
+ mask = mask2;
+ prnd = prnd2;
+ mask2 = mask2 << 1;
+ prnd2 = prnd2 << 1;
+ nrnd2 = prnd2 - 1;
+ }
+ free(tmp);
+ return(0);
+}
+
+/* ######################################################################### */
+static void
+shuffle(int a[], int n, int n2, int tmp[])
+{
+
+/*
+int a[]; array to shuffle
+int n; number of elements to shuffle
+int n2; second dimension
+int tmp[]; scratch storage
+*/
+
+int i;
+int *p1, *p2, *pt;
+
+ /*
+ * copy odd elements to tmp
+ */
+ pt = tmp;
+ p1 = &a[n2];
+ for (i=1; i < n; i += 2) {
+ *pt = *p1;
+ pt += 1;
+ p1 += (n2+n2);
+ }
+ /*
+ * compress even elements into first half of A
+ */
+ p1 = &a[n2];
+ p2 = &a[n2+n2];
+ for (i=2; i<n; i += 2) {
+ *p1 = *p2;
+ p1 += n2;
+ p2 += (n2+n2);
+ }
+ /*
+ * put odd elements into 2nd half
+ */
+ pt = tmp;
+ for (i = 1; i<n; i += 2) {
+ *p1 = *pt;
+ p1 += n2;
+ pt += 1;
+ }
+}
+/* ######################################################################### */
+static void
+shuffle64(LONGLONG a[], int n, int n2, LONGLONG tmp[])
+{
+
+/*
+LONGLONG a[]; array to shuffle
+int n; number of elements to shuffle
+int n2; second dimension
+LONGLONG tmp[]; scratch storage
+*/
+
+int i;
+LONGLONG *p1, *p2, *pt;
+
+ /*
+ * copy odd elements to tmp
+ */
+ pt = tmp;
+ p1 = &a[n2];
+ for (i=1; i < n; i += 2) {
+ *pt = *p1;
+ pt += 1;
+ p1 += (n2+n2);
+ }
+ /*
+ * compress even elements into first half of A
+ */
+ p1 = &a[n2];
+ p2 = &a[n2+n2];
+ for (i=2; i<n; i += 2) {
+ *p1 = *p2;
+ p1 += n2;
+ p2 += (n2+n2);
+ }
+ /*
+ * put odd elements into 2nd half
+ */
+ pt = tmp;
+ for (i = 1; i<n; i += 2) {
+ *p1 = *pt;
+ p1 += n2;
+ pt += 1;
+ }
+}
+/* ######################################################################### */
+/* ######################################################################### */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* digitize.c digitize H-transform
+ *
+ * Programmer: R. White Date: 11 March 1991
+ */
+
+/* ######################################################################### */
+static void
+digitize(int a[], int nx, int ny, int scale)
+{
+int d, *p;
+
+ /*
+ * round to multiple of scale
+ */
+ if (scale <= 1) return;
+ d=(scale+1)/2-1;
+ for (p=a; p <= &a[nx*ny-1]; p++) *p = ((*p>0) ? (*p+d) : (*p-d))/scale;
+}
+
+/* ######################################################################### */
+static void
+digitize64(LONGLONG a[], int nx, int ny, int scale)
+{
+LONGLONG d, *p, scale64;
+
+ /*
+ * round to multiple of scale
+ */
+ if (scale <= 1) return;
+ d=(scale+1)/2-1;
+ scale64 = scale; /* use a 64-bit int for efficiency in the big loop */
+
+ for (p=a; p <= &a[nx*ny-1]; p++) *p = ((*p>0) ? (*p+d) : (*p-d))/scale64;
+}
+/* ######################################################################### */
+/* ######################################################################### */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* encode.c encode H-transform and write to outfile
+ *
+ * Programmer: R. White Date: 2 February 1994
+ */
+
+static char code_magic[2] = { (char)0xDD, (char)0x99 };
+
+
+/* ######################################################################### */
+static int encode(char *outfile, long *nlength, int a[], int nx, int ny, int scale)
+{
+
+/* FILE *outfile; - change outfile to a char array */
+/*
+ long * nlength returned length (in bytes) of the encoded array)
+ int a[]; input H-transform array (nx,ny)
+ int nx,ny; size of H-transform array
+ int scale; scale factor for digitization
+*/
+int nel, nx2, ny2, i, j, k, q, vmax[3], nsign, bits_to_go;
+unsigned char nbitplanes[3];
+unsigned char *signbits;
+int stat;
+
+ noutchar = 0; /* initialize the number of compressed bytes that have been written */
+ nel = nx*ny;
+ /*
+ * write magic value
+ */
+ qwrite(outfile, code_magic, sizeof(code_magic));
+ writeint(outfile, nx); /* size of image */
+ writeint(outfile, ny);
+ writeint(outfile, scale); /* scale factor for digitization */
+ /*
+ * write first value of A (sum of all pixels -- the only value
+ * which does not compress well)
+ */
+ writelonglong(outfile, (LONGLONG) a[0]);
+
+ a[0] = 0;
+ /*
+ * allocate array for sign bits and save values, 8 per byte
+ */
+ signbits = (unsigned char *) malloc((nel+7)/8);
+ if (signbits == (unsigned char *) NULL) {
+ ffpmsg("encode: insufficient memory");
+ return(DATA_COMPRESSION_ERR);
+ }
+ nsign = 0;
+ bits_to_go = 8;
+ signbits[0] = 0;
+ for (i=0; i<nel; i++) {
+ if (a[i] > 0) {
+ /*
+ * positive element, put zero at end of buffer
+ */
+ signbits[nsign] <<= 1;
+ bits_to_go -= 1;
+ } else if (a[i] < 0) {
+ /*
+ * negative element, shift in a one
+ */
+ signbits[nsign] <<= 1;
+ signbits[nsign] |= 1;
+ bits_to_go -= 1;
+ /*
+ * replace a by absolute value
+ */
+ a[i] = -a[i];
+ }
+ if (bits_to_go == 0) {
+ /*
+ * filled up this byte, go to the next one
+ */
+ bits_to_go = 8;
+ nsign += 1;
+ signbits[nsign] = 0;
+ }
+ }
+ if (bits_to_go != 8) {
+ /*
+ * some bits in last element
+ * move bits in last byte to bottom and increment nsign
+ */
+ signbits[nsign] <<= bits_to_go;
+ nsign += 1;
+ }
+ /*
+ * calculate number of bit planes for 3 quadrants
+ *
+ * quadrant 0=bottom left, 1=bottom right or top left, 2=top right,
+ */
+ for (q=0; q<3; q++) {
+ vmax[q] = 0;
+ }
+ /*
+ * get maximum absolute value in each quadrant
+ */
+ nx2 = (nx+1)/2;
+ ny2 = (ny+1)/2;
+ j=0; /* column counter */
+ k=0; /* row counter */
+ for (i=0; i<nel; i++) {
+ q = (j>=ny2) + (k>=nx2);
+ if (vmax[q] < a[i]) vmax[q] = a[i];
+ if (++j >= ny) {
+ j = 0;
+ k += 1;
+ }
+ }
+ /*
+ * now calculate number of bits for each quadrant
+ */
+
+ /* this is a more efficient way to do this, */
+
+
+ for (q = 0; q < 3; q++) {
+ for (nbitplanes[q] = 0; vmax[q]>0; vmax[q] = vmax[q]>>1, nbitplanes[q]++) ;
+ }
+
+
+/*
+ for (q = 0; q < 3; q++) {
+ nbitplanes[q] = (int) (log((float) (vmax[q]+1))/log(2.0)+0.5);
+ if ( (vmax[q]+1) > (1<<nbitplanes[q]) ) {
+ nbitplanes[q] += 1;
+ }
+ }
+*/
+
+ /*
+ * write nbitplanes
+ */
+ if (0 == qwrite(outfile, (char *) nbitplanes, sizeof(nbitplanes))) {
+ *nlength = noutchar;
+ ffpmsg("encode: output buffer too small");
+ return(DATA_COMPRESSION_ERR);
+ }
+
+ /*
+ * write coded array
+ */
+ stat = doencode(outfile, a, nx, ny, nbitplanes);
+ /*
+ * write sign bits
+ */
+
+ if (nsign > 0) {
+
+ if ( 0 == qwrite(outfile, (char *) signbits, nsign)) {
+ free(signbits);
+ *nlength = noutchar;
+ ffpmsg("encode: output buffer too small");
+ return(DATA_COMPRESSION_ERR);
+ }
+ }
+
+ free(signbits);
+ *nlength = noutchar;
+
+ if (noutchar >= noutmax) {
+ ffpmsg("encode: output buffer too small");
+ return(DATA_COMPRESSION_ERR);
+ }
+
+ return(stat);
+}
+/* ######################################################################### */
+static int encode64(char *outfile, long *nlength, LONGLONG a[], int nx, int ny, int scale)
+{
+
+/* FILE *outfile; - change outfile to a char array */
+/*
+ long * nlength returned length (in bytes) of the encoded array)
+ LONGLONG a[]; input H-transform array (nx,ny)
+ int nx,ny; size of H-transform array
+ int scale; scale factor for digitization
+*/
+int nel, nx2, ny2, i, j, k, q, nsign, bits_to_go;
+LONGLONG vmax[3];
+unsigned char nbitplanes[3];
+unsigned char *signbits;
+int stat;
+
+ noutchar = 0; /* initialize the number of compressed bytes that have been written */
+ nel = nx*ny;
+ /*
+ * write magic value
+ */
+ qwrite(outfile, code_magic, sizeof(code_magic));
+ writeint(outfile, nx); /* size of image */
+ writeint(outfile, ny);
+ writeint(outfile, scale); /* scale factor for digitization */
+ /*
+ * write first value of A (sum of all pixels -- the only value
+ * which does not compress well)
+ */
+ writelonglong(outfile, a[0]);
+
+ a[0] = 0;
+ /*
+ * allocate array for sign bits and save values, 8 per byte
+ */
+ signbits = (unsigned char *) malloc((nel+7)/8);
+ if (signbits == (unsigned char *) NULL) {
+ ffpmsg("encode64: insufficient memory");
+ return(DATA_COMPRESSION_ERR);
+ }
+ nsign = 0;
+ bits_to_go = 8;
+ signbits[0] = 0;
+ for (i=0; i<nel; i++) {
+ if (a[i] > 0) {
+ /*
+ * positive element, put zero at end of buffer
+ */
+ signbits[nsign] <<= 1;
+ bits_to_go -= 1;
+ } else if (a[i] < 0) {
+ /*
+ * negative element, shift in a one
+ */
+ signbits[nsign] <<= 1;
+ signbits[nsign] |= 1;
+ bits_to_go -= 1;
+ /*
+ * replace a by absolute value
+ */
+ a[i] = -a[i];
+ }
+ if (bits_to_go == 0) {
+ /*
+ * filled up this byte, go to the next one
+ */
+ bits_to_go = 8;
+ nsign += 1;
+ signbits[nsign] = 0;
+ }
+ }
+ if (bits_to_go != 8) {
+ /*
+ * some bits in last element
+ * move bits in last byte to bottom and increment nsign
+ */
+ signbits[nsign] <<= bits_to_go;
+ nsign += 1;
+ }
+ /*
+ * calculate number of bit planes for 3 quadrants
+ *
+ * quadrant 0=bottom left, 1=bottom right or top left, 2=top right,
+ */
+ for (q=0; q<3; q++) {
+ vmax[q] = 0;
+ }
+ /*
+ * get maximum absolute value in each quadrant
+ */
+ nx2 = (nx+1)/2;
+ ny2 = (ny+1)/2;
+ j=0; /* column counter */
+ k=0; /* row counter */
+ for (i=0; i<nel; i++) {
+ q = (j>=ny2) + (k>=nx2);
+ if (vmax[q] < a[i]) vmax[q] = a[i];
+ if (++j >= ny) {
+ j = 0;
+ k += 1;
+ }
+ }
+ /*
+ * now calculate number of bits for each quadrant
+ */
+
+ /* this is a more efficient way to do this, */
+
+
+ for (q = 0; q < 3; q++) {
+ for (nbitplanes[q] = 0; vmax[q]>0; vmax[q] = vmax[q]>>1, nbitplanes[q]++) ;
+ }
+
+
+/*
+ for (q = 0; q < 3; q++) {
+ nbitplanes[q] = log((float) (vmax[q]+1))/log(2.0)+0.5;
+ if ( (vmax[q]+1) > (((LONGLONG) 1)<<nbitplanes[q]) ) {
+ nbitplanes[q] += 1;
+ }
+ }
+*/
+
+ /*
+ * write nbitplanes
+ */
+
+ if (0 == qwrite(outfile, (char *) nbitplanes, sizeof(nbitplanes))) {
+ *nlength = noutchar;
+ ffpmsg("encode: output buffer too small");
+ return(DATA_COMPRESSION_ERR);
+ }
+
+ /*
+ * write coded array
+ */
+ stat = doencode64(outfile, a, nx, ny, nbitplanes);
+ /*
+ * write sign bits
+ */
+
+ if (nsign > 0) {
+
+ if ( 0 == qwrite(outfile, (char *) signbits, nsign)) {
+ free(signbits);
+ *nlength = noutchar;
+ ffpmsg("encode: output buffer too small");
+ return(DATA_COMPRESSION_ERR);
+ }
+ }
+
+ free(signbits);
+ *nlength = noutchar;
+
+ if (noutchar >= noutmax) {
+ ffpmsg("encode64: output buffer too small");
+ return(DATA_COMPRESSION_ERR);
+ }
+
+ return(stat);
+}
+/* ######################################################################### */
+/* ######################################################################### */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* qwrite.c Write binary data
+ *
+ * Programmer: R. White Date: 11 March 1991
+ */
+
+/* ######################################################################### */
+static void
+writeint(char *outfile, int a)
+{
+int i;
+unsigned char b[4];
+
+ /* Write integer A one byte at a time to outfile.
+ *
+ * This is portable from Vax to Sun since it eliminates the
+ * need for byte-swapping.
+ */
+ for (i=3; i>=0; i--) {
+ b[i] = a & 0x000000ff;
+ a >>= 8;
+ }
+ for (i=0; i<4; i++) qwrite(outfile, (char *) &b[i],1);
+}
+
+/* ######################################################################### */
+static void
+writelonglong(char *outfile, LONGLONG a)
+{
+int i;
+unsigned char b[8];
+
+ /* Write integer A one byte at a time to outfile.
+ *
+ * This is portable from Vax to Sun since it eliminates the
+ * need for byte-swapping.
+ */
+ for (i=7; i>=0; i--) {
+ b[i] = (unsigned char) (a & 0x000000ff);
+ a >>= 8;
+ }
+ for (i=0; i<8; i++) qwrite(outfile, (char *) &b[i],1);
+}
+/* ######################################################################### */
+static int
+qwrite(char *file, char buffer[], int n){
+ /*
+ * write n bytes from buffer into file
+ * returns number of bytes read (=n) if successful, <=0 if not
+ */
+
+ if (noutchar + n > noutmax) return(0); /* buffer overflow */
+
+ memcpy(&file[noutchar], buffer, n);
+ noutchar += n;
+
+ return(n);
+}
+/* ######################################################################### */
+/* ######################################################################### */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* doencode.c Encode 2-D array and write stream of characters on outfile
+ *
+ * This version assumes that A is positive.
+ *
+ * Programmer: R. White Date: 7 May 1991
+ */
+
+/* ######################################################################### */
+static int
+doencode(char *outfile, int a[], int nx, int ny, unsigned char nbitplanes[3])
+{
+/* char *outfile; output data stream
+int a[]; Array of values to encode
+int nx,ny; Array dimensions [nx][ny]
+unsigned char nbitplanes[3]; Number of bit planes in quadrants
+*/
+
+int nx2, ny2, stat;
+
+ nx2 = (nx+1)/2;
+ ny2 = (ny+1)/2;
+ /*
+ * Initialize bit output
+ */
+ start_outputing_bits();
+ /*
+ * write out the bit planes for each quadrant
+ */
+ stat = qtree_encode(outfile, &a[0], ny, nx2, ny2, nbitplanes[0]);
+
+ if (!stat)
+ stat = qtree_encode(outfile, &a[ny2], ny, nx2, ny/2, nbitplanes[1]);
+
+ if (!stat)
+ stat = qtree_encode(outfile, &a[ny*nx2], ny, nx/2, ny2, nbitplanes[1]);
+
+ if (!stat)
+ stat = qtree_encode(outfile, &a[ny*nx2+ny2], ny, nx/2, ny/2, nbitplanes[2]);
+ /*
+ * Add zero as an EOF symbol
+ */
+ output_nybble(outfile, 0);
+ done_outputing_bits(outfile);
+
+ return(stat);
+}
+/* ######################################################################### */
+static int
+doencode64(char *outfile, LONGLONG a[], int nx, int ny, unsigned char nbitplanes[3])
+{
+/* char *outfile; output data stream
+LONGLONG a[]; Array of values to encode
+int nx,ny; Array dimensions [nx][ny]
+unsigned char nbitplanes[3]; Number of bit planes in quadrants
+*/
+
+int nx2, ny2, stat;
+
+ nx2 = (nx+1)/2;
+ ny2 = (ny+1)/2;
+ /*
+ * Initialize bit output
+ */
+ start_outputing_bits();
+ /*
+ * write out the bit planes for each quadrant
+ */
+ stat = qtree_encode64(outfile, &a[0], ny, nx2, ny2, nbitplanes[0]);
+
+ if (!stat)
+ stat = qtree_encode64(outfile, &a[ny2], ny, nx2, ny/2, nbitplanes[1]);
+
+ if (!stat)
+ stat = qtree_encode64(outfile, &a[ny*nx2], ny, nx/2, ny2, nbitplanes[1]);
+
+ if (!stat)
+ stat = qtree_encode64(outfile, &a[ny*nx2+ny2], ny, nx/2, ny/2, nbitplanes[2]);
+ /*
+ * Add zero as an EOF symbol
+ */
+ output_nybble(outfile, 0);
+ done_outputing_bits(outfile);
+
+ return(stat);
+}
+/* ######################################################################### */
+/* ######################################################################### */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* BIT OUTPUT ROUTINES */
+
+
+static LONGLONG bitcount;
+
+/* THE BIT BUFFER */
+
+static int buffer2; /* Bits buffered for output */
+static int bits_to_go2; /* Number of bits free in buffer */
+
+
+/* ######################################################################### */
+/* INITIALIZE FOR BIT OUTPUT */
+
+static void
+start_outputing_bits(void)
+{
+ buffer2 = 0; /* Buffer is empty to start */
+ bits_to_go2 = 8; /* with */
+ bitcount = 0;
+}
+
+/* ######################################################################### */
+/* OUTPUT N BITS (N must be <= 8) */
+
+static void
+output_nbits(char *outfile, int bits, int n)
+{
+ /* AND mask for the right-most n bits */
+ static int mask[9] = {0, 1, 3, 7, 15, 31, 63, 127, 255};
+ /*
+ * insert bits at end of buffer
+ */
+ buffer2 <<= n;
+/* buffer2 |= ( bits & ((1<<n)-1) ); */
+ buffer2 |= ( bits & (*(mask+n)) );
+ bits_to_go2 -= n;
+ if (bits_to_go2 <= 0) {
+ /*
+ * buffer2 full, put out top 8 bits
+ */
+
+ outfile[noutchar] = ((buffer2>>(-bits_to_go2)) & 0xff);
+
+ if (noutchar < noutmax) noutchar++;
+
+ bits_to_go2 += 8;
+ }
+ bitcount += n;
+}
+/* ######################################################################### */
+/* OUTPUT a 4 bit nybble */
+static void
+output_nybble(char *outfile, int bits)
+{
+ /*
+ * insert 4 bits at end of buffer
+ */
+ buffer2 = (buffer2<<4) | ( bits & 15 );
+ bits_to_go2 -= 4;
+ if (bits_to_go2 <= 0) {
+ /*
+ * buffer2 full, put out top 8 bits
+ */
+
+ outfile[noutchar] = ((buffer2>>(-bits_to_go2)) & 0xff);
+
+ if (noutchar < noutmax) noutchar++;
+
+ bits_to_go2 += 8;
+ }
+ bitcount += 4;
+}
+/* ############################################################################ */
+/* OUTPUT array of 4 BITS */
+
+static void output_nnybble(char *outfile, int n, unsigned char array[])
+{
+ /* pack the 4 lower bits in each element of the array into the outfile array */
+
+int ii, jj, kk = 0, shift;
+
+ if (n == 1) {
+ output_nybble(outfile, (int) array[0]);
+ return;
+ }
+/* forcing byte alignment doesn;t help, and even makes it go slightly slower
+if (bits_to_go2 != 8)
+ output_nbits(outfile, kk, bits_to_go2);
+*/
+ if (bits_to_go2 <= 4)
+ {
+ /* just room for 1 nybble; write it out separately */
+ output_nybble(outfile, array[0]);
+ kk++; /* index to next array element */
+
+ if (n == 2) /* only 1 more nybble to write out */
+ {
+ output_nybble(outfile, (int) array[1]);
+ return;
+ }
+ }
+
+
+ /* bits_to_go2 is now in the range 5 - 8 */
+ shift = 8 - bits_to_go2;
+
+ /* now write out pairs of nybbles; this does not affect value of bits_to_go2 */
+ jj = (n - kk) / 2;
+
+ if (bits_to_go2 == 8) {
+ /* special case if nybbles are aligned on byte boundary */
+ /* this actually seems to make very little differnece in speed */
+ buffer2 = 0;
+ for (ii = 0; ii < jj; ii++)
+ {
+ outfile[noutchar] = ((array[kk] & 15)<<4) | (array[kk+1] & 15);
+ kk += 2;
+ noutchar++;
+ }
+ } else {
+ for (ii = 0; ii < jj; ii++)
+ {
+ buffer2 = (buffer2<<8) | ((array[kk] & 15)<<4) | (array[kk+1] & 15);
+ kk += 2;
+
+ /*
+ buffer2 full, put out top 8 bits
+ */
+
+ outfile[noutchar] = ((buffer2>>shift) & 0xff);
+ noutchar++;
+ }
+ }
+
+ bitcount += (8 * (ii - 1));
+
+ /* write out last odd nybble, if present */
+ if (kk != n) output_nybble(outfile, (int) array[n - 1]);
+
+ return;
+}
+
+
+/* ######################################################################### */
+/* FLUSH OUT THE LAST BITS */
+
+static void
+done_outputing_bits(char *outfile)
+{
+ if(bits_to_go2 < 8) {
+/* putc(buffer2<<bits_to_go2,outfile); */
+
+ outfile[noutchar] = (buffer2<<bits_to_go2);
+ if (noutchar < noutmax) noutchar++;
+
+ /* count the garbage bits too */
+ bitcount += bits_to_go2;
+ }
+}
+/* ######################################################################### */
+/* ######################################################################### */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* qtree_encode.c Encode values in quadrant of 2-D array using binary
+ * quadtree coding for each bit plane. Assumes array is
+ * positive.
+ *
+ * Programmer: R. White Date: 15 May 1991
+ */
+
+/*
+ * Huffman code values and number of bits in each code
+ */
+static int code[16] =
+ {
+ 0x3e, 0x00, 0x01, 0x08, 0x02, 0x09, 0x1a, 0x1b,
+ 0x03, 0x1c, 0x0a, 0x1d, 0x0b, 0x1e, 0x3f, 0x0c
+ };
+static int ncode[16] =
+ {
+ 6, 3, 3, 4, 3, 4, 5, 5,
+ 3, 5, 4, 5, 4, 5, 6, 4
+ };
+
+/*
+ * variables for bit output to buffer when Huffman coding
+ */
+static int bitbuffer, bits_to_go3;
+
+/*
+ * macros to write out 4-bit nybble, Huffman code for this value
+ */
+
+
+/* ######################################################################### */
+static int
+qtree_encode(char *outfile, int a[], int n, int nqx, int nqy, int nbitplanes)
+{
+
+/*
+int a[];
+int n; physical dimension of row in a
+int nqx; length of row
+int nqy; length of column (<=n)
+int nbitplanes; number of bit planes to output
+*/
+
+int log2n, i, k, bit, b, bmax, nqmax, nqx2, nqy2, nx, ny;
+unsigned char *scratch, *buffer;
+
+ /*
+ * log2n is log2 of max(nqx,nqy) rounded up to next power of 2
+ */
+ nqmax = (nqx>nqy) ? nqx : nqy;
+ log2n = (int) (log((float) nqmax)/log(2.0)+0.5);
+ if (nqmax > (1<<log2n)) {
+ log2n += 1;
+ }
+ /*
+ * initialize buffer point, max buffer size
+ */
+ nqx2 = (nqx+1)/2;
+ nqy2 = (nqy+1)/2;
+ bmax = (nqx2*nqy2+1)/2;
+ /*
+ * We're indexing A as a 2-D array with dimensions (nqx,nqy).
+ * Scratch is 2-D with dimensions (nqx/2,nqy/2) rounded up.
+ * Buffer is used to store string of codes for output.
+ */
+ scratch = (unsigned char *) malloc(2*bmax);
+ buffer = (unsigned char *) malloc(bmax);
+ if ((scratch == (unsigned char *) NULL) ||
+ (buffer == (unsigned char *) NULL)) {
+ ffpmsg("qtree_encode: insufficient memory");
+ return(DATA_COMPRESSION_ERR);
+ }
+ /*
+ * now encode each bit plane, starting with the top
+ */
+ for (bit=nbitplanes-1; bit >= 0; bit--) {
+ /*
+ * initial bit buffer
+ */
+ b = 0;
+ bitbuffer = 0;
+ bits_to_go3 = 0;
+ /*
+ * on first pass copy A to scratch array
+ */
+ qtree_onebit(a,n,nqx,nqy,scratch,bit);
+ nx = (nqx+1)>>1;
+ ny = (nqy+1)>>1;
+ /*
+ * copy non-zero values to output buffer, which will be written
+ * in reverse order
+ */
+ if (bufcopy(scratch,nx*ny,buffer,&b,bmax)) {
+ /*
+ * quadtree is expanding data,
+ * change warning code and just fill buffer with bit-map
+ */
+ write_bdirect(outfile,a,n,nqx,nqy,scratch,bit);
+ goto bitplane_done;
+ }
+ /*
+ * do log2n reductions
+ */
+ for (k = 1; k<log2n; k++) {
+ qtree_reduce(scratch,ny,nx,ny,scratch);
+ nx = (nx+1)>>1;
+ ny = (ny+1)>>1;
+ if (bufcopy(scratch,nx*ny,buffer,&b,bmax)) {
+ write_bdirect(outfile,a,n,nqx,nqy,scratch,bit);
+ goto bitplane_done;
+ }
+ }
+ /*
+ * OK, we've got the code in buffer
+ * Write quadtree warning code, then write buffer in reverse order
+ */
+ output_nybble(outfile,0xF);
+ if (b==0) {
+ if (bits_to_go3>0) {
+ /*
+ * put out the last few bits
+ */
+ output_nbits(outfile, bitbuffer & ((1<<bits_to_go3)-1),
+ bits_to_go3);
+ } else {
+ /*
+ * have to write a zero nybble if there are no 1's in array
+ */
+ output_huffman(outfile,0);
+ }
+ } else {
+ if (bits_to_go3>0) {
+ /*
+ * put out the last few bits
+ */
+ output_nbits(outfile, bitbuffer & ((1<<bits_to_go3)-1),
+ bits_to_go3);
+ }
+ for (i=b-1; i>=0; i--) {
+ output_nbits(outfile,buffer[i],8);
+ }
+ }
+ bitplane_done: ;
+ }
+ free(buffer);
+ free(scratch);
+ return(0);
+}
+/* ######################################################################### */
+static int
+qtree_encode64(char *outfile, LONGLONG a[], int n, int nqx, int nqy, int nbitplanes)
+{
+
+/*
+LONGLONG a[];
+int n; physical dimension of row in a
+int nqx; length of row
+int nqy; length of column (<=n)
+int nbitplanes; number of bit planes to output
+*/
+
+int log2n, i, k, bit, b, nqmax, nqx2, nqy2, nx, ny;
+int bmax; /* this potentially needs to be made a 64-bit int to support large arrays */
+unsigned char *scratch, *buffer;
+
+ /*
+ * log2n is log2 of max(nqx,nqy) rounded up to next power of 2
+ */
+ nqmax = (nqx>nqy) ? nqx : nqy;
+ log2n = (int) (log((float) nqmax)/log(2.0)+0.5);
+ if (nqmax > (1<<log2n)) {
+ log2n += 1;
+ }
+ /*
+ * initialize buffer point, max buffer size
+ */
+ nqx2 = (nqx+1)/2;
+ nqy2 = (nqy+1)/2;
+ bmax = (( nqx2)* ( nqy2)+1)/2;
+ /*
+ * We're indexing A as a 2-D array with dimensions (nqx,nqy).
+ * Scratch is 2-D with dimensions (nqx/2,nqy/2) rounded up.
+ * Buffer is used to store string of codes for output.
+ */
+ scratch = (unsigned char *) malloc(2*bmax);
+ buffer = (unsigned char *) malloc(bmax);
+ if ((scratch == (unsigned char *) NULL) ||
+ (buffer == (unsigned char *) NULL)) {
+ ffpmsg("qtree_encode64: insufficient memory");
+ return(DATA_COMPRESSION_ERR);
+ }
+ /*
+ * now encode each bit plane, starting with the top
+ */
+ for (bit=nbitplanes-1; bit >= 0; bit--) {
+ /*
+ * initial bit buffer
+ */
+ b = 0;
+ bitbuffer = 0;
+ bits_to_go3 = 0;
+ /*
+ * on first pass copy A to scratch array
+ */
+ qtree_onebit64(a,n,nqx,nqy,scratch,bit);
+ nx = (nqx+1)>>1;
+ ny = (nqy+1)>>1;
+ /*
+ * copy non-zero values to output buffer, which will be written
+ * in reverse order
+ */
+ if (bufcopy(scratch,nx*ny,buffer,&b,bmax)) {
+ /*
+ * quadtree is expanding data,
+ * change warning code and just fill buffer with bit-map
+ */
+ write_bdirect64(outfile,a,n,nqx,nqy,scratch,bit);
+ goto bitplane_done;
+ }
+ /*
+ * do log2n reductions
+ */
+ for (k = 1; k<log2n; k++) {
+ qtree_reduce(scratch,ny,nx,ny,scratch);
+ nx = (nx+1)>>1;
+ ny = (ny+1)>>1;
+ if (bufcopy(scratch,nx*ny,buffer,&b,bmax)) {
+ write_bdirect64(outfile,a,n,nqx,nqy,scratch,bit);
+ goto bitplane_done;
+ }
+ }
+ /*
+ * OK, we've got the code in buffer
+ * Write quadtree warning code, then write buffer in reverse order
+ */
+ output_nybble(outfile,0xF);
+ if (b==0) {
+ if (bits_to_go3>0) {
+ /*
+ * put out the last few bits
+ */
+ output_nbits(outfile, bitbuffer & ((1<<bits_to_go3)-1),
+ bits_to_go3);
+ } else {
+ /*
+ * have to write a zero nybble if there are no 1's in array
+ */
+ output_huffman(outfile,0);
+ }
+ } else {
+ if (bits_to_go3>0) {
+ /*
+ * put out the last few bits
+ */
+ output_nbits(outfile, bitbuffer & ((1<<bits_to_go3)-1),
+ bits_to_go3);
+ }
+ for (i=b-1; i>=0; i--) {
+ output_nbits(outfile,buffer[i],8);
+ }
+ }
+ bitplane_done: ;
+ }
+ free(buffer);
+ free(scratch);
+ return(0);
+}
+
+/* ######################################################################### */
+/*
+ * copy non-zero codes from array to buffer
+ */
+static int
+bufcopy(unsigned char a[], int n, unsigned char buffer[], int *b, int bmax)
+{
+int i;
+
+ for (i = 0; i < n; i++) {
+ if (a[i] != 0) {
+ /*
+ * add Huffman code for a[i] to buffer
+ */
+ bitbuffer |= code[a[i]] << bits_to_go3;
+ bits_to_go3 += ncode[a[i]];
+ if (bits_to_go3 >= 8) {
+ buffer[*b] = bitbuffer & 0xFF;
+ *b += 1;
+ /*
+ * return warning code if we fill buffer
+ */
+ if (*b >= bmax) return(1);
+ bitbuffer >>= 8;
+ bits_to_go3 -= 8;
+ }
+ }
+ }
+ return(0);
+}
+
+/* ######################################################################### */
+/*
+ * Do first quadtree reduction step on bit BIT of array A.
+ * Results put into B.
+ *
+ */
+static void
+qtree_onebit(int a[], int n, int nx, int ny, unsigned char b[], int bit)
+{
+int i, j, k;
+int b0, b1, b2, b3;
+int s10, s00;
+
+ /*
+ * use selected bit to get amount to shift
+ */
+ b0 = 1<<bit;
+ b1 = b0<<1;
+ b2 = b0<<2;
+ b3 = b0<<3;
+ k = 0; /* k is index of b[i/2,j/2] */
+ for (i = 0; i<nx-1; i += 2) {
+ s00 = n*i; /* s00 is index of a[i,j] */
+/* tried using s00+n directly in the statements, but this had no effect on performance */
+ s10 = s00+n; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<ny-1; j += 2) {
+
+/*
+ this was not any faster..
+
+ b[k] = (a[s00] & b0) ?
+ (a[s00+1] & b0) ?
+ (a[s10] & b0) ?
+ (a[s10+1] & b0) ? 15 : 14
+ : (a[s10+1] & b0) ? 13 : 12
+ : (a[s10] & b0) ?
+ (a[s10+1] & b0) ? 11 : 10
+ : (a[s10+1] & b0) ? 9 : 8
+ : (a[s00+1] & b0) ?
+ (a[s10] & b0) ?
+ (a[s10+1] & b0) ? 7 : 6
+ : (a[s10+1] & b0) ? 5 : 4
+
+ : (a[s10] & b0) ?
+ (a[s10+1] & b0) ? 3 : 2
+ : (a[s10+1] & b0) ? 1 : 0;
+*/
+
+/*
+this alternative way of calculating b[k] was slowwer than the original code
+ if ( a[s00] & b0)
+ if ( a[s00+1] & b0)
+ if ( a[s10] & b0)
+ if ( a[s10+1] & b0)
+ b[k] = 15;
+ else
+ b[k] = 14;
+ else
+ if ( a[s10+1] & b0)
+ b[k] = 13;
+ else
+ b[k] = 12;
+ else
+ if ( a[s10] & b0)
+ if ( a[s10+1] & b0)
+ b[k] = 11;
+ else
+ b[k] = 10;
+ else
+ if ( a[s10+1] & b0)
+ b[k] = 9;
+ else
+ b[k] = 8;
+ else
+ if ( a[s00+1] & b0)
+ if ( a[s10] & b0)
+ if ( a[s10+1] & b0)
+ b[k] = 7;
+ else
+ b[k] = 6;
+ else
+ if ( a[s10+1] & b0)
+ b[k] = 5;
+ else
+ b[k] = 4;
+ else
+ if ( a[s10] & b0)
+ if ( a[s10+1] & b0)
+ b[k] = 3;
+ else
+ b[k] = 2;
+ else
+ if ( a[s10+1] & b0)
+ b[k] = 1;
+ else
+ b[k] = 0;
+*/
+
+
+
+ b[k] = ( ( a[s10+1] & b0)
+ | ((a[s10 ]<<1) & b1)
+ | ((a[s00+1]<<2) & b2)
+ | ((a[s00 ]<<3) & b3) ) >> bit;
+
+ k += 1;
+ s00 += 2;
+ s10 += 2;
+ }
+ if (j < ny) {
+ /*
+ * row size is odd, do last element in row
+ * s00+1,s10+1 are off edge
+ */
+ b[k] = ( ((a[s10 ]<<1) & b1)
+ | ((a[s00 ]<<3) & b3) ) >> bit;
+ k += 1;
+ }
+ }
+ if (i < nx) {
+ /*
+ * column size is odd, do last row
+ * s10,s10+1 are off edge
+ */
+ s00 = n*i;
+ for (j = 0; j<ny-1; j += 2) {
+ b[k] = ( ((a[s00+1]<<2) & b2)
+ | ((a[s00 ]<<3) & b3) ) >> bit;
+ k += 1;
+ s00 += 2;
+ }
+ if (j < ny) {
+ /*
+ * both row and column size are odd, do corner element
+ * s00+1, s10, s10+1 are off edge
+ */
+ b[k] = ( ((a[s00 ]<<3) & b3) ) >> bit;
+ k += 1;
+ }
+ }
+}
+/* ######################################################################### */
+/*
+ * Do first quadtree reduction step on bit BIT of array A.
+ * Results put into B.
+ *
+ */
+static void
+qtree_onebit64(LONGLONG a[], int n, int nx, int ny, unsigned char b[], int bit)
+{
+int i, j, k;
+LONGLONG b0, b1, b2, b3;
+int s10, s00;
+
+ /*
+ * use selected bit to get amount to shift
+ */
+ b0 = ((LONGLONG) 1)<<bit;
+ b1 = b0<<1;
+ b2 = b0<<2;
+ b3 = b0<<3;
+ k = 0; /* k is index of b[i/2,j/2] */
+ for (i = 0; i<nx-1; i += 2) {
+ s00 = n*i; /* s00 is index of a[i,j] */
+ s10 = s00+n; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<ny-1; j += 2) {
+ b[k] = (unsigned char) (( ( a[s10+1] & b0)
+ | ((a[s10 ]<<1) & b1)
+ | ((a[s00+1]<<2) & b2)
+ | ((a[s00 ]<<3) & b3) ) >> bit);
+ k += 1;
+ s00 += 2;
+ s10 += 2;
+ }
+ if (j < ny) {
+ /*
+ * row size is odd, do last element in row
+ * s00+1,s10+1 are off edge
+ */
+ b[k] = (unsigned char) (( ((a[s10 ]<<1) & b1)
+ | ((a[s00 ]<<3) & b3) ) >> bit);
+ k += 1;
+ }
+ }
+ if (i < nx) {
+ /*
+ * column size is odd, do last row
+ * s10,s10+1 are off edge
+ */
+ s00 = n*i;
+ for (j = 0; j<ny-1; j += 2) {
+ b[k] = (unsigned char) (( ((a[s00+1]<<2) & b2)
+ | ((a[s00 ]<<3) & b3) ) >> bit);
+ k += 1;
+ s00 += 2;
+ }
+ if (j < ny) {
+ /*
+ * both row and column size are odd, do corner element
+ * s00+1, s10, s10+1 are off edge
+ */
+ b[k] = (unsigned char) (( ((a[s00 ]<<3) & b3) ) >> bit);
+ k += 1;
+ }
+ }
+}
+
+/* ######################################################################### */
+/*
+ * do one quadtree reduction step on array a
+ * results put into b (which may be the same as a)
+ */
+static void
+qtree_reduce(unsigned char a[], int n, int nx, int ny, unsigned char b[])
+{
+int i, j, k;
+int s10, s00;
+
+ k = 0; /* k is index of b[i/2,j/2] */
+ for (i = 0; i<nx-1; i += 2) {
+ s00 = n*i; /* s00 is index of a[i,j] */
+ s10 = s00+n; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<ny-1; j += 2) {
+ b[k] = (a[s10+1] != 0)
+ | ( (a[s10 ] != 0) << 1)
+ | ( (a[s00+1] != 0) << 2)
+ | ( (a[s00 ] != 0) << 3);
+ k += 1;
+ s00 += 2;
+ s10 += 2;
+ }
+ if (j < ny) {
+ /*
+ * row size is odd, do last element in row
+ * s00+1,s10+1 are off edge
+ */
+ b[k] = ( (a[s10 ] != 0) << 1)
+ | ( (a[s00 ] != 0) << 3);
+ k += 1;
+ }
+ }
+ if (i < nx) {
+ /*
+ * column size is odd, do last row
+ * s10,s10+1 are off edge
+ */
+ s00 = n*i;
+ for (j = 0; j<ny-1; j += 2) {
+ b[k] = ( (a[s00+1] != 0) << 2)
+ | ( (a[s00 ] != 0) << 3);
+ k += 1;
+ s00 += 2;
+ }
+ if (j < ny) {
+ /*
+ * both row and column size are odd, do corner element
+ * s00+1, s10, s10+1 are off edge
+ */
+ b[k] = ( (a[s00 ] != 0) << 3);
+ k += 1;
+ }
+ }
+}
+
+/* ######################################################################### */
+static void
+write_bdirect(char *outfile, int a[], int n,int nqx, int nqy, unsigned char scratch[], int bit)
+{
+
+ /*
+ * Write the direct bitmap warning code
+ */
+ output_nybble(outfile,0x0);
+ /*
+ * Copy A to scratch array (again!), packing 4 bits/nybble
+ */
+ qtree_onebit(a,n,nqx,nqy,scratch,bit);
+ /*
+ * write to outfile
+ */
+/*
+int i;
+ for (i = 0; i < ((nqx+1)/2) * ((nqy+1)/2); i++) {
+ output_nybble(outfile,scratch[i]);
+ }
+*/
+ output_nnybble(outfile, ((nqx+1)/2) * ((nqy+1)/2), scratch);
+
+}
+/* ######################################################################### */
+static void
+write_bdirect64(char *outfile, LONGLONG a[], int n,int nqx, int nqy, unsigned char scratch[], int bit)
+{
+
+ /*
+ * Write the direct bitmap warning code
+ */
+ output_nybble(outfile,0x0);
+ /*
+ * Copy A to scratch array (again!), packing 4 bits/nybble
+ */
+ qtree_onebit64(a,n,nqx,nqy,scratch,bit);
+ /*
+ * write to outfile
+ */
+/*
+int i;
+ for (i = 0; i < ((nqx+1)/2) * ((nqy+1)/2); i++) {
+ output_nybble(outfile,scratch[i]);
+ }
+*/
+ output_nnybble(outfile, ((nqx+1)/2) * ((nqy+1)/2), scratch);
+}
diff --git a/vendor/cfitsio/fits_hdecompress.c b/vendor/cfitsio/fits_hdecompress.c
new file mode 100644
index 00000000..2086d381
--- /dev/null
+++ b/vendor/cfitsio/fits_hdecompress.c
@@ -0,0 +1,2618 @@
+/* #########################################################################
+These routines to apply the H-compress decompression algorithm to a 2-D Fits
+image were written by R. White at the STScI and were obtained from the STScI at
+http://www.stsci.edu/software/hcompress.html
+
+This source file is a concatination of the following sources files in the
+original distribution
+ hinv.c
+ hsmooth.c
+ undigitize.c
+ decode.c
+ dodecode.c
+ qtree_decode.c
+ qread.c
+ bit_input.c
+
+
+The following modifications have been made to the original code:
+
+ - commented out redundant "include" statements
+ - added the nextchar global variable
+ - changed all the 'extern' declarations to 'static', since all the routines are in
+ the same source file
+ - changed the first parameter in decode (and in lower level routines from a file stream
+ to a char array
+ - modified the myread routine, and lower level byte reading routines, to copy
+ the input bytes to a char array, instead of reading them from a file stream
+ - changed the function declarations to the more modern ANSI C style
+ - changed calls to printf and perror to call the CFITSIO ffpmsg routine
+ - replace "exit" statements with "return" statements
+
+ ############################################################################ */
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/* WDP added test to see if min and max are already defined */
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+static long nextchar;
+
+static int decode(unsigned char *infile, int *a, int *nx, int *ny, int *scale);
+static int decode64(unsigned char *infile, LONGLONG *a, int *nx, int *ny, int *scale);
+static int hinv(int a[], int nx, int ny, int smooth ,int scale);
+static int hinv64(LONGLONG a[], int nx, int ny, int smooth ,int scale);
+static void undigitize(int a[], int nx, int ny, int scale);
+static void undigitize64(LONGLONG a[], int nx, int ny, int scale);
+static void unshuffle(int a[], int n, int n2, int tmp[]);
+static void unshuffle64(LONGLONG a[], int n, int n2, LONGLONG tmp[]);
+static void hsmooth(int a[], int nxtop, int nytop, int ny, int scale);
+static void hsmooth64(LONGLONG a[], int nxtop, int nytop, int ny, int scale);
+static void qread(unsigned char *infile,char *a, int n);
+static int readint(unsigned char *infile);
+static LONGLONG readlonglong(unsigned char *infile);
+static int dodecode(unsigned char *infile, int a[], int nx, int ny, unsigned char nbitplanes[3]);
+static int dodecode64(unsigned char *infile, LONGLONG a[], int nx, int ny, unsigned char nbitplanes[3]);
+static int qtree_decode(unsigned char *infile, int a[], int n, int nqx, int nqy, int nbitplanes);
+static int qtree_decode64(unsigned char *infile, LONGLONG a[], int n, int nqx, int nqy, int nbitplanes);
+static void start_inputing_bits(void);
+static int input_bit(unsigned char *infile);
+static int input_nbits(unsigned char *infile, int n);
+/* make input_nybble a separate routine, for added effiency */
+/* #define input_nybble(infile) input_nbits(infile,4) */
+static int input_nybble(unsigned char *infile);
+static int input_nnybble(unsigned char *infile, int n, unsigned char *array);
+
+static void qtree_expand(unsigned char *infile, unsigned char a[], int nx, int ny, unsigned char b[]);
+static void qtree_bitins(unsigned char a[], int nx, int ny, int b[], int n, int bit);
+static void qtree_bitins64(unsigned char a[], int nx, int ny, LONGLONG b[], int n, int bit);
+static void qtree_copy(unsigned char a[], int nx, int ny, unsigned char b[], int n);
+static void read_bdirect(unsigned char *infile, int a[], int n, int nqx, int nqy, unsigned char scratch[], int bit);
+static void read_bdirect64(unsigned char *infile, LONGLONG a[], int n, int nqx, int nqy, unsigned char scratch[], int bit);
+static int input_huffman(unsigned char *infile);
+
+/* ---------------------------------------------------------------------- */
+int fits_hdecompress(unsigned char *input, int smooth, int *a, int *ny, int *nx,
+ int *scale, int *status)
+{
+ /*
+ decompress the input byte stream using the H-compress algorithm
+
+ input - input array of compressed bytes
+ a - pre-allocated array to hold the output uncompressed image
+ nx - returned X axis size
+ ny - returned Y axis size
+
+ NOTE: the nx and ny dimensions as defined within this code are reversed from
+ the usual FITS notation. ny is the fastest varying dimension, which is
+ usually considered the X axis in the FITS image display
+
+ */
+int stat;
+
+ if (*status > 0) return(*status);
+
+ /* decode the input array */
+
+ FFLOCK; /* decode uses the nextchar global variable */
+ stat = decode(input, a, nx, ny, scale);
+ FFUNLOCK;
+
+ *status = stat;
+ if (stat) return(*status);
+
+ /*
+ * Un-Digitize
+ */
+ undigitize(a, *nx, *ny, *scale);
+
+ /*
+ * Inverse H-transform
+ */
+ stat = hinv(a, *nx, *ny, smooth, *scale);
+ *status = stat;
+
+ return(*status);
+}
+/* ---------------------------------------------------------------------- */
+int fits_hdecompress64(unsigned char *input, int smooth, LONGLONG *a, int *ny, int *nx,
+ int *scale, int *status)
+{
+ /*
+ decompress the input byte stream using the H-compress algorithm
+
+ input - input array of compressed bytes
+ a - pre-allocated array to hold the output uncompressed image
+ nx - returned X axis size
+ ny - returned Y axis size
+
+ NOTE: the nx and ny dimensions as defined within this code are reversed from
+ the usual FITS notation. ny is the fastest varying dimension, which is
+ usually considered the X axis in the FITS image display
+
+ */
+ int stat, *iarray, ii, nval;
+
+ if (*status > 0) return(*status);
+
+ /* decode the input array */
+
+ FFLOCK; /* decode uses the nextchar global variable */
+ stat = decode64(input, a, nx, ny, scale);
+ FFUNLOCK;
+
+ *status = stat;
+ if (stat) return(*status);
+
+ /*
+ * Un-Digitize
+ */
+ undigitize64(a, *nx, *ny, *scale);
+
+ /*
+ * Inverse H-transform
+ */
+ stat = hinv64(a, *nx, *ny, smooth, *scale);
+
+ *status = stat;
+
+ /* pack the I*8 values back into an I*4 array */
+ iarray = (int *) a;
+ nval = (*nx) * (*ny);
+
+ for (ii = 0; ii < nval; ii++)
+ iarray[ii] = (int) a[ii];
+
+ return(*status);
+}
+
+/* ############################################################################ */
+/* ############################################################################ */
+
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* hinv.c Inverse H-transform of NX x NY integer image
+ *
+ * Programmer: R. White Date: 23 July 1993
+ */
+
+/* ############################################################################ */
+static int
+hinv(int a[], int nx, int ny, int smooth ,int scale)
+/*
+int smooth; 0 for no smoothing, else smooth during inversion
+int scale; used if smoothing is specified
+*/
+{
+int nmax, log2n, i, j, k;
+int nxtop,nytop,nxf,nyf,c;
+int oddx,oddy;
+int shift, bit0, bit1, bit2, mask0, mask1, mask2,
+ prnd0, prnd1, prnd2, nrnd0, nrnd1, nrnd2, lowbit0, lowbit1;
+int h0, hx, hy, hc;
+int s10, s00;
+int *tmp;
+
+ /*
+ * log2n is log2 of max(nx,ny) rounded up to next power of 2
+ */
+ nmax = (nx>ny) ? nx : ny;
+ log2n = (int) (log((float) nmax)/log(2.0)+0.5);
+ if ( nmax > (1<<log2n) ) {
+ log2n += 1;
+ }
+ /*
+ * get temporary storage for shuffling elements
+ */
+ tmp = (int *) malloc(((nmax+1)/2)*sizeof(int));
+ if (tmp == (int *) NULL) {
+ ffpmsg("hinv: insufficient memory");
+ return(DATA_DECOMPRESSION_ERR);
+ }
+ /*
+ * set up masks, rounding parameters
+ */
+ shift = 1;
+ bit0 = 1 << (log2n - 1);
+ bit1 = bit0 << 1;
+ bit2 = bit0 << 2;
+ mask0 = -bit0;
+ mask1 = mask0 << 1;
+ mask2 = mask0 << 2;
+ prnd0 = bit0 >> 1;
+ prnd1 = bit1 >> 1;
+ prnd2 = bit2 >> 1;
+ nrnd0 = prnd0 - 1;
+ nrnd1 = prnd1 - 1;
+ nrnd2 = prnd2 - 1;
+ /*
+ * round h0 to multiple of bit2
+ */
+ a[0] = (a[0] + ((a[0] >= 0) ? prnd2 : nrnd2)) & mask2;
+ /*
+ * do log2n expansions
+ *
+ * We're indexing a as a 2-D array with dimensions (nx,ny).
+ */
+ nxtop = 1;
+ nytop = 1;
+ nxf = nx;
+ nyf = ny;
+ c = 1<<log2n;
+ for (k = log2n-1; k>=0; k--) {
+ /*
+ * this somewhat cryptic code generates the sequence
+ * ntop[k-1] = (ntop[k]+1)/2, where ntop[log2n] = n
+ */
+ c = c>>1;
+ nxtop = nxtop<<1;
+ nytop = nytop<<1;
+ if (nxf <= c) { nxtop -= 1; } else { nxf -= c; }
+ if (nyf <= c) { nytop -= 1; } else { nyf -= c; }
+ /*
+ * double shift and fix nrnd0 (because prnd0=0) on last pass
+ */
+ if (k == 0) {
+ nrnd0 = 0;
+ shift = 2;
+ }
+ /*
+ * unshuffle in each dimension to interleave coefficients
+ */
+ for (i = 0; i<nxtop; i++) {
+ unshuffle(&a[ny*i],nytop,1,tmp);
+ }
+ for (j = 0; j<nytop; j++) {
+ unshuffle(&a[j],nxtop,ny,tmp);
+ }
+ /*
+ * smooth by interpolating coefficients if SMOOTH != 0
+ */
+ if (smooth) hsmooth(a,nxtop,nytop,ny,scale);
+ oddx = nxtop % 2;
+ oddy = nytop % 2;
+ for (i = 0; i<nxtop-oddx; i += 2) {
+ s00 = ny*i; /* s00 is index of a[i,j] */
+ s10 = s00+ny; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<nytop-oddy; j += 2) {
+ h0 = a[s00 ];
+ hx = a[s10 ];
+ hy = a[s00+1];
+ hc = a[s10+1];
+ /*
+ * round hx and hy to multiple of bit1, hc to multiple of bit0
+ * h0 is already a multiple of bit2
+ */
+ hx = (hx + ((hx >= 0) ? prnd1 : nrnd1)) & mask1;
+ hy = (hy + ((hy >= 0) ? prnd1 : nrnd1)) & mask1;
+ hc = (hc + ((hc >= 0) ? prnd0 : nrnd0)) & mask0;
+ /*
+ * propagate bit0 of hc to hx,hy
+ */
+ lowbit0 = hc & bit0;
+ hx = (hx >= 0) ? (hx - lowbit0) : (hx + lowbit0);
+ hy = (hy >= 0) ? (hy - lowbit0) : (hy + lowbit0);
+ /*
+ * Propagate bits 0 and 1 of hc,hx,hy to h0.
+ * This could be simplified if we assume h0>0, but then
+ * the inversion would not be lossless for images with
+ * negative pixels.
+ */
+ lowbit1 = (hc ^ hx ^ hy) & bit1;
+ h0 = (h0 >= 0)
+ ? (h0 + lowbit0 - lowbit1)
+ : (h0 + ((lowbit0 == 0) ? lowbit1 : (lowbit0-lowbit1)));
+ /*
+ * Divide sums by 2 (4 last time)
+ */
+ a[s10+1] = (h0 + hx + hy + hc) >> shift;
+ a[s10 ] = (h0 + hx - hy - hc) >> shift;
+ a[s00+1] = (h0 - hx + hy - hc) >> shift;
+ a[s00 ] = (h0 - hx - hy + hc) >> shift;
+ s00 += 2;
+ s10 += 2;
+ }
+ if (oddy) {
+ /*
+ * do last element in row if row length is odd
+ * s00+1, s10+1 are off edge
+ */
+ h0 = a[s00 ];
+ hx = a[s10 ];
+ hx = ((hx >= 0) ? (hx+prnd1) : (hx+nrnd1)) & mask1;
+ lowbit1 = hx & bit1;
+ h0 = (h0 >= 0) ? (h0 - lowbit1) : (h0 + lowbit1);
+ a[s10 ] = (h0 + hx) >> shift;
+ a[s00 ] = (h0 - hx) >> shift;
+ }
+ }
+ if (oddx) {
+ /*
+ * do last row if column length is odd
+ * s10, s10+1 are off edge
+ */
+ s00 = ny*i;
+ for (j = 0; j<nytop-oddy; j += 2) {
+ h0 = a[s00 ];
+ hy = a[s00+1];
+ hy = ((hy >= 0) ? (hy+prnd1) : (hy+nrnd1)) & mask1;
+ lowbit1 = hy & bit1;
+ h0 = (h0 >= 0) ? (h0 - lowbit1) : (h0 + lowbit1);
+ a[s00+1] = (h0 + hy) >> shift;
+ a[s00 ] = (h0 - hy) >> shift;
+ s00 += 2;
+ }
+ if (oddy) {
+ /*
+ * do corner element if both row and column lengths are odd
+ * s00+1, s10, s10+1 are off edge
+ */
+ h0 = a[s00 ];
+ a[s00 ] = h0 >> shift;
+ }
+ }
+ /*
+ * divide all the masks and rounding values by 2
+ */
+ bit2 = bit1;
+ bit1 = bit0;
+ bit0 = bit0 >> 1;
+ mask1 = mask0;
+ mask0 = mask0 >> 1;
+ prnd1 = prnd0;
+ prnd0 = prnd0 >> 1;
+ nrnd1 = nrnd0;
+ nrnd0 = prnd0 - 1;
+ }
+ free(tmp);
+ return(0);
+}
+/* ############################################################################ */
+static int
+hinv64(LONGLONG a[], int nx, int ny, int smooth ,int scale)
+/*
+int smooth; 0 for no smoothing, else smooth during inversion
+int scale; used if smoothing is specified
+*/
+{
+int nmax, log2n, i, j, k;
+int nxtop,nytop,nxf,nyf,c;
+int oddx,oddy;
+int shift;
+LONGLONG mask0, mask1, mask2, prnd0, prnd1, prnd2, bit0, bit1, bit2;
+LONGLONG nrnd0, nrnd1, nrnd2, lowbit0, lowbit1;
+LONGLONG h0, hx, hy, hc;
+int s10, s00;
+LONGLONG *tmp;
+
+ /*
+ * log2n is log2 of max(nx,ny) rounded up to next power of 2
+ */
+ nmax = (nx>ny) ? nx : ny;
+ log2n = (int) (log((float) nmax)/log(2.0)+0.5);
+ if ( nmax > (1<<log2n) ) {
+ log2n += 1;
+ }
+ /*
+ * get temporary storage for shuffling elements
+ */
+ tmp = (LONGLONG *) malloc(((nmax+1)/2)*sizeof(LONGLONG));
+ if (tmp == (LONGLONG *) NULL) {
+ ffpmsg("hinv64: insufficient memory");
+ return(DATA_DECOMPRESSION_ERR);
+ }
+ /*
+ * set up masks, rounding parameters
+ */
+ shift = 1;
+ bit0 = ((LONGLONG) 1) << (log2n - 1);
+ bit1 = bit0 << 1;
+ bit2 = bit0 << 2;
+ mask0 = -bit0;
+ mask1 = mask0 << 1;
+ mask2 = mask0 << 2;
+ prnd0 = bit0 >> 1;
+ prnd1 = bit1 >> 1;
+ prnd2 = bit2 >> 1;
+ nrnd0 = prnd0 - 1;
+ nrnd1 = prnd1 - 1;
+ nrnd2 = prnd2 - 1;
+ /*
+ * round h0 to multiple of bit2
+ */
+ a[0] = (a[0] + ((a[0] >= 0) ? prnd2 : nrnd2)) & mask2;
+ /*
+ * do log2n expansions
+ *
+ * We're indexing a as a 2-D array with dimensions (nx,ny).
+ */
+ nxtop = 1;
+ nytop = 1;
+ nxf = nx;
+ nyf = ny;
+ c = 1<<log2n;
+ for (k = log2n-1; k>=0; k--) {
+ /*
+ * this somewhat cryptic code generates the sequence
+ * ntop[k-1] = (ntop[k]+1)/2, where ntop[log2n] = n
+ */
+ c = c>>1;
+ nxtop = nxtop<<1;
+ nytop = nytop<<1;
+ if (nxf <= c) { nxtop -= 1; } else { nxf -= c; }
+ if (nyf <= c) { nytop -= 1; } else { nyf -= c; }
+ /*
+ * double shift and fix nrnd0 (because prnd0=0) on last pass
+ */
+ if (k == 0) {
+ nrnd0 = 0;
+ shift = 2;
+ }
+ /*
+ * unshuffle in each dimension to interleave coefficients
+ */
+ for (i = 0; i<nxtop; i++) {
+ unshuffle64(&a[ny*i],nytop,1,tmp);
+ }
+ for (j = 0; j<nytop; j++) {
+ unshuffle64(&a[j],nxtop,ny,tmp);
+ }
+ /*
+ * smooth by interpolating coefficients if SMOOTH != 0
+ */
+ if (smooth) hsmooth64(a,nxtop,nytop,ny,scale);
+ oddx = nxtop % 2;
+ oddy = nytop % 2;
+ for (i = 0; i<nxtop-oddx; i += 2) {
+ s00 = ny*i; /* s00 is index of a[i,j] */
+ s10 = s00+ny; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<nytop-oddy; j += 2) {
+ h0 = a[s00 ];
+ hx = a[s10 ];
+ hy = a[s00+1];
+ hc = a[s10+1];
+ /*
+ * round hx and hy to multiple of bit1, hc to multiple of bit0
+ * h0 is already a multiple of bit2
+ */
+ hx = (hx + ((hx >= 0) ? prnd1 : nrnd1)) & mask1;
+ hy = (hy + ((hy >= 0) ? prnd1 : nrnd1)) & mask1;
+ hc = (hc + ((hc >= 0) ? prnd0 : nrnd0)) & mask0;
+ /*
+ * propagate bit0 of hc to hx,hy
+ */
+ lowbit0 = hc & bit0;
+ hx = (hx >= 0) ? (hx - lowbit0) : (hx + lowbit0);
+ hy = (hy >= 0) ? (hy - lowbit0) : (hy + lowbit0);
+ /*
+ * Propagate bits 0 and 1 of hc,hx,hy to h0.
+ * This could be simplified if we assume h0>0, but then
+ * the inversion would not be lossless for images with
+ * negative pixels.
+ */
+ lowbit1 = (hc ^ hx ^ hy) & bit1;
+ h0 = (h0 >= 0)
+ ? (h0 + lowbit0 - lowbit1)
+ : (h0 + ((lowbit0 == 0) ? lowbit1 : (lowbit0-lowbit1)));
+ /*
+ * Divide sums by 2 (4 last time)
+ */
+ a[s10+1] = (h0 + hx + hy + hc) >> shift;
+ a[s10 ] = (h0 + hx - hy - hc) >> shift;
+ a[s00+1] = (h0 - hx + hy - hc) >> shift;
+ a[s00 ] = (h0 - hx - hy + hc) >> shift;
+ s00 += 2;
+ s10 += 2;
+ }
+ if (oddy) {
+ /*
+ * do last element in row if row length is odd
+ * s00+1, s10+1 are off edge
+ */
+ h0 = a[s00 ];
+ hx = a[s10 ];
+ hx = ((hx >= 0) ? (hx+prnd1) : (hx+nrnd1)) & mask1;
+ lowbit1 = hx & bit1;
+ h0 = (h0 >= 0) ? (h0 - lowbit1) : (h0 + lowbit1);
+ a[s10 ] = (h0 + hx) >> shift;
+ a[s00 ] = (h0 - hx) >> shift;
+ }
+ }
+ if (oddx) {
+ /*
+ * do last row if column length is odd
+ * s10, s10+1 are off edge
+ */
+ s00 = ny*i;
+ for (j = 0; j<nytop-oddy; j += 2) {
+ h0 = a[s00 ];
+ hy = a[s00+1];
+ hy = ((hy >= 0) ? (hy+prnd1) : (hy+nrnd1)) & mask1;
+ lowbit1 = hy & bit1;
+ h0 = (h0 >= 0) ? (h0 - lowbit1) : (h0 + lowbit1);
+ a[s00+1] = (h0 + hy) >> shift;
+ a[s00 ] = (h0 - hy) >> shift;
+ s00 += 2;
+ }
+ if (oddy) {
+ /*
+ * do corner element if both row and column lengths are odd
+ * s00+1, s10, s10+1 are off edge
+ */
+ h0 = a[s00 ];
+ a[s00 ] = h0 >> shift;
+ }
+ }
+ /*
+ * divide all the masks and rounding values by 2
+ */
+ bit2 = bit1;
+ bit1 = bit0;
+ bit0 = bit0 >> 1;
+ mask1 = mask0;
+ mask0 = mask0 >> 1;
+ prnd1 = prnd0;
+ prnd0 = prnd0 >> 1;
+ nrnd1 = nrnd0;
+ nrnd0 = prnd0 - 1;
+ }
+ free(tmp);
+ return(0);
+}
+
+/* ############################################################################ */
+static void
+unshuffle(int a[], int n, int n2, int tmp[])
+/*
+int a[]; array to shuffle
+int n; number of elements to shuffle
+int n2; second dimension
+int tmp[]; scratch storage
+*/
+{
+int i;
+int nhalf;
+int *p1, *p2, *pt;
+
+ /*
+ * copy 2nd half of array to tmp
+ */
+ nhalf = (n+1)>>1;
+ pt = tmp;
+ p1 = &a[n2*nhalf]; /* pointer to a[i] */
+ for (i=nhalf; i<n; i++) {
+ *pt = *p1;
+ p1 += n2;
+ pt += 1;
+ }
+ /*
+ * distribute 1st half of array to even elements
+ */
+ p2 = &a[ n2*(nhalf-1) ]; /* pointer to a[i] */
+ p1 = &a[(n2*(nhalf-1))<<1]; /* pointer to a[2*i] */
+ for (i=nhalf-1; i >= 0; i--) {
+ *p1 = *p2;
+ p2 -= n2;
+ p1 -= (n2+n2);
+ }
+ /*
+ * now distribute 2nd half of array (in tmp) to odd elements
+ */
+ pt = tmp;
+ p1 = &a[n2]; /* pointer to a[i] */
+ for (i=1; i<n; i += 2) {
+ *p1 = *pt;
+ p1 += (n2+n2);
+ pt += 1;
+ }
+}
+/* ############################################################################ */
+static void
+unshuffle64(LONGLONG a[], int n, int n2, LONGLONG tmp[])
+/*
+LONGLONG a[]; array to shuffle
+int n; number of elements to shuffle
+int n2; second dimension
+LONGLONG tmp[]; scratch storage
+*/
+{
+int i;
+int nhalf;
+LONGLONG *p1, *p2, *pt;
+
+ /*
+ * copy 2nd half of array to tmp
+ */
+ nhalf = (n+1)>>1;
+ pt = tmp;
+ p1 = &a[n2*nhalf]; /* pointer to a[i] */
+ for (i=nhalf; i<n; i++) {
+ *pt = *p1;
+ p1 += n2;
+ pt += 1;
+ }
+ /*
+ * distribute 1st half of array to even elements
+ */
+ p2 = &a[ n2*(nhalf-1) ]; /* pointer to a[i] */
+ p1 = &a[(n2*(nhalf-1))<<1]; /* pointer to a[2*i] */
+ for (i=nhalf-1; i >= 0; i--) {
+ *p1 = *p2;
+ p2 -= n2;
+ p1 -= (n2+n2);
+ }
+ /*
+ * now distribute 2nd half of array (in tmp) to odd elements
+ */
+ pt = tmp;
+ p1 = &a[n2]; /* pointer to a[i] */
+ for (i=1; i<n; i += 2) {
+ *p1 = *pt;
+ p1 += (n2+n2);
+ pt += 1;
+ }
+}
+
+/* ############################################################################ */
+/* ############################################################################ */
+
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* hsmooth.c Smooth H-transform image by adjusting coefficients toward
+ * interpolated values
+ *
+ * Programmer: R. White Date: 13 April 1992
+ */
+
+/* ############################################################################ */
+static void
+hsmooth(int a[], int nxtop, int nytop, int ny, int scale)
+/*
+int a[]; array of H-transform coefficients
+int nxtop,nytop; size of coefficient block to use
+int ny; actual 1st dimension of array
+int scale; truncation scale factor that was used
+*/
+{
+int i, j;
+int ny2, s10, s00, diff, dmax, dmin, s, smax;
+int hm, h0, hp, hmm, hpm, hmp, hpp, hx2, hy2;
+int m1,m2;
+
+ /*
+ * Maximum change in coefficients is determined by scale factor.
+ * Since we rounded during division (see digitize.c), the biggest
+ * permitted change is scale/2.
+ */
+ smax = (scale >> 1);
+ if (smax <= 0) return;
+ ny2 = ny << 1;
+ /*
+ * We're indexing a as a 2-D array with dimensions (nxtop,ny) of which
+ * only (nxtop,nytop) are used. The coefficients on the edge of the
+ * array are not adjusted (which is why the loops below start at 2
+ * instead of 0 and end at nxtop-2 instead of nxtop.)
+ */
+ /*
+ * Adjust x difference hx
+ */
+ for (i = 2; i<nxtop-2; i += 2) {
+ s00 = ny*i; /* s00 is index of a[i,j] */
+ s10 = s00+ny; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<nytop; j += 2) {
+ /*
+ * hp is h0 (mean value) in next x zone, hm is h0 in previous x zone
+ */
+ hm = a[s00-ny2];
+ h0 = a[s00];
+ hp = a[s00+ny2];
+ /*
+ * diff = 8 * hx slope that would match h0 in neighboring zones
+ */
+ diff = hp-hm;
+ /*
+ * monotonicity constraints on diff
+ */
+ dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
+ dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
+ /*
+ * if monotonicity would set slope = 0 then don't change hx.
+ * note dmax>=0, dmin<=0.
+ */
+ if (dmin < dmax) {
+ diff = max( min(diff, dmax), dmin);
+ /*
+ * Compute change in slope limited to range +/- smax.
+ * Careful with rounding negative numbers when using
+ * shift for divide by 8.
+ */
+ s = diff-(a[s10]<<3);
+ s = (s>=0) ? (s>>3) : ((s+7)>>3) ;
+ s = max( min(s, smax), -smax);
+ a[s10] = a[s10]+s;
+ }
+ s00 += 2;
+ s10 += 2;
+ }
+ }
+ /*
+ * Adjust y difference hy
+ */
+ for (i = 0; i<nxtop; i += 2) {
+ s00 = ny*i+2;
+ s10 = s00+ny;
+ for (j = 2; j<nytop-2; j += 2) {
+ hm = a[s00-2];
+ h0 = a[s00];
+ hp = a[s00+2];
+ diff = hp-hm;
+ dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
+ dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
+ if (dmin < dmax) {
+ diff = max( min(diff, dmax), dmin);
+ s = diff-(a[s00+1]<<3);
+ s = (s>=0) ? (s>>3) : ((s+7)>>3) ;
+ s = max( min(s, smax), -smax);
+ a[s00+1] = a[s00+1]+s;
+ }
+ s00 += 2;
+ s10 += 2;
+ }
+ }
+ /*
+ * Adjust curvature difference hc
+ */
+ for (i = 2; i<nxtop-2; i += 2) {
+ s00 = ny*i+2;
+ s10 = s00+ny;
+ for (j = 2; j<nytop-2; j += 2) {
+ /*
+ * ------------------ y
+ * | hmp | | hpp | |
+ * ------------------ |
+ * | | h0 | | |
+ * ------------------ -------x
+ * | hmm | | hpm |
+ * ------------------
+ */
+ hmm = a[s00-ny2-2];
+ hpm = a[s00+ny2-2];
+ hmp = a[s00-ny2+2];
+ hpp = a[s00+ny2+2];
+ h0 = a[s00];
+ /*
+ * diff = 64 * hc value that would match h0 in neighboring zones
+ */
+ diff = hpp + hmm - hmp - hpm;
+ /*
+ * 2 times x,y slopes in this zone
+ */
+ hx2 = a[s10 ]<<1;
+ hy2 = a[s00+1]<<1;
+ /*
+ * monotonicity constraints on diff
+ */
+ m1 = min(max(hpp-h0,0)-hx2-hy2, max(h0-hpm,0)+hx2-hy2);
+ m2 = min(max(h0-hmp,0)-hx2+hy2, max(hmm-h0,0)+hx2+hy2);
+ dmax = min(m1,m2) << 4;
+ m1 = max(min(hpp-h0,0)-hx2-hy2, min(h0-hpm,0)+hx2-hy2);
+ m2 = max(min(h0-hmp,0)-hx2+hy2, min(hmm-h0,0)+hx2+hy2);
+ dmin = max(m1,m2) << 4;
+ /*
+ * if monotonicity would set slope = 0 then don't change hc.
+ * note dmax>=0, dmin<=0.
+ */
+ if (dmin < dmax) {
+ diff = max( min(diff, dmax), dmin);
+ /*
+ * Compute change in slope limited to range +/- smax.
+ * Careful with rounding negative numbers when using
+ * shift for divide by 64.
+ */
+ s = diff-(a[s10+1]<<6);
+ s = (s>=0) ? (s>>6) : ((s+63)>>6) ;
+ s = max( min(s, smax), -smax);
+ a[s10+1] = a[s10+1]+s;
+ }
+ s00 += 2;
+ s10 += 2;
+ }
+ }
+}
+/* ############################################################################ */
+static void
+hsmooth64(LONGLONG a[], int nxtop, int nytop, int ny, int scale)
+/*
+LONGLONG a[]; array of H-transform coefficients
+int nxtop,nytop; size of coefficient block to use
+int ny; actual 1st dimension of array
+int scale; truncation scale factor that was used
+*/
+{
+int i, j;
+int ny2, s10, s00;
+LONGLONG hm, h0, hp, hmm, hpm, hmp, hpp, hx2, hy2, diff, dmax, dmin, s, smax, m1, m2;
+
+ /*
+ * Maximum change in coefficients is determined by scale factor.
+ * Since we rounded during division (see digitize.c), the biggest
+ * permitted change is scale/2.
+ */
+ smax = (scale >> 1);
+ if (smax <= 0) return;
+ ny2 = ny << 1;
+ /*
+ * We're indexing a as a 2-D array with dimensions (nxtop,ny) of which
+ * only (nxtop,nytop) are used. The coefficients on the edge of the
+ * array are not adjusted (which is why the loops below start at 2
+ * instead of 0 and end at nxtop-2 instead of nxtop.)
+ */
+ /*
+ * Adjust x difference hx
+ */
+ for (i = 2; i<nxtop-2; i += 2) {
+ s00 = ny*i; /* s00 is index of a[i,j] */
+ s10 = s00+ny; /* s10 is index of a[i+1,j] */
+ for (j = 0; j<nytop; j += 2) {
+ /*
+ * hp is h0 (mean value) in next x zone, hm is h0 in previous x zone
+ */
+ hm = a[s00-ny2];
+ h0 = a[s00];
+ hp = a[s00+ny2];
+ /*
+ * diff = 8 * hx slope that would match h0 in neighboring zones
+ */
+ diff = hp-hm;
+ /*
+ * monotonicity constraints on diff
+ */
+ dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
+ dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
+ /*
+ * if monotonicity would set slope = 0 then don't change hx.
+ * note dmax>=0, dmin<=0.
+ */
+ if (dmin < dmax) {
+ diff = max( min(diff, dmax), dmin);
+ /*
+ * Compute change in slope limited to range +/- smax.
+ * Careful with rounding negative numbers when using
+ * shift for divide by 8.
+ */
+ s = diff-(a[s10]<<3);
+ s = (s>=0) ? (s>>3) : ((s+7)>>3) ;
+ s = max( min(s, smax), -smax);
+ a[s10] = a[s10]+s;
+ }
+ s00 += 2;
+ s10 += 2;
+ }
+ }
+ /*
+ * Adjust y difference hy
+ */
+ for (i = 0; i<nxtop; i += 2) {
+ s00 = ny*i+2;
+ s10 = s00+ny;
+ for (j = 2; j<nytop-2; j += 2) {
+ hm = a[s00-2];
+ h0 = a[s00];
+ hp = a[s00+2];
+ diff = hp-hm;
+ dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
+ dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
+ if (dmin < dmax) {
+ diff = max( min(diff, dmax), dmin);
+ s = diff-(a[s00+1]<<3);
+ s = (s>=0) ? (s>>3) : ((s+7)>>3) ;
+ s = max( min(s, smax), -smax);
+ a[s00+1] = a[s00+1]+s;
+ }
+ s00 += 2;
+ s10 += 2;
+ }
+ }
+ /*
+ * Adjust curvature difference hc
+ */
+ for (i = 2; i<nxtop-2; i += 2) {
+ s00 = ny*i+2;
+ s10 = s00+ny;
+ for (j = 2; j<nytop-2; j += 2) {
+ /*
+ * ------------------ y
+ * | hmp | | hpp | |
+ * ------------------ |
+ * | | h0 | | |
+ * ------------------ -------x
+ * | hmm | | hpm |
+ * ------------------
+ */
+ hmm = a[s00-ny2-2];
+ hpm = a[s00+ny2-2];
+ hmp = a[s00-ny2+2];
+ hpp = a[s00+ny2+2];
+ h0 = a[s00];
+ /*
+ * diff = 64 * hc value that would match h0 in neighboring zones
+ */
+ diff = hpp + hmm - hmp - hpm;
+ /*
+ * 2 times x,y slopes in this zone
+ */
+ hx2 = a[s10 ]<<1;
+ hy2 = a[s00+1]<<1;
+ /*
+ * monotonicity constraints on diff
+ */
+ m1 = min(max(hpp-h0,0)-hx2-hy2, max(h0-hpm,0)+hx2-hy2);
+ m2 = min(max(h0-hmp,0)-hx2+hy2, max(hmm-h0,0)+hx2+hy2);
+ dmax = min(m1,m2) << 4;
+ m1 = max(min(hpp-h0,0)-hx2-hy2, min(h0-hpm,0)+hx2-hy2);
+ m2 = max(min(h0-hmp,0)-hx2+hy2, min(hmm-h0,0)+hx2+hy2);
+ dmin = max(m1,m2) << 4;
+ /*
+ * if monotonicity would set slope = 0 then don't change hc.
+ * note dmax>=0, dmin<=0.
+ */
+ if (dmin < dmax) {
+ diff = max( min(diff, dmax), dmin);
+ /*
+ * Compute change in slope limited to range +/- smax.
+ * Careful with rounding negative numbers when using
+ * shift for divide by 64.
+ */
+ s = diff-(a[s10+1]<<6);
+ s = (s>=0) ? (s>>6) : ((s+63)>>6) ;
+ s = max( min(s, smax), -smax);
+ a[s10+1] = a[s10+1]+s;
+ }
+ s00 += 2;
+ s10 += 2;
+ }
+ }
+}
+
+
+/* ############################################################################ */
+/* ############################################################################ */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* undigitize.c undigitize H-transform
+ *
+ * Programmer: R. White Date: 9 May 1991
+ */
+
+/* ############################################################################ */
+static void
+undigitize(int a[], int nx, int ny, int scale)
+{
+int *p;
+
+ /*
+ * multiply by scale
+ */
+ if (scale <= 1) return;
+ for (p=a; p <= &a[nx*ny-1]; p++) *p = (*p)*scale;
+}
+/* ############################################################################ */
+static void
+undigitize64(LONGLONG a[], int nx, int ny, int scale)
+{
+LONGLONG *p, scale64;
+
+ /*
+ * multiply by scale
+ */
+ if (scale <= 1) return;
+ scale64 = (LONGLONG) scale; /* use a 64-bit int for efficiency in the big loop */
+
+ for (p=a; p <= &a[nx*ny-1]; p++) *p = (*p)*scale64;
+}
+
+/* ############################################################################ */
+/* ############################################################################ */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* decode.c read codes from infile and construct array
+ *
+ * Programmer: R. White Date: 2 February 1994
+ */
+
+
+static char code_magic[2] = { (char)0xDD, (char)0x99 };
+
+/* ############################################################################ */
+static int decode(unsigned char *infile, int *a, int *nx, int *ny, int *scale)
+/*
+char *infile; input file
+int *a; address of output array [nx][ny]
+int *nx,*ny; size of output array
+int *scale; scale factor for digitization
+*/
+{
+LONGLONG sumall;
+int nel, stat;
+unsigned char nbitplanes[3];
+char tmagic[2];
+
+ /* initialize the byte read position to the beginning of the array */;
+ nextchar = 0;
+
+ /*
+ * File starts either with special 2-byte magic code or with
+ * FITS keyword "SIMPLE ="
+ */
+ qread(infile, tmagic, sizeof(tmagic));
+ /*
+ * check for correct magic code value
+ */
+ if (memcmp(tmagic,code_magic,sizeof(code_magic)) != 0) {
+ ffpmsg("bad file format");
+ return(DATA_DECOMPRESSION_ERR);
+ }
+ *nx =readint(infile); /* x size of image */
+ *ny =readint(infile); /* y size of image */
+ *scale=readint(infile); /* scale factor for digitization */
+
+ nel = (*nx) * (*ny);
+
+ /* sum of all pixels */
+ sumall=readlonglong(infile);
+ /* # bits in quadrants */
+
+ qread(infile, (char *) nbitplanes, sizeof(nbitplanes));
+
+ stat = dodecode(infile, a, *nx, *ny, nbitplanes);
+ /*
+ * put sum of all pixels back into pixel 0
+ */
+ a[0] = (int) sumall;
+ return(stat);
+}
+/* ############################################################################ */
+static int decode64(unsigned char *infile, LONGLONG *a, int *nx, int *ny, int *scale)
+/*
+char *infile; input file
+LONGLONG *a; address of output array [nx][ny]
+int *nx,*ny; size of output array
+int *scale; scale factor for digitization
+*/
+{
+int nel, stat;
+LONGLONG sumall;
+unsigned char nbitplanes[3];
+char tmagic[2];
+
+ /* initialize the byte read position to the beginning of the array */;
+ nextchar = 0;
+
+ /*
+ * File starts either with special 2-byte magic code or with
+ * FITS keyword "SIMPLE ="
+ */
+ qread(infile, tmagic, sizeof(tmagic));
+ /*
+ * check for correct magic code value
+ */
+ if (memcmp(tmagic,code_magic,sizeof(code_magic)) != 0) {
+ ffpmsg("bad file format");
+ return(DATA_DECOMPRESSION_ERR);
+ }
+ *nx =readint(infile); /* x size of image */
+ *ny =readint(infile); /* y size of image */
+ *scale=readint(infile); /* scale factor for digitization */
+
+ nel = (*nx) * (*ny);
+
+ /* sum of all pixels */
+ sumall=readlonglong(infile);
+ /* # bits in quadrants */
+
+ qread(infile, (char *) nbitplanes, sizeof(nbitplanes));
+
+ stat = dodecode64(infile, a, *nx, *ny, nbitplanes);
+ /*
+ * put sum of all pixels back into pixel 0
+ */
+ a[0] = sumall;
+
+ return(stat);
+}
+
+
+/* ############################################################################ */
+/* ############################################################################ */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* dodecode.c Decode stream of characters on infile and return array
+ *
+ * This version encodes the different quadrants separately
+ *
+ * Programmer: R. White Date: 9 May 1991
+ */
+
+/* ############################################################################ */
+static int
+dodecode(unsigned char *infile, int a[], int nx, int ny, unsigned char nbitplanes[3])
+
+/* int a[];
+ int nx,ny; Array dimensions are [nx][ny]
+ unsigned char nbitplanes[3]; Number of bit planes in quadrants
+*/
+{
+int i, nel, nx2, ny2, stat;
+
+ nel = nx*ny;
+ nx2 = (nx+1)/2;
+ ny2 = (ny+1)/2;
+
+ /*
+ * initialize a to zero
+ */
+ for (i=0; i<nel; i++) a[i] = 0;
+ /*
+ * Initialize bit input
+ */
+ start_inputing_bits();
+ /*
+ * read bit planes for each quadrant
+ */
+ stat = qtree_decode(infile, &a[0], ny, nx2, ny2, nbitplanes[0]);
+ if (stat) return(stat);
+
+ stat = qtree_decode(infile, &a[ny2], ny, nx2, ny/2, nbitplanes[1]);
+ if (stat) return(stat);
+
+ stat = qtree_decode(infile, &a[ny*nx2], ny, nx/2, ny2, nbitplanes[1]);
+ if (stat) return(stat);
+
+ stat = qtree_decode(infile, &a[ny*nx2+ny2], ny, nx/2, ny/2, nbitplanes[2]);
+ if (stat) return(stat);
+
+ /*
+ * make sure there is an EOF symbol (nybble=0) at end
+ */
+ if (input_nybble(infile) != 0) {
+ ffpmsg("dodecode: bad bit plane values");
+ return(DATA_DECOMPRESSION_ERR);
+ }
+ /*
+ * now get the sign bits
+ * Re-initialize bit input
+ */
+ start_inputing_bits();
+ for (i=0; i<nel; i++) {
+ if (a[i]) {
+ /* tried putting the input_bit code in-line here, instead of */
+ /* calling the function, but it made no difference in the speed */
+ if (input_bit(infile)) a[i] = -a[i];
+ }
+ }
+ return(0);
+}
+/* ############################################################################ */
+static int
+dodecode64(unsigned char *infile, LONGLONG a[], int nx, int ny, unsigned char nbitplanes[3])
+
+/* LONGLONG a[];
+ int nx,ny; Array dimensions are [nx][ny]
+ unsigned char nbitplanes[3]; Number of bit planes in quadrants
+*/
+{
+int i, nel, nx2, ny2, stat;
+
+ nel = nx*ny;
+ nx2 = (nx+1)/2;
+ ny2 = (ny+1)/2;
+
+ /*
+ * initialize a to zero
+ */
+ for (i=0; i<nel; i++) a[i] = 0;
+ /*
+ * Initialize bit input
+ */
+ start_inputing_bits();
+ /*
+ * read bit planes for each quadrant
+ */
+ stat = qtree_decode64(infile, &a[0], ny, nx2, ny2, nbitplanes[0]);
+ if (stat) return(stat);
+
+ stat = qtree_decode64(infile, &a[ny2], ny, nx2, ny/2, nbitplanes[1]);
+ if (stat) return(stat);
+
+ stat = qtree_decode64(infile, &a[ny*nx2], ny, nx/2, ny2, nbitplanes[1]);
+ if (stat) return(stat);
+
+ stat = qtree_decode64(infile, &a[ny*nx2+ny2], ny, nx/2, ny/2, nbitplanes[2]);
+ if (stat) return(stat);
+
+ /*
+ * make sure there is an EOF symbol (nybble=0) at end
+ */
+ if (input_nybble(infile) != 0) {
+ ffpmsg("dodecode64: bad bit plane values");
+ return(DATA_DECOMPRESSION_ERR);
+ }
+ /*
+ * now get the sign bits
+ * Re-initialize bit input
+ */
+ start_inputing_bits();
+ for (i=0; i<nel; i++) {
+ if (a[i]) {
+ if (input_bit(infile) != 0) a[i] = -a[i];
+ }
+ }
+ return(0);
+}
+
+/* ############################################################################ */
+/* ############################################################################ */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* qtree_decode.c Read stream of codes from infile and construct bit planes
+ * in quadrant of 2-D array using binary quadtree coding
+ *
+ * Programmer: R. White Date: 7 May 1991
+ */
+
+/* ############################################################################ */
+static int
+qtree_decode(unsigned char *infile, int a[], int n, int nqx, int nqy, int nbitplanes)
+
+/*
+char *infile;
+int a[]; a is 2-D array with dimensions (n,n)
+int n; length of full row in a
+int nqx; partial length of row to decode
+int nqy; partial length of column (<=n)
+int nbitplanes; number of bitplanes to decode
+*/
+{
+int log2n, k, bit, b, nqmax;
+int nx,ny,nfx,nfy,c;
+int nqx2, nqy2;
+unsigned char *scratch;
+
+ /*
+ * log2n is log2 of max(nqx,nqy) rounded up to next power of 2
+ */
+ nqmax = (nqx>nqy) ? nqx : nqy;
+ log2n = (int) (log((float) nqmax)/log(2.0)+0.5);
+ if (nqmax > (1<<log2n)) {
+ log2n += 1;
+ }
+ /*
+ * allocate scratch array for working space
+ */
+ nqx2=(nqx+1)/2;
+ nqy2=(nqy+1)/2;
+ scratch = (unsigned char *) malloc(nqx2*nqy2);
+ if (scratch == (unsigned char *) NULL) {
+ ffpmsg("qtree_decode: insufficient memory");
+ return(DATA_DECOMPRESSION_ERR);
+ }
+ /*
+ * now decode each bit plane, starting at the top
+ * A is assumed to be initialized to zero
+ */
+ for (bit = nbitplanes-1; bit >= 0; bit--) {
+ /*
+ * Was bitplane was quadtree-coded or written directly?
+ */
+ b = input_nybble(infile);
+
+ if(b == 0) {
+ /*
+ * bit map was written directly
+ */
+ read_bdirect(infile,a,n,nqx,nqy,scratch,bit);
+ } else if (b != 0xf) {
+ ffpmsg("qtree_decode: bad format code");
+ return(DATA_DECOMPRESSION_ERR);
+ } else {
+ /*
+ * bitmap was quadtree-coded, do log2n expansions
+ *
+ * read first code
+ */
+ scratch[0] = input_huffman(infile);
+ /*
+ * now do log2n expansions, reading codes from file as necessary
+ */
+ nx = 1;
+ ny = 1;
+ nfx = nqx;
+ nfy = nqy;
+ c = 1<<log2n;
+ for (k = 1; k<log2n; k++) {
+ /*
+ * this somewhat cryptic code generates the sequence
+ * n[k-1] = (n[k]+1)/2 where n[log2n]=nqx or nqy
+ */
+ c = c>>1;
+ nx = nx<<1;
+ ny = ny<<1;
+ if (nfx <= c) { nx -= 1; } else { nfx -= c; }
+ if (nfy <= c) { ny -= 1; } else { nfy -= c; }
+ qtree_expand(infile,scratch,nx,ny,scratch);
+ }
+ /*
+ * now copy last set of 4-bit codes to bitplane bit of array a
+ */
+ qtree_bitins(scratch,nqx,nqy,a,n,bit);
+ }
+ }
+ free(scratch);
+ return(0);
+}
+/* ############################################################################ */
+static int
+qtree_decode64(unsigned char *infile, LONGLONG a[], int n, int nqx, int nqy, int nbitplanes)
+
+/*
+char *infile;
+LONGLONG a[]; a is 2-D array with dimensions (n,n)
+int n; length of full row in a
+int nqx; partial length of row to decode
+int nqy; partial length of column (<=n)
+int nbitplanes; number of bitplanes to decode
+*/
+{
+int log2n, k, bit, b, nqmax;
+int nx,ny,nfx,nfy,c;
+int nqx2, nqy2;
+unsigned char *scratch;
+
+ /*
+ * log2n is log2 of max(nqx,nqy) rounded up to next power of 2
+ */
+ nqmax = (nqx>nqy) ? nqx : nqy;
+ log2n = (int) (log((float) nqmax)/log(2.0)+0.5);
+ if (nqmax > (1<<log2n)) {
+ log2n += 1;
+ }
+ /*
+ * allocate scratch array for working space
+ */
+ nqx2=(nqx+1)/2;
+ nqy2=(nqy+1)/2;
+ scratch = (unsigned char *) malloc(nqx2*nqy2);
+ if (scratch == (unsigned char *) NULL) {
+ ffpmsg("qtree_decode64: insufficient memory");
+ return(DATA_DECOMPRESSION_ERR);
+ }
+ /*
+ * now decode each bit plane, starting at the top
+ * A is assumed to be initialized to zero
+ */
+ for (bit = nbitplanes-1; bit >= 0; bit--) {
+ /*
+ * Was bitplane was quadtree-coded or written directly?
+ */
+ b = input_nybble(infile);
+
+ if(b == 0) {
+ /*
+ * bit map was written directly
+ */
+ read_bdirect64(infile,a,n,nqx,nqy,scratch,bit);
+ } else if (b != 0xf) {
+ ffpmsg("qtree_decode64: bad format code");
+ return(DATA_DECOMPRESSION_ERR);
+ } else {
+ /*
+ * bitmap was quadtree-coded, do log2n expansions
+ *
+ * read first code
+ */
+ scratch[0] = input_huffman(infile);
+ /*
+ * now do log2n expansions, reading codes from file as necessary
+ */
+ nx = 1;
+ ny = 1;
+ nfx = nqx;
+ nfy = nqy;
+ c = 1<<log2n;
+ for (k = 1; k<log2n; k++) {
+ /*
+ * this somewhat cryptic code generates the sequence
+ * n[k-1] = (n[k]+1)/2 where n[log2n]=nqx or nqy
+ */
+ c = c>>1;
+ nx = nx<<1;
+ ny = ny<<1;
+ if (nfx <= c) { nx -= 1; } else { nfx -= c; }
+ if (nfy <= c) { ny -= 1; } else { nfy -= c; }
+ qtree_expand(infile,scratch,nx,ny,scratch);
+ }
+ /*
+ * now copy last set of 4-bit codes to bitplane bit of array a
+ */
+ qtree_bitins64(scratch,nqx,nqy,a,n,bit);
+ }
+ }
+ free(scratch);
+ return(0);
+}
+
+
+/* ############################################################################ */
+/*
+ * do one quadtree expansion step on array a[(nqx+1)/2,(nqy+1)/2]
+ * results put into b[nqx,nqy] (which may be the same as a)
+ */
+static void
+qtree_expand(unsigned char *infile, unsigned char a[], int nx, int ny, unsigned char b[])
+{
+int i;
+
+ /*
+ * first copy a to b, expanding each 4-bit value
+ */
+ qtree_copy(a,nx,ny,b,ny);
+ /*
+ * now read new 4-bit values into b for each non-zero element
+ */
+ for (i = nx*ny-1; i >= 0; i--) {
+ if (b[i]) b[i] = input_huffman(infile);
+ }
+}
+
+/* ############################################################################ */
+/*
+ * copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
+ * each value to 2x2 pixels
+ * a,b may be same array
+ */
+static void
+qtree_copy(unsigned char a[], int nx, int ny, unsigned char b[], int n)
+/* int n; declared y dimension of b */
+{
+int i, j, k, nx2, ny2;
+int s00, s10;
+
+ /*
+ * first copy 4-bit values to b
+ * start at end in case a,b are same array
+ */
+ nx2 = (nx+1)/2;
+ ny2 = (ny+1)/2;
+ k = ny2*(nx2-1)+ny2-1; /* k is index of a[i,j] */
+ for (i = nx2-1; i >= 0; i--) {
+ s00 = 2*(n*i+ny2-1); /* s00 is index of b[2*i,2*j] */
+ for (j = ny2-1; j >= 0; j--) {
+ b[s00] = a[k];
+ k -= 1;
+ s00 -= 2;
+ }
+ }
+ /*
+ * now expand each 2x2 block
+ */
+ for (i = 0; i<nx-1; i += 2) {
+
+ /* Note:
+ Unlike the case in qtree_bitins, this code runs faster on a 32-bit linux
+ machine using the s10 intermediate variable, rather that using s00+n.
+ Go figure!
+ */
+ s00 = n*i; /* s00 is index of b[i,j] */
+ s10 = s00+n; /* s10 is index of b[i+1,j] */
+
+ for (j = 0; j<ny-1; j += 2) {
+
+ switch (b[s00]) {
+ case(0):
+ b[s10+1] = 0;
+ b[s10 ] = 0;
+ b[s00+1] = 0;
+ b[s00 ] = 0;
+
+ break;
+ case(1):
+ b[s10+1] = 1;
+ b[s10 ] = 0;
+ b[s00+1] = 0;
+ b[s00 ] = 0;
+
+ break;
+ case(2):
+ b[s10+1] = 0;
+ b[s10 ] = 1;
+ b[s00+1] = 0;
+ b[s00 ] = 0;
+
+ break;
+ case(3):
+ b[s10+1] = 1;
+ b[s10 ] = 1;
+ b[s00+1] = 0;
+ b[s00 ] = 0;
+
+ break;
+ case(4):
+ b[s10+1] = 0;
+ b[s10 ] = 0;
+ b[s00+1] = 1;
+ b[s00 ] = 0;
+
+ break;
+ case(5):
+ b[s10+1] = 1;
+ b[s10 ] = 0;
+ b[s00+1] = 1;
+ b[s00 ] = 0;
+
+ break;
+ case(6):
+ b[s10+1] = 0;
+ b[s10 ] = 1;
+ b[s00+1] = 1;
+ b[s00 ] = 0;
+
+ break;
+ case(7):
+ b[s10+1] = 1;
+ b[s10 ] = 1;
+ b[s00+1] = 1;
+ b[s00 ] = 0;
+
+ break;
+ case(8):
+ b[s10+1] = 0;
+ b[s10 ] = 0;
+ b[s00+1] = 0;
+ b[s00 ] = 1;
+
+ break;
+ case(9):
+ b[s10+1] = 1;
+ b[s10 ] = 0;
+ b[s00+1] = 0;
+ b[s00 ] = 1;
+ break;
+ case(10):
+ b[s10+1] = 0;
+ b[s10 ] = 1;
+ b[s00+1] = 0;
+ b[s00 ] = 1;
+
+ break;
+ case(11):
+ b[s10+1] = 1;
+ b[s10 ] = 1;
+ b[s00+1] = 0;
+ b[s00 ] = 1;
+
+ break;
+ case(12):
+ b[s10+1] = 0;
+ b[s10 ] = 0;
+ b[s00+1] = 1;
+ b[s00 ] = 1;
+
+ break;
+ case(13):
+ b[s10+1] = 1;
+ b[s10 ] = 0;
+ b[s00+1] = 1;
+ b[s00 ] = 1;
+
+ break;
+ case(14):
+ b[s10+1] = 0;
+ b[s10 ] = 1;
+ b[s00+1] = 1;
+ b[s00 ] = 1;
+
+ break;
+ case(15):
+ b[s10+1] = 1;
+ b[s10 ] = 1;
+ b[s00+1] = 1;
+ b[s00 ] = 1;
+
+ break;
+ }
+/*
+ b[s10+1] = b[s00] & 1;
+ b[s10 ] = (b[s00]>>1) & 1;
+ b[s00+1] = (b[s00]>>2) & 1;
+ b[s00 ] = (b[s00]>>3) & 1;
+*/
+
+ s00 += 2;
+ s10 += 2;
+ }
+
+ if (j < ny) {
+ /*
+ * row size is odd, do last element in row
+ * s00+1, s10+1 are off edge
+ */
+ /* not worth converting this to use 16 case statements */
+ b[s10 ] = (b[s00]>>1) & 1;
+ b[s00 ] = (b[s00]>>3) & 1;
+ }
+ }
+ if (i < nx) {
+ /*
+ * column size is odd, do last row
+ * s10, s10+1 are off edge
+ */
+ s00 = n*i;
+ for (j = 0; j<ny-1; j += 2) {
+ /* not worth converting this to use 16 case statements */
+ b[s00+1] = (b[s00]>>2) & 1;
+ b[s00 ] = (b[s00]>>3) & 1;
+ s00 += 2;
+ }
+ if (j < ny) {
+ /*
+ * both row and column size are odd, do corner element
+ * s00+1, s10, s10+1 are off edge
+ */
+ /* not worth converting this to use 16 case statements */
+ b[s00 ] = (b[s00]>>3) & 1;
+ }
+ }
+}
+
+/* ############################################################################ */
+/*
+ * Copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
+ * each value to 2x2 pixels and inserting into bitplane BIT of B.
+ * A,B may NOT be same array (it wouldn't make sense to be inserting
+ * bits into the same array anyway.)
+ */
+static void
+qtree_bitins(unsigned char a[], int nx, int ny, int b[], int n, int bit)
+/*
+ int n; declared y dimension of b
+*/
+{
+int i, j, k;
+int s00;
+int plane_val;
+
+ plane_val = 1 << bit;
+
+ /*
+ * expand each 2x2 block
+ */
+ k = 0; /* k is index of a[i/2,j/2] */
+ for (i = 0; i<nx-1; i += 2) {
+ s00 = n*i; /* s00 is index of b[i,j] */
+
+ /* Note:
+ this code appears to run very slightly faster on a 32-bit linux
+ machine using s00+n rather than the s10 intermediate variable
+ */
+ /* s10 = s00+n; */ /* s10 is index of b[i+1,j] */
+ for (j = 0; j<ny-1; j += 2) {
+
+ switch (a[k]) {
+ case(0):
+ break;
+ case(1):
+ b[s00+n+1] |= plane_val;
+ break;
+ case(2):
+ b[s00+n ] |= plane_val;
+ break;
+ case(3):
+ b[s00+n+1] |= plane_val;
+ b[s00+n ] |= plane_val;
+ break;
+ case(4):
+ b[s00+1] |= plane_val;
+ break;
+ case(5):
+ b[s00+n+1] |= plane_val;
+ b[s00+1] |= plane_val;
+ break;
+ case(6):
+ b[s00+n ] |= plane_val;
+ b[s00+1] |= plane_val;
+ break;
+ case(7):
+ b[s00+n+1] |= plane_val;
+ b[s00+n ] |= plane_val;
+ b[s00+1] |= plane_val;
+ break;
+ case(8):
+ b[s00 ] |= plane_val;
+ break;
+ case(9):
+ b[s00+n+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(10):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(11):
+ b[s00+n+1] |= plane_val;
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(12):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(13):
+ b[s00+n+1] |= plane_val;
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(14):
+ b[s00+n ] |= plane_val;
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(15):
+ b[s00+n+1] |= plane_val;
+ b[s00+n ] |= plane_val;
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ }
+
+/*
+ b[s10+1] |= ( a[k] & 1) << bit;
+ b[s10 ] |= ((a[k]>>1) & 1) << bit;
+ b[s00+1] |= ((a[k]>>2) & 1) << bit;
+ b[s00 ] |= ((a[k]>>3) & 1) << bit;
+*/
+ s00 += 2;
+/* s10 += 2; */
+ k += 1;
+ }
+ if (j < ny) {
+ /*
+ * row size is odd, do last element in row
+ * s00+1, s10+1 are off edge
+ */
+
+ switch (a[k]) {
+ case(0):
+ break;
+ case(1):
+ break;
+ case(2):
+ b[s00+n ] |= plane_val;
+ break;
+ case(3):
+ b[s00+n ] |= plane_val;
+ break;
+ case(4):
+ break;
+ case(5):
+ break;
+ case(6):
+ b[s00+n ] |= plane_val;
+ break;
+ case(7):
+ b[s00+n ] |= plane_val;
+ break;
+ case(8):
+ b[s00 ] |= plane_val;
+ break;
+ case(9):
+ b[s00 ] |= plane_val;
+ break;
+ case(10):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(11):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(12):
+ b[s00 ] |= plane_val;
+ break;
+ case(13):
+ b[s00 ] |= plane_val;
+ break;
+ case(14):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(15):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ }
+
+/*
+ b[s10 ] |= ((a[k]>>1) & 1) << bit;
+ b[s00 ] |= ((a[k]>>3) & 1) << bit;
+*/
+ k += 1;
+ }
+ }
+ if (i < nx) {
+ /*
+ * column size is odd, do last row
+ * s10, s10+1 are off edge
+ */
+ s00 = n*i;
+ for (j = 0; j<ny-1; j += 2) {
+
+ switch (a[k]) {
+ case(0):
+ break;
+ case(1):
+ break;
+ case(2):
+ break;
+ case(3):
+ break;
+ case(4):
+ b[s00+1] |= plane_val;
+ break;
+ case(5):
+ b[s00+1] |= plane_val;
+ break;
+ case(6):
+ b[s00+1] |= plane_val;
+ break;
+ case(7):
+ b[s00+1] |= plane_val;
+ break;
+ case(8):
+ b[s00 ] |= plane_val;
+ break;
+ case(9):
+ b[s00 ] |= plane_val;
+ break;
+ case(10):
+ b[s00 ] |= plane_val;
+ break;
+ case(11):
+ b[s00 ] |= plane_val;
+ break;
+ case(12):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(13):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(14):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(15):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ }
+
+/*
+ b[s00+1] |= ((a[k]>>2) & 1) << bit;
+ b[s00 ] |= ((a[k]>>3) & 1) << bit;
+*/
+
+ s00 += 2;
+ k += 1;
+ }
+ if (j < ny) {
+ /*
+ * both row and column size are odd, do corner element
+ * s00+1, s10, s10+1 are off edge
+ */
+
+ switch (a[k]) {
+ case(0):
+ break;
+ case(1):
+ break;
+ case(2):
+ break;
+ case(3):
+ break;
+ case(4):
+ break;
+ case(5):
+ break;
+ case(6):
+ break;
+ case(7):
+ break;
+ case(8):
+ b[s00 ] |= plane_val;
+ break;
+ case(9):
+ b[s00 ] |= plane_val;
+ break;
+ case(10):
+ b[s00 ] |= plane_val;
+ break;
+ case(11):
+ b[s00 ] |= plane_val;
+ break;
+ case(12):
+ b[s00 ] |= plane_val;
+ break;
+ case(13):
+ b[s00 ] |= plane_val;
+ break;
+ case(14):
+ b[s00 ] |= plane_val;
+ break;
+ case(15):
+ b[s00 ] |= plane_val;
+ break;
+ }
+
+/*
+ b[s00 ] |= ((a[k]>>3) & 1) << bit;
+*/
+ k += 1;
+ }
+ }
+}
+/* ############################################################################ */
+/*
+ * Copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
+ * each value to 2x2 pixels and inserting into bitplane BIT of B.
+ * A,B may NOT be same array (it wouldn't make sense to be inserting
+ * bits into the same array anyway.)
+ */
+static void
+qtree_bitins64(unsigned char a[], int nx, int ny, LONGLONG b[], int n, int bit)
+/*
+ int n; declared y dimension of b
+*/
+{
+int i, j, k;
+int s00;
+int plane_val;
+
+ plane_val = 1 << bit;
+
+ /*
+ * expand each 2x2 block
+ */
+ k = 0; /* k is index of a[i/2,j/2] */
+ for (i = 0; i<nx-1; i += 2) {
+ s00 = n*i; /* s00 is index of b[i,j] */
+
+ /* Note:
+ this code appears to run very slightly faster on a 32-bit linux
+ machine using s00+n rather than the s10 intermediate variable
+ */
+ /* s10 = s00+n; */ /* s10 is index of b[i+1,j] */
+ for (j = 0; j<ny-1; j += 2) {
+
+ switch (a[k]) {
+ case(0):
+ break;
+ case(1):
+ b[s00+n+1] |= plane_val;
+ break;
+ case(2):
+ b[s00+n ] |= plane_val;
+ break;
+ case(3):
+ b[s00+n+1] |= plane_val;
+ b[s00+n ] |= plane_val;
+ break;
+ case(4):
+ b[s00+1] |= plane_val;
+ break;
+ case(5):
+ b[s00+n+1] |= plane_val;
+ b[s00+1] |= plane_val;
+ break;
+ case(6):
+ b[s00+n ] |= plane_val;
+ b[s00+1] |= plane_val;
+ break;
+ case(7):
+ b[s00+n+1] |= plane_val;
+ b[s00+n ] |= plane_val;
+ b[s00+1] |= plane_val;
+ break;
+ case(8):
+ b[s00 ] |= plane_val;
+ break;
+ case(9):
+ b[s00+n+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(10):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(11):
+ b[s00+n+1] |= plane_val;
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(12):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(13):
+ b[s00+n+1] |= plane_val;
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(14):
+ b[s00+n ] |= plane_val;
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(15):
+ b[s00+n+1] |= plane_val;
+ b[s00+n ] |= plane_val;
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ }
+
+/*
+ b[s10+1] |= ((LONGLONG) ( a[k] & 1)) << bit;
+ b[s10 ] |= ((((LONGLONG)a[k])>>1) & 1) << bit;
+ b[s00+1] |= ((((LONGLONG)a[k])>>2) & 1) << bit;
+ b[s00 ] |= ((((LONGLONG)a[k])>>3) & 1) << bit;
+*/
+ s00 += 2;
+/* s10 += 2; */
+ k += 1;
+ }
+ if (j < ny) {
+ /*
+ * row size is odd, do last element in row
+ * s00+1, s10+1 are off edge
+ */
+
+ switch (a[k]) {
+ case(0):
+ break;
+ case(1):
+ break;
+ case(2):
+ b[s00+n ] |= plane_val;
+ break;
+ case(3):
+ b[s00+n ] |= plane_val;
+ break;
+ case(4):
+ break;
+ case(5):
+ break;
+ case(6):
+ b[s00+n ] |= plane_val;
+ break;
+ case(7):
+ b[s00+n ] |= plane_val;
+ break;
+ case(8):
+ b[s00 ] |= plane_val;
+ break;
+ case(9):
+ b[s00 ] |= plane_val;
+ break;
+ case(10):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(11):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(12):
+ b[s00 ] |= plane_val;
+ break;
+ case(13):
+ b[s00 ] |= plane_val;
+ break;
+ case(14):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(15):
+ b[s00+n ] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ }
+/*
+ b[s10 ] |= ((((LONGLONG)a[k])>>1) & 1) << bit;
+ b[s00 ] |= ((((LONGLONG)a[k])>>3) & 1) << bit;
+*/
+ k += 1;
+ }
+ }
+ if (i < nx) {
+ /*
+ * column size is odd, do last row
+ * s10, s10+1 are off edge
+ */
+ s00 = n*i;
+ for (j = 0; j<ny-1; j += 2) {
+
+ switch (a[k]) {
+ case(0):
+ break;
+ case(1):
+ break;
+ case(2):
+ break;
+ case(3):
+ break;
+ case(4):
+ b[s00+1] |= plane_val;
+ break;
+ case(5):
+ b[s00+1] |= plane_val;
+ break;
+ case(6):
+ b[s00+1] |= plane_val;
+ break;
+ case(7):
+ b[s00+1] |= plane_val;
+ break;
+ case(8):
+ b[s00 ] |= plane_val;
+ break;
+ case(9):
+ b[s00 ] |= plane_val;
+ break;
+ case(10):
+ b[s00 ] |= plane_val;
+ break;
+ case(11):
+ b[s00 ] |= plane_val;
+ break;
+ case(12):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(13):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(14):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ case(15):
+ b[s00+1] |= plane_val;
+ b[s00 ] |= plane_val;
+ break;
+ }
+
+/*
+ b[s00+1] |= ((((LONGLONG)a[k])>>2) & 1) << bit;
+ b[s00 ] |= ((((LONGLONG)a[k])>>3) & 1) << bit;
+*/
+ s00 += 2;
+ k += 1;
+ }
+ if (j < ny) {
+ /*
+ * both row and column size are odd, do corner element
+ * s00+1, s10, s10+1 are off edge
+ */
+
+ switch (a[k]) {
+ case(0):
+ break;
+ case(1):
+ break;
+ case(2):
+ break;
+ case(3):
+ break;
+ case(4):
+ break;
+ case(5):
+ break;
+ case(6):
+ break;
+ case(7):
+ break;
+ case(8):
+ b[s00 ] |= plane_val;
+ break;
+ case(9):
+ b[s00 ] |= plane_val;
+ break;
+ case(10):
+ b[s00 ] |= plane_val;
+ break;
+ case(11):
+ b[s00 ] |= plane_val;
+ break;
+ case(12):
+ b[s00 ] |= plane_val;
+ break;
+ case(13):
+ b[s00 ] |= plane_val;
+ break;
+ case(14):
+ b[s00 ] |= plane_val;
+ break;
+ case(15):
+ b[s00 ] |= plane_val;
+ break;
+ }
+/*
+ b[s00 ] |= ((((LONGLONG)a[k])>>3) & 1) << bit;
+*/
+ k += 1;
+ }
+ }
+}
+
+/* ############################################################################ */
+static void
+read_bdirect(unsigned char *infile, int a[], int n, int nqx, int nqy, unsigned char scratch[], int bit)
+{
+ /*
+ * read bit image packed 4 pixels/nybble
+ */
+/*
+int i;
+ for (i = 0; i < ((nqx+1)/2) * ((nqy+1)/2); i++) {
+ scratch[i] = input_nybble(infile);
+ }
+*/
+ input_nnybble(infile, ((nqx+1)/2) * ((nqy+1)/2), scratch);
+
+ /*
+ * insert in bitplane BIT of image A
+ */
+ qtree_bitins(scratch,nqx,nqy,a,n,bit);
+}
+/* ############################################################################ */
+static void
+read_bdirect64(unsigned char *infile, LONGLONG a[], int n, int nqx, int nqy, unsigned char scratch[], int bit)
+{
+ /*
+ * read bit image packed 4 pixels/nybble
+ */
+/*
+int i;
+ for (i = 0; i < ((nqx+1)/2) * ((nqy+1)/2); i++) {
+ scratch[i] = input_nybble(infile);
+ }
+*/
+ input_nnybble(infile, ((nqx+1)/2) * ((nqy+1)/2), scratch);
+
+ /*
+ * insert in bitplane BIT of image A
+ */
+ qtree_bitins64(scratch,nqx,nqy,a,n,bit);
+}
+
+/* ############################################################################ */
+/*
+ * Huffman decoding for fixed codes
+ *
+ * Coded values range from 0-15
+ *
+ * Huffman code values (hex):
+ *
+ * 3e, 00, 01, 08, 02, 09, 1a, 1b,
+ * 03, 1c, 0a, 1d, 0b, 1e, 3f, 0c
+ *
+ * and number of bits in each code:
+ *
+ * 6, 3, 3, 4, 3, 4, 5, 5,
+ * 3, 5, 4, 5, 4, 5, 6, 4
+ */
+static int input_huffman(unsigned char *infile)
+{
+int c;
+
+ /*
+ * get first 3 bits to start
+ */
+ c = input_nbits(infile,3);
+ if (c < 4) {
+ /*
+ * this is all we need
+ * return 1,2,4,8 for c=0,1,2,3
+ */
+ return(1<<c);
+ }
+ /*
+ * get the next bit
+ */
+ c = input_bit(infile) | (c<<1);
+ if (c < 13) {
+ /*
+ * OK, 4 bits is enough
+ */
+ switch (c) {
+ case 8 : return(3);
+ case 9 : return(5);
+ case 10 : return(10);
+ case 11 : return(12);
+ case 12 : return(15);
+ }
+ }
+ /*
+ * get yet another bit
+ */
+ c = input_bit(infile) | (c<<1);
+ if (c < 31) {
+ /*
+ * OK, 5 bits is enough
+ */
+ switch (c) {
+ case 26 : return(6);
+ case 27 : return(7);
+ case 28 : return(9);
+ case 29 : return(11);
+ case 30 : return(13);
+ }
+ }
+ /*
+ * need the 6th bit
+ */
+ c = input_bit(infile) | (c<<1);
+ if (c == 62) {
+ return(0);
+ } else {
+ return(14);
+ }
+}
+
+/* ############################################################################ */
+/* ############################################################################ */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+/* qread.c Read binary data
+ *
+ * Programmer: R. White Date: 11 March 1991
+ */
+
+static int readint(unsigned char *infile)
+{
+int a,i;
+unsigned char b[4];
+
+ /* Read integer A one byte at a time from infile.
+ *
+ * This is portable from Vax to Sun since it eliminates the
+ * need for byte-swapping.
+ *
+ * This routine is only called to read the first 3 values
+ * in the compressed file, so it doesn't have to be
+ * super-efficient
+ */
+ for (i=0; i<4; i++) qread(infile,(char *) &b[i],1);
+ a = b[0];
+ for (i=1; i<4; i++) a = (a<<8) + b[i];
+ return(a);
+}
+
+/* ############################################################################ */
+static LONGLONG readlonglong(unsigned char *infile)
+{
+int i;
+LONGLONG a;
+unsigned char b[8];
+
+ /* Read integer A one byte at a time from infile.
+ *
+ * This is portable from Vax to Sun since it eliminates the
+ * need for byte-swapping.
+ *
+ * This routine is only called to read the first 3 values
+ * in the compressed file, so it doesn't have to be
+ * super-efficient
+ */
+ for (i=0; i<8; i++) qread(infile,(char *) &b[i],1);
+ a = b[0];
+ for (i=1; i<8; i++) a = (a<<8) + b[i];
+ return(a);
+}
+
+/* ############################################################################ */
+static void qread(unsigned char *file, char buffer[], int n)
+{
+ /*
+ * read n bytes from file into buffer
+ *
+ */
+
+ memcpy(buffer, &file[nextchar], n);
+ nextchar += n;
+}
+
+/* ############################################################################ */
+/* ############################################################################ */
+/* Copyright (c) 1993 Association of Universities for Research
+ * in Astronomy. All rights reserved. Produced under National
+ * Aeronautics and Space Administration Contract No. NAS5-26555.
+ */
+
+/* BIT INPUT ROUTINES */
+
+/* THE BIT BUFFER */
+
+static int buffer2; /* Bits waiting to be input */
+static int bits_to_go; /* Number of bits still in buffer */
+
+/* INITIALIZE BIT INPUT */
+
+/* ############################################################################ */
+static void start_inputing_bits(void)
+{
+ /*
+ * Buffer starts out with no bits in it
+ */
+ bits_to_go = 0;
+}
+
+/* ############################################################################ */
+/* INPUT A BIT */
+
+static int input_bit(unsigned char *infile)
+{
+ if (bits_to_go == 0) { /* Read the next byte if no */
+
+ buffer2 = infile[nextchar];
+ nextchar++;
+
+ bits_to_go = 8;
+ }
+ /*
+ * Return the next bit
+ */
+ bits_to_go -= 1;
+ return((buffer2>>bits_to_go) & 1);
+}
+
+/* ############################################################################ */
+/* INPUT N BITS (N must be <= 8) */
+
+static int input_nbits(unsigned char *infile, int n)
+{
+ /* AND mask for retreiving the right-most n bits */
+ static int mask[9] = {0, 1, 3, 7, 15, 31, 63, 127, 255};
+
+ if (bits_to_go < n) {
+ /*
+ * need another byte's worth of bits
+ */
+
+ buffer2 = (buffer2<<8) | (int) infile[nextchar];
+ nextchar++;
+ bits_to_go += 8;
+ }
+ /*
+ * now pick off the first n bits
+ */
+ bits_to_go -= n;
+
+ /* there was a slight gain in speed by replacing the following line */
+/* return( (buffer2>>bits_to_go) & ((1<<n)-1) ); */
+ return( (buffer2>>bits_to_go) & (*(mask+n)) );
+}
+/* ############################################################################ */
+/* INPUT 4 BITS */
+
+static int input_nybble(unsigned char *infile)
+{
+ if (bits_to_go < 4) {
+ /*
+ * need another byte's worth of bits
+ */
+
+ buffer2 = (buffer2<<8) | (int) infile[nextchar];
+ nextchar++;
+ bits_to_go += 8;
+ }
+ /*
+ * now pick off the first 4 bits
+ */
+ bits_to_go -= 4;
+
+ return( (buffer2>>bits_to_go) & 15 );
+}
+/* ############################################################################ */
+/* INPUT array of 4 BITS */
+
+static int input_nnybble(unsigned char *infile, int n, unsigned char array[])
+{
+ /* copy n 4-bit nybbles from infile to the lower 4 bits of array */
+
+int ii, kk, shift1, shift2;
+
+/* forcing byte alignment doesn;t help, and even makes it go slightly slower
+if (bits_to_go != 8) input_nbits(infile, bits_to_go);
+*/
+ if (n == 1) {
+ array[0] = input_nybble(infile);
+ return(0);
+ }
+
+ if (bits_to_go == 8) {
+ /*
+ already have 2 full nybbles in buffer2, so
+ backspace the infile array to reuse last char
+ */
+ nextchar--;
+ bits_to_go = 0;
+ }
+
+ /* bits_to_go now has a value in the range 0 - 7. After adding */
+ /* another byte, bits_to_go effectively will be in range 8 - 15 */
+
+ shift1 = bits_to_go + 4; /* shift1 will be in range 4 - 11 */
+ shift2 = bits_to_go; /* shift2 will be in range 0 - 7 */
+ kk = 0;
+
+ /* special case */
+ if (bits_to_go == 0)
+ {
+ for (ii = 0; ii < n/2; ii++) {
+ /*
+ * refill the buffer with next byte
+ */
+ buffer2 = (buffer2<<8) | (int) infile[nextchar];
+ nextchar++;
+ array[kk] = (int) ((buffer2>>4) & 15);
+ array[kk + 1] = (int) ((buffer2) & 15); /* no shift required */
+ kk += 2;
+ }
+ }
+ else
+ {
+ for (ii = 0; ii < n/2; ii++) {
+ /*
+ * refill the buffer with next byte
+ */
+ buffer2 = (buffer2<<8) | (int) infile[nextchar];
+ nextchar++;
+ array[kk] = (int) ((buffer2>>shift1) & 15);
+ array[kk + 1] = (int) ((buffer2>>shift2) & 15);
+ kk += 2;
+ }
+ }
+
+
+ if (ii * 2 != n) { /* have to read last odd byte */
+ array[n-1] = input_nybble(infile);
+ }
+
+ return( (buffer2>>bits_to_go) & 15 );
+}
diff --git a/vendor/cfitsio/fitscopy.c b/vendor/cfitsio/fitscopy.c
new file mode 100644
index 00000000..67e32295
--- /dev/null
+++ b/vendor/cfitsio/fitscopy.c
@@ -0,0 +1,60 @@
+#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; /* 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 the previous, current, and following HDUs */
+ fits_copy_file(infptr, outfptr, 1, 1, 1, &status);
+
+ 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/vendor/cfitsio/fitscore.c b/vendor/cfitsio/fitscore.c
new file mode 100644
index 00000000..3700672b
--- /dev/null
+++ b/vendor/cfitsio/fitscore.c
@@ -0,0 +1,9243 @@
+/* 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 <locale.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 */
+
+#ifdef _REENTRANT
+/*
+ Fitsio_Lock and Fitsio_Pthread_Status are declared in fitsio2.h.
+*/
+pthread_mutex_t Fitsio_Lock;
+int Fitsio_Pthread_Status = 0;
+
+#endif
+
+int STREAM_DRIVER = 0;
+struct lconv *lcxxx;
+
+/*--------------------------------------------------------------------------*/
+float ffvers(float *version) /* IO - version number */
+/*
+ return the current version number of the FITSIO software
+*/
+{
+ *version = (float) 3.31;
+
+/* 18 Jul 2012
+
+ Previous releases:
+ *version = 3.30 11 Apr 2012
+ *version = 3.29 22 Sep 2011
+ *version = 3.28 12 May 2011
+ *version = 3.27 3 Mar 2011
+ *version = 3.26 30 Dec 2010
+ *version = 3.25 9 June 2010
+ *version = 3.24 26 Jan 2010
+ *version = 3.23 7 Jan 2010
+ *version = 3.22 28 Oct 2009
+ *version = 3.21 24 Sep 2009
+ *version = 3.20 31 Aug 2009
+ *version = 3.18 12 May 2009 (beta version)
+ *version = 3.14 18 Mar 2009
+ *version = 3.13 5 Jan 2009
+ *version = 3.12 8 Oct 2008
+ *version = 3.11 19 Sep 2008
+ *version = 3.10 20 Aug 2008
+ *version = 3.09 3 Jun 2008
+ *version = 3.08 15 Apr 2007 (internal release)
+ *version = 3.07 5 Nov 2007 (internal release)
+ *version = 3.06 27 Aug 2007
+ *version = 3.05 12 Jul 2007 (internal release)
+ *version = 3.03 11 Dec 2006
+ *version = 3.02 18 Sep 2006
+ *version = 3.01 May 2006 included in FTOOLS 6.1 release
+ *version = 3.006 20 Feb 2006
+ *version = 3.005 20 Dec 2005 (beta, in heasoft swift release
+ *version = 3.004 16 Sep 2005 (beta, in heasoft swift release
+ *version = 3.003 28 Jul 2005 (beta, in heasoft swift release
+ *version = 3.002 15 Apr 2005 (beta)
+ *version = 3.001 15 Mar 2005 (beta) released with heasoft 6.0
+ *version = 3.000 1 Mar 2005 (internal release only)
+ *version = 2.51 2 Dec 2004
+ *version = 2.50 28 Jul 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;
+
+ FFLOCK;
+
+ 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 */
+ FFUNLOCK;
+ 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++;
+
+ }
+
+ FFUNLOCK;
+ 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(const 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] );
+
+ if (card[ii] == 0)
+ strcat(msg, " (NULL char.)");
+ else if (card[ii] == 9)
+ strcat(msg, " (TAB char.)");
+ else if (card[ii] == 10)
+ strcat(msg, " (Line Feed char.)");
+ else if (card[ii] == 11)
+ strcat(msg, " (Vertical Tab)");
+ else if (card[ii] == 12)
+ strcat(msg, " (Form Feed char.)");
+ else if (card[ii] == 13)
+ strcat(msg, " (Carriage Return)");
+ else if (card[ii] == 27)
+ strcat(msg, " (Escape char.)");
+ else if (card[ii] == 127)
+ strcat(msg, " (Delete char.)");
+
+ 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(const char *keyname, /* I - keyword name */
+ char *value, /* I - keyword value */
+ const 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, nblank = 0;
+
+ if (*status > 0)
+ return(*status);
+
+ *tmpname = '\0';
+ *card = '\0';
+
+ while(*(keyname + nblank) == ' ') /* skip leading blanks in the name */
+ nblank++;
+
+ strncat(tmpname, keyname + nblank, FLEN_KEYWORD - 1);
+
+ len = strlen(value);
+ 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);
+
+ if (namelen + 12 + len > 80) {
+ /* save 1 char by not putting a space before the equals sign */
+ strcat(card, "= ");
+ namelen += 11;
+ } else {
+ strcat(card, " = ");
+ namelen += 12;
+ }
+ }
+
+ 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);
+
+ /* silently replace any illegal characters with a space */
+ for (ii=0; ii < len; ii++)
+ if (tcard[ii] < ' ' || tcard[ii] > 126) tcard[ii] = ' ';
+
+ 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 */
+
+/* no need to do this any more, since any illegal characters have been removed
+ 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(const 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)
+ {
+ jj = minvalue(jj, 69); /* don't exceed 70 char string length */
+ value[jj] = '\''; /* close the bad value string */
+ value[jj+1] = '\0'; /* terminate the bad value string */
+ ffpmsg("This keyword string value has no closing quote:");
+ ffpmsg(card);
+ /* May 2008 - modified to not fail on this minor error */
+/* 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[140], comment[140];
+ char *tok, *suffix, *loc, tvalue[140];
+ 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;
+
+ /* test for pecular case where token is a string of dashes */
+ if (strncmp(tok, "--------------------", 20) == 0)
+ return(*status = BAD_KEYCHAR);
+
+ 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);
+ if ((loc = strchr(tvalue, 'D')))
+ {
+ *loc = 'E'; /* replace D's with E's. */
+ dval = strtod(tvalue, &suffix); /* read value again */
+ }
+ else if ((loc = strchr(tvalue, 'd')))
+ {
+ *loc = 'E'; /* replace d's with E's. */
+ dval = strtod(tvalue, &suffix); /* read value again */
+ }
+ else if ((loc = strchr(tvalue, '.')))
+ {
+ *loc = ','; /* replace period with a comma */
+ 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 fits_translate_keyword(
+ char *inrec, /* I - input string */
+ char *outrec, /* O - output converted string, or */
+ /* a null string if input does not */
+ /* match any of the patterns */
+ char *patterns[][2],/* I - pointer to input / output string */
+ /* templates */
+ int npat, /* I - number of templates passed */
+ int n_value, /* I - base 'n' template value of interest */
+ int n_offset, /* I - offset to be applied to the 'n' */
+ /* value in the output string */
+ int n_range, /* I - controls range of 'n' template */
+ /* values of interest (-1,0, or +1) */
+ int *pat_num, /* O - matched pattern number (0 based) or -1 */
+ int *i, /* O - value of i, if any, else 0 */
+ int *j, /* O - value of j, if any, else 0 */
+ int *m, /* O - value of m, if any, else 0 */
+ int *n, /* O - value of n, if any, else 0 */
+
+ int *status) /* IO - error status */
+
+/*
+
+Translate a keyword name to a new name, based on a set of patterns.
+The user passes an array of patterns to be matched. Input pattern
+number i is pattern[i][0], and output pattern number i is
+pattern[i][1]. Keywords are matched against the input patterns. If a
+match is found then the keyword is re-written according to the output
+pattern.
+
+Order is important. The first match is accepted. The fastest match
+will be made when templates with the same first character are grouped
+together.
+
+Several characters have special meanings:
+
+ i,j - single digits, preserved in output template
+ n - column number of one or more digits, preserved in output template
+ m - generic number of one or more digits, preserved in output template
+ a - coordinate designator, preserved in output template
+ # - number of one or more digits
+ ? - any character
+ * - only allowed in first character position, to match all
+ keywords; only useful as last pattern in the list
+
+i, j, n, and m are returned by the routine.
+
+For example, the input pattern "iCTYPn" will match "1CTYP5" (if n_value
+is 5); the output pattern "CTYPEi" will be re-written as "CTYPE1".
+Notice that "i" is preserved.
+
+The following output patterns are special
+
+Special output pattern characters:
+
+ "-" - do not copy a keyword that matches the corresponding input pattern
+
+ "+" - copy the input unchanged
+
+The inrec string could be just the 8-char keyword name, or the entire
+80-char header record. Characters 9 = 80 in the input string simply get
+appended to the translated keyword name.
+
+If n_range = 0, then only keywords with 'n' equal to n_value will be
+considered as a pattern match. If n_range = +1, then all values of
+'n' greater than or equal to n_value will be a match, and if -1,
+then values of 'n' less than or equal to n_value will match.
+
+ This routine was written by Craig Markwardt, GSFC
+*/
+
+{
+ int i1 = 0, j1 = 0, n1 = 0, m1 = 0;
+ int fac;
+ char a = ' ';
+ char oldp;
+ char c, s;
+ int ip, ic, pat, pass = 0, firstfail;
+ char *spat;
+
+ if (*status > 0)
+ return(*status);
+ if ((inrec == 0) || (outrec == 0))
+ return (*status = NULL_INPUT_PTR);
+
+ *outrec = '\0';
+/*
+ if (*inrec == '\0') return 0;
+*/
+
+ if (*inrec == '\0') /* expand to full 8 char blank keyword name */
+ strcpy(inrec, " ");
+
+ oldp = '\0';
+ firstfail = 0;
+
+ /* ===== Pattern match stage */
+ for (pat=0; pat < npat; pat++) {
+ spat = patterns[pat][0];
+
+ i1 = 0; j1 = 0; m1 = -1; n1 = -1; a = ' '; /* Initialize the place-holders */
+ pass = 0;
+
+ /* Pass the wildcard pattern */
+ if (spat[0] == '*') {
+ pass = 1;
+ break;
+ }
+
+ /* Optimization: if we have seen this initial pattern character before,
+ then it must have failed, and we can skip the pattern */
+ if (firstfail && spat[0] == oldp) continue;
+ oldp = spat[0];
+
+ /*
+ ip = index of pattern character being matched
+ ic = index of keyname character being matched
+ firstfail = 1 if we fail on the first characteor (0=not)
+ */
+
+ for (ip=0, ic=0, firstfail=1;
+ (spat[ip]) && (ic < 8);
+ ip++, ic++, firstfail=0) {
+ c = inrec[ic];
+ s = spat[ip];
+
+ if (s == 'i') {
+ /* Special pattern: 'i' placeholder */
+ if (isdigit(c)) { i1 = c - '0'; pass = 1;}
+ } else if (s == 'j') {
+ /* Special pattern: 'j' placeholder */
+ if (isdigit(c)) { j1 = c - '0'; pass = 1;}
+ } else if ((s == 'n')||(s == 'm')||(s == '#')) {
+ /* Special patterns: multi-digit number */
+ int val = 0;
+ pass = 0;
+ if (isdigit(c)) {
+ pass = 1; /* NOTE, could fail below */
+
+ /* Parse decimal number */
+ while (ic<8 && isdigit(c)) {
+ val = val*10 + (c - '0');
+ ic++; c = inrec[ic];
+ }
+ ic--; c = inrec[ic];
+
+ if (s == 'n') {
+
+ /* Is it a column number? */
+ if ( val >= 1 && val <= 999 && /* Row range check */
+ (((n_range == 0) && (val == n_value)) || /* Strict equality */
+ ((n_range == -1) && (val <= n_value)) || /* n <= n_value */
+ ((n_range == +1) && (val >= n_value))) ) { /* n >= n_value */
+ n1 = val;
+ } else {
+ pass = 0;
+ }
+ } else if (s == 'm') {
+
+ /* Generic number */
+ m1 = val;
+ }
+ }
+ } else if (s == 'a') {
+ /* Special pattern: coordinate designator */
+ if (isupper(c) || c == ' ') { a = c; pass = 1;}
+ } else if (s == '?') {
+ /* Match any individual character */
+ pass = 1;
+ } else if (c == s) {
+ /* Match a specific character */
+ pass = 1;
+ } else {
+ /* FAIL */
+ pass = 0;
+ }
+ if (!pass) break;
+ }
+
+ /* Must pass to the end of the keyword. No partial matches allowed */
+ if (pass && (ic >= 8 || inrec[ic] == ' ')) break;
+ }
+
+ /* Transfer the pattern-matched numbers to the output parameters */
+ if (i) { *i = i1; }
+ if (j) { *j = j1; }
+ if (n) { *n = n1; }
+ if (m) { *m = m1; }
+ if (pat_num) { *pat_num = pat; }
+
+ /* ===== Keyword rewriting and output stage */
+ spat = patterns[pat][1];
+
+ /* Return case: no match, or explicit deletion pattern */
+ if (pass == 0 || spat[0] == '\0' || spat[0] == '-') return 0;
+
+ /* A match: we start by copying the input record to the output */
+ strcpy(outrec, inrec);
+
+ /* Return case: return the input record unchanged */
+ if (spat[0] == '+') return 0;
+
+
+ /* Final case: a new output pattern */
+ for (ip=0, ic=0; spat[ip]; ip++, ic++) {
+ s = spat[ip];
+ if (s == 'i') {
+ outrec[ic] = (i1+'0');
+ } else if (s == 'j') {
+ outrec[ic] = (j1+'0');
+ } else if (s == 'n') {
+ if (n1 == -1) { n1 = n_value; }
+ if (n1 > 0) {
+ n1 += n_offset;
+ for (fac = 1; (n1/fac) > 0; fac *= 10);
+ fac /= 10;
+ while(fac > 0) {
+ outrec[ic] = ((n1/fac) % 10) + '0';
+ fac /= 10;
+ ic ++;
+ }
+ ic--;
+ }
+ } else if (s == 'm' && m1 >= 0) {
+ for (fac = 1; (m1/fac) > 0; fac *= 10);
+ fac /= 10;
+ while(fac > 0) {
+ outrec[ic] = ((m1/fac) % 10) + '0';
+ fac /= 10;
+ ic ++;
+ }
+ ic --;
+ } else if (s == 'a') {
+ outrec[ic] = a;
+ } else {
+ outrec[ic] = s;
+ }
+ }
+
+ /* Pad the keyword name with spaces */
+ for ( ; ic<8; ic++) { outrec[ic] = ' '; }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_translate_keywords(
+ fitsfile *infptr, /* I - pointer to input HDU */
+ fitsfile *outfptr, /* I - pointer to output HDU */
+ int firstkey, /* I - first HDU record number to start with */
+ char *patterns[][2],/* I - pointer to input / output keyword templates */
+ int npat, /* I - number of templates passed */
+ int n_value, /* I - base 'n' template value of interest */
+ int n_offset, /* I - offset to be applied to the 'n' */
+ /* value in the output string */
+ int n_range, /* I - controls range of 'n' template */
+ /* values of interest (-1,0, or +1) */
+ int *status) /* IO - error status */
+/*
+ Copy relevant keywords from the table header into the newly
+ created primary array header. Convert names of keywords where
+ appropriate. See fits_translate_keyword() for the definitions.
+
+ Translation begins at header record number 'firstkey', and
+ continues to the end of the header.
+
+ This routine was written by Craig Markwardt, GSFC
+*/
+{
+ int nrec, nkeys, nmore;
+ char rec[FLEN_CARD];
+ int i = 0, j = 0, n = 0, m = 0;
+ int pat_num = 0, maxchr, ii;
+ char outrec[FLEN_CARD];
+
+ if (*status > 0)
+ return(*status);
+
+ ffghsp(infptr, &nkeys, &nmore, status); /* get number of keywords */
+
+ for (nrec = firstkey; nrec <= nkeys; nrec++) {
+ outrec[0] = '\0';
+
+ ffgrec(infptr, nrec, rec, status);
+
+ /* silently overlook any illegal ASCII characters in the value or */
+ /* comment fields of the record. It is usually not appropriate to */
+ /* abort the process because of this minor transgression of the FITS rules. */
+ /* Set the offending character to a blank */
+
+ maxchr = strlen(rec);
+ for (ii = 8; ii < maxchr; ii++)
+ {
+ if (rec[ii] < 32 || rec[ii] > 126)
+ rec[ii] = ' ';
+ }
+
+ fits_translate_keyword(rec, outrec, patterns, npat,
+ n_value, n_offset, n_range,
+ &pat_num, &i, &j, &m, &n, status);
+
+ if (outrec[0]) {
+ ffprec(outfptr, outrec, status); /* copy the keyword */
+ rec[8] = 0; outrec[8] = 0;
+ } else {
+ rec[8] = 0; outrec[8] = 0;
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_copy_pixlist2image(
+ fitsfile *infptr, /* I - pointer to input HDU */
+ fitsfile *outfptr, /* I - pointer to output HDU */
+ int firstkey, /* I - first HDU record number to start with */
+ int naxis, /* I - number of axes in the image */
+ int *colnum, /* I - numbers of the columns to be binned */
+ int *status) /* IO - error status */
+/*
+ Copy relevant keywords from the pixel list table header into a newly
+ created primary array header. Convert names of keywords where
+ appropriate. See fits_translate_pixkeyword() for the definitions.
+
+ Translation begins at header record number 'firstkey', and
+ continues to the end of the header.
+*/
+{
+ int nrec, nkeys, nmore;
+ char rec[FLEN_CARD], outrec[FLEN_CARD];
+ int pat_num = 0, npat;
+ int iret, jret, nret, mret, lret;
+ char *patterns[][2] = {
+
+ {"TCTYPn", "CTYPEn" },
+ {"TCTYna", "CTYPEna" },
+ {"TCUNIn", "CUNITn" },
+ {"TCUNna", "CUNITna" },
+ {"TCRVLn", "CRVALn" },
+ {"TCRVna", "CRVALna" },
+ {"TCDLTn", "CDELTn" },
+ {"TCDEna", "CDELTna" },
+ {"TCRPXn", "CRPIXn" },
+ {"TCRPna", "CRPIXna" },
+ {"TCROTn", "CROTAn" },
+ {"TPn_ma", "PCn_ma" },
+ {"TPCn_m", "PCn_ma" },
+ {"TCn_ma", "CDn_ma" },
+ {"TCDn_m", "CDn_ma" },
+ {"TVn_la", "PVn_la" },
+ {"TPVn_l", "PVn_la" },
+ {"TSn_la", "PSn_la" },
+ {"TPSn_l", "PSn_la" },
+ {"TWCSna", "WCSNAMEa" },
+ {"TCNAna", "CNAMEna" },
+ {"TCRDna", "CRDERna" },
+ {"TCSYna", "CSYERna" },
+ {"LONPna", "LONPOLEa" },
+ {"LATPna", "LATPOLEa" },
+ {"EQUIna", "EQUINOXa" },
+ {"MJDOBn", "MJD-OBS" },
+ {"MJDAn", "MJD-AVG" },
+ {"DAVGn", "DATE-AVG" },
+ {"RADEna", "RADESYSa" },
+ {"RFRQna", "RESTFRQa" },
+ {"RWAVna", "RESTWAVa" },
+ {"SPECna", "SPECSYSa" },
+ {"SOBSna", "SSYSOBSa" },
+ {"SSRCna", "SSYSSRCa" },
+
+ /* preserve common keywords */
+ {"LONPOLEa", "+" },
+ {"LATPOLEa", "+" },
+ {"EQUINOXa", "+" },
+ {"EPOCH", "+" },
+ {"MJD-????", "+" },
+ {"DATE????", "+" },
+ {"TIME????", "+" },
+ {"RADESYSa", "+" },
+ {"RADECSYS", "+" },
+ {"TELESCOP", "+" },
+ {"INSTRUME", "+" },
+ {"OBSERVER", "+" },
+ {"OBJECT", "+" },
+
+ /* Delete general table column keywords */
+ {"XTENSION", "-" },
+ {"BITPIX", "-" },
+ {"NAXIS", "-" },
+ {"NAXISi", "-" },
+ {"PCOUNT", "-" },
+ {"GCOUNT", "-" },
+ {"TFIELDS", "-" },
+
+ {"TDIM#", "-" },
+ {"THEAP", "-" },
+ {"EXTNAME", "-" },
+ {"EXTVER", "-" },
+ {"EXTLEVEL","-" },
+ {"CHECKSUM","-" },
+ {"DATASUM", "-" },
+ {"NAXLEN", "-" },
+ {"AXLEN#", "-" },
+ {"CPREF", "-" },
+
+ /* Delete table keywords related to other columns */
+ {"T????#a", "-" },
+ {"TC??#a", "-" },
+ {"T??#_#", "-" },
+ {"TWCS#a", "-" },
+
+ {"LONP#a", "-" },
+ {"LATP#a", "-" },
+ {"EQUI#a", "-" },
+ {"MJDOB#", "-" },
+ {"MJDA#", "-" },
+ {"RADE#a", "-" },
+ {"DAVG#", "-" },
+
+ {"iCTYP#", "-" },
+ {"iCTY#a", "-" },
+ {"iCUNI#", "-" },
+ {"iCUN#a", "-" },
+ {"iCRVL#", "-" },
+ {"iCDLT#", "-" },
+ {"iCRPX#", "-" },
+ {"iCTY#a", "-" },
+ {"iCUN#a", "-" },
+ {"iCRV#a", "-" },
+ {"iCDE#a", "-" },
+ {"iCRP#a", "-" },
+ {"ijPC#a", "-" },
+ {"ijCD#a", "-" },
+ {"iV#_#a", "-" },
+ {"iS#_#a", "-" },
+ {"iCRD#a", "-" },
+ {"iCSY#a", "-" },
+ {"iCROT#", "-" },
+ {"WCAX#a", "-" },
+ {"WCSN#a", "-" },
+ {"iCNA#a", "-" },
+
+ {"*", "+" }}; /* copy all other keywords */
+
+ if (*status > 0)
+ return(*status);
+
+ npat = sizeof(patterns)/sizeof(patterns[0][0])/2;
+
+ ffghsp(infptr, &nkeys, &nmore, status); /* get number of keywords */
+
+ for (nrec = firstkey; nrec <= nkeys; nrec++) {
+ outrec[0] = '\0';
+
+ ffgrec(infptr, nrec, rec, status);
+
+ fits_translate_pixkeyword(rec, outrec, patterns, npat,
+ naxis, colnum,
+ &pat_num, &iret, &jret, &nret, &mret, &lret, status);
+
+ if (outrec[0]) {
+ ffprec(outfptr, outrec, status); /* copy the keyword */
+ }
+
+ rec[8] = 0; outrec[8] = 0;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_translate_pixkeyword(
+ char *inrec, /* I - input string */
+ char *outrec, /* O - output converted string, or */
+ /* a null string if input does not */
+ /* match any of the patterns */
+ char *patterns[][2],/* I - pointer to input / output string */
+ /* templates */
+ int npat, /* I - number of templates passed */
+ int naxis, /* I - number of columns to be binned */
+ int *colnum, /* I - numbers of the columns to be binned */
+ int *pat_num, /* O - matched pattern number (0 based) or -1 */
+ int *i,
+ int *j,
+ int *n,
+ int *m,
+ int *l,
+ int *status) /* IO - error status */
+
+/*
+
+Translate a keyword name to a new name, based on a set of patterns.
+The user passes an array of patterns to be matched. Input pattern
+number i is pattern[i][0], and output pattern number i is
+pattern[i][1]. Keywords are matched against the input patterns. If a
+match is found then the keyword is re-written according to the output
+pattern.
+
+Order is important. The first match is accepted. The fastest match
+will be made when templates with the same first character are grouped
+together.
+
+Several characters have special meanings:
+
+ i,j - single digits, preserved in output template
+ n, m - column number of one or more digits, preserved in output template
+ k - generic number of one or more digits, preserved in output template
+ a - coordinate designator, preserved in output template
+ # - number of one or more digits
+ ? - any character
+ * - only allowed in first character position, to match all
+ keywords; only useful as last pattern in the list
+
+i, j, n, and m are returned by the routine.
+
+For example, the input pattern "iCTYPn" will match "1CTYP5" (if n_value
+is 5); the output pattern "CTYPEi" will be re-written as "CTYPE1".
+Notice that "i" is preserved.
+
+The following output patterns are special
+
+Special output pattern characters:
+
+ "-" - do not copy a keyword that matches the corresponding input pattern
+
+ "+" - copy the input unchanged
+
+The inrec string could be just the 8-char keyword name, or the entire
+80-char header record. Characters 9 = 80 in the input string simply get
+appended to the translated keyword name.
+
+If n_range = 0, then only keywords with 'n' equal to n_value will be
+considered as a pattern match. If n_range = +1, then all values of
+'n' greater than or equal to n_value will be a match, and if -1,
+then values of 'n' less than or equal to n_value will match.
+
+*/
+
+{
+ int i1 = 0, j1 = 0, val;
+ int fac, nval, mval, lval;
+ char a = ' ';
+ char oldp;
+ char c, s;
+ int ip, ic, pat, pass = 0, firstfail;
+ char *spat;
+
+ if (*status > 0)
+ return(*status);
+
+ if ((inrec == 0) || (outrec == 0))
+ return (*status = NULL_INPUT_PTR);
+
+ *outrec = '\0';
+ if (*inrec == '\0') return 0;
+
+ oldp = '\0';
+ firstfail = 0;
+
+ /* ===== Pattern match stage */
+ for (pat=0; pat < npat; pat++) {
+
+ spat = patterns[pat][0];
+
+ i1 = 0; j1 = 0; a = ' '; /* Initialize the place-holders */
+ pass = 0;
+
+ /* Pass the wildcard pattern */
+ if (spat[0] == '*') {
+ pass = 1;
+ break;
+ }
+
+ /* Optimization: if we have seen this initial pattern character before,
+ then it must have failed, and we can skip the pattern */
+ if (firstfail && spat[0] == oldp) continue;
+ oldp = spat[0];
+
+ /*
+ ip = index of pattern character being matched
+ ic = index of keyname character being matched
+ firstfail = 1 if we fail on the first characteor (0=not)
+ */
+
+ for (ip=0, ic=0, firstfail=1;
+ (spat[ip]) && (ic < 8);
+ ip++, ic++, firstfail=0) {
+ c = inrec[ic];
+ s = spat[ip];
+
+ if (s == 'i') {
+ /* Special pattern: 'i' placeholder */
+ if (isdigit(c)) { i1 = c - '0'; pass = 1;}
+ } else if (s == 'j') {
+ /* Special pattern: 'j' placeholder */
+ if (isdigit(c)) { j1 = c - '0'; pass = 1;}
+ } else if ((s == 'n')||(s == 'm')||(s == 'l')||(s == '#')) {
+ /* Special patterns: multi-digit number */
+ val = 0;
+ pass = 0;
+ if (isdigit(c)) {
+ pass = 1; /* NOTE, could fail below */
+
+ /* Parse decimal number */
+ while (ic<8 && isdigit(c)) {
+ val = val*10 + (c - '0');
+ ic++; c = inrec[ic];
+ }
+ ic--; c = inrec[ic];
+
+ if (s == 'n' || s == 'm') {
+
+ /* Is it a column number? */
+ if ( val >= 1 && val <= 999) {
+
+ if (val == colnum[0])
+ val = 1;
+ else if (val == colnum[1])
+ val = 2;
+ else if (val == colnum[2])
+ val = 3;
+ else if (val == colnum[3])
+ val = 4;
+ else {
+ pass = 0;
+ val = 0;
+ }
+
+ if (s == 'n')
+ nval = val;
+ else
+ mval = val;
+
+ } else {
+ pass = 0;
+ }
+ } else if (s == 'l') {
+ /* Generic number */
+ lval = val;
+ }
+ }
+ } else if (s == 'a') {
+ /* Special pattern: coordinate designator */
+ if (isupper(c) || c == ' ') { a = c; pass = 1;}
+ } else if (s == '?') {
+ /* Match any individual character */
+ pass = 1;
+ } else if (c == s) {
+ /* Match a specific character */
+ pass = 1;
+ } else {
+ /* FAIL */
+ pass = 0;
+ }
+
+ if (!pass) break;
+ }
+
+
+ /* Must pass to the end of the keyword. No partial matches allowed */
+ if (pass && (ic >= 8 || inrec[ic] == ' ')) break;
+ }
+
+
+ /* Transfer the pattern-matched numbers to the output parameters */
+ if (i) { *i = i1; }
+ if (j) { *j = j1; }
+ if (n) { *n = nval; }
+ if (m) { *m = mval; }
+ if (l) { *l = lval; }
+ if (pat_num) { *pat_num = pat; }
+
+ /* ===== Keyword rewriting and output stage */
+ spat = patterns[pat][1];
+
+ /* Return case: no match, or explicit deletion pattern */
+ if (pass == 0 || spat[0] == '\0' || spat[0] == '-') return 0;
+
+ /* A match: we start by copying the input record to the output */
+ strcpy(outrec, inrec);
+
+ /* Return case: return the input record unchanged */
+ if (spat[0] == '+') return 0;
+
+ /* Final case: a new output pattern */
+ for (ip=0, ic=0; spat[ip]; ip++, ic++) {
+ s = spat[ip];
+ if (s == 'i') {
+ outrec[ic] = (i1+'0');
+ } else if (s == 'j') {
+ outrec[ic] = (j1+'0');
+ } else if (s == 'n' && nval > 0) {
+ for (fac = 1; (nval/fac) > 0; fac *= 10);
+ fac /= 10;
+ while(fac > 0) {
+ outrec[ic] = ((nval/fac) % 10) + '0';
+ fac /= 10;
+ ic ++;
+ }
+ ic--;
+ } else if (s == 'm' && mval > 0) {
+ for (fac = 1; (mval/fac) > 0; fac *= 10);
+ fac /= 10;
+ while(fac > 0) {
+ outrec[ic] = ((mval/fac) % 10) + '0';
+ fac /= 10;
+ ic ++;
+ }
+ ic--;
+ } else if (s == 'l' && lval >= 0) {
+ for (fac = 1; (lval/fac) > 0; fac *= 10);
+ fac /= 10;
+ while(fac > 0) {
+ outrec[ic] = ((lval/fac) % 10) + '0';
+ fac /= 10;
+ ic ++;
+ }
+ ic --;
+ } else if (s == 'a') {
+ outrec[ic] = a;
+ } else {
+ outrec[ic] = s;
+ }
+ }
+
+ /* Pad the keyword name with spaces */
+ for ( ; ic<8; ic++) { outrec[ic] = ' '; }
+
+ 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' || form[0] == 'Q')
+ {
+ 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);
+}
+/*--------------------------------------------------------------------------*/
+int ffbnfmll(char *tform, /* I - format code from the TFORMn keyword */
+ int *dtcode, /* O - numerical datatype code */
+ LONGLONG *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;
+ LONGLONG repeat;
+ char *form, temp[FLEN_VALUE], message[FLEN_ERRMSG];
+ double drepeat;
+
+ 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 (ffbnfmll).");
+ 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 {
+ /* read repeat count */
+
+ /* print as double, because the string-to-64-bit int conversion */
+ /* character is platform dependent (%lld, %ld, %I64d) */
+
+ sscanf(form,"%lf", &drepeat);
+ repeat = (LONGLONG) (drepeat + 0.1);
+ }
+ /*-----------------------------------------------*/
+ /* determine datatype code */
+ /*-----------------------------------------------*/
+
+ form = form + ii; /* skip over the repeat field */
+
+ if (form[0] == 'P' || form[0] == 'Q')
+ {
+ 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 = (long) 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 */
+ }
+
+ if (strchr(tform+ii, '%')) /* is there a % character in the string?? */
+ {
+ cform[0] = '\0';
+ return; /* illegal TFORM string (possibly even harmful) */
+ }
+
+ 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.
+*/
+{
+ LONGLONG trepeat, twidth;
+
+ ffgtclll(fptr, colnum, typecode, &trepeat, &twidth, status);
+
+ if (*status > 0)
+ return(*status);
+
+ if (repeat)
+ *repeat= (long) trepeat;
+
+ if (width)
+ *width = (long) twidth;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgtclll( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ int *typecode, /* O - datatype code (21 = short, etc) */
+ LONGLONG *repeat, /* O - repeat count of field */
+ LONGLONG *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;
+ long tmpwidth;
+
+ 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, &tmpwidth, &decims, status);
+ *width = tmpwidth;
+
+ if (repeat)
+ *repeat = 1;
+ }
+ else
+ {
+ if (typecode)
+ *typecode = colptr->tdatatype;
+
+ if (width)
+ *width = colptr->twidth;
+
+ if (repeat)
+ *repeat = 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.
+*/
+{
+ LONGLONG trepeat, twidth;
+
+ ffeqtyll(fptr, colnum, typecode, &trepeat, &twidth, status);
+
+ if (repeat)
+ *repeat= (long) trepeat;
+
+ if (width)
+ *width = (long) twidth;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffeqtyll( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ int *typecode, /* O - datatype code (21 = short, etc) */
+ LONGLONG *repeat, /* O - repeat count of field */
+ LONGLONG *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, lngzero = 0, tmpwidth;
+
+ 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, &tmpwidth, &decims, status);
+ *width = tmpwidth;
+
+ if (repeat)
+ *repeat = 1;
+ }
+ else
+ {
+ if (typecode)
+ *typecode = colptr->tdatatype;
+
+ if (width)
+ *width = colptr->twidth;
+
+ if (repeat)
+ *repeat = 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 = (long) tzero;
+ lngscale = (long) 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 = (long) (fptr->Fptr)->numrows;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgnrwll( fitsfile *fptr, /* I - FITS file pointer */
+ LONGLONG *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 = (long) ((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
+*/
+{
+ LONGLONG trepeat, ttnull;
+
+ if (*status > 0)
+ return(*status);
+
+ ffgbclll(fptr, colnum, ttype, tunit, dtype, &trepeat, tscal, tzero,
+ &ttnull, tdisp, status);
+
+ if (repeat)
+ *repeat = (long) trepeat;
+
+ if (tnull)
+ *tnull = (long) ttnull;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgbclll( 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. */
+ LONGLONG *repeat, /* O - vector column repeat count */
+ double *tscal, /* O - TSCALn keyword value */
+ double *tzero, /* O - TZEROn keyword value */
+ LONGLONG *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) == TLONGLONG)
+ strcat(dtype, "K");
+ 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 = 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 ffghadll(fitsfile *fptr, /* I - FITS file pointer */
+ LONGLONG *headstart, /* O - byte offset to beginning of CHDU */
+ LONGLONG *datastart, /* O - byte offset to beginning of next HDU */
+ LONGLONG *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 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 = (OFF_T) (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu];
+
+ if (datastart)
+ *datastart = (OFF_T) (fptr->Fptr)->datastart;
+
+ if (dataend)
+ *dataend = (OFF_T) (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.
+*/
+{
+ LONGLONG shead, sdata, edata;
+
+ if (*status > 0)
+ return(*status);
+
+ ffghadll(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 pcount, gcount;
+ LONGLONG naxes[999], npix, blank;
+ 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;
+ ffmaky(fptr, 2, status); /* reset to beginning of header */
+
+ 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 */
+ (fptr->Fptr)->imgdim = naxis;
+ if (naxis == 0)
+ {
+ npix = 0;
+ }
+ else
+ {
+ if (groups)
+ {
+ npix = 1; /* NAXIS1 = 0 is a special flag for 'random groups' */
+ }
+ else
+ {
+ npix = naxes[0];
+ }
+
+ (fptr->Fptr)->imgnaxis[0] = naxes[0];
+ for (ii=1; ii < naxis; ii++)
+ {
+ npix = npix*naxes[ii]; /* calc number of pixels in the array */
+ (fptr->Fptr)->imgnaxis[ii] = naxes[ii];
+ }
+ }
+
+ /*
+ 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 +
+ ( ((LONGLONG) 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 */
+
+ /* free the tile-compressed image cache, if it exists */
+ if ((fptr->Fptr)->tiledata) {
+ free((fptr->Fptr)->tiledata);
+ (fptr->Fptr)->tiledata = 0;
+ (fptr->Fptr)->tilerow = 0;
+ (fptr->Fptr)->tiledatasize = 0;
+ (fptr->Fptr)->tiletype = 0;
+ }
+
+ if ((fptr->Fptr)->tilenullarray) {
+ free((fptr->Fptr)->tilenullarray);
+ (fptr->Fptr)->tilenullarray = 0;
+ }
+
+ 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 */
+
+ /* free the tile-compressed image cache, if it exists */
+
+ /* free the tile-compressed image cache, if it exists */
+ if ((fptr->Fptr)->tiledata) {
+ free((fptr->Fptr)->tiledata);
+ (fptr->Fptr)->tiledata = 0;
+ (fptr->Fptr)->tilerow = 0;
+ (fptr->Fptr)->tiledatasize = 0;
+ (fptr->Fptr)->tiletype = 0;
+ }
+
+ if ((fptr->Fptr)->tilenullarray) {
+ free((fptr->Fptr)->tilenullarray);
+ (fptr->Fptr)->tilenullarray = 0;
+ }
+
+ 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 = (LONGLONG) 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;
+ long tfield;
+ LONGLONG pcount, rowlen, nrows, tbcoln;
+ 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", (long) pcount);
+ ffpmsg(errmsg);
+ return(*status = BAD_PCOUNT);
+ }
+
+ (fptr->Fptr)->rowlength = rowlen; /* store length of a row */
+ (fptr->Fptr)->tfield = tfield; /* store number of table fields in row */
+
+ /* free the tile-compressed image cache, if it exists */
+ if ((fptr->Fptr)->tiledata) {
+ free((fptr->Fptr)->tiledata);
+ (fptr->Fptr)->tiledata = 0;
+ (fptr->Fptr)->tilerow = 0;
+ (fptr->Fptr)->tiledatasize = 0;
+ (fptr->Fptr)->tiletype = 0;
+ }
+
+ if ((fptr->Fptr)->tilenullarray) {
+ free((fptr->Fptr)->tilenullarray);
+ (fptr->Fptr)->tilenullarray = 0;
+ }
+
+
+ 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 = 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: %ld (ffainit).",
+ name, (long) 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 +
+ ( ((LONGLONG)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 tfield;
+ LONGLONG pcount, rowlen, nrows, 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 = rowlen; /* store length of a row */
+ (fptr->Fptr)->tfield = tfield; /* store number of table fields in row */
+
+
+ /* free the tile-compressed image cache, if it exists */
+ if ((fptr->Fptr)->tiledata) {
+ free((fptr->Fptr)->tiledata);
+ (fptr->Fptr)->tiledata = 0;
+ (fptr->Fptr)->tilerow = 0;
+ (fptr->Fptr)->tiledatasize = 0;
+ (fptr->Fptr)->tiletype = 0;
+ }
+
+ if ((fptr->Fptr)->tilenullarray) {
+ free((fptr->Fptr)->tilenullarray);
+ (fptr->Fptr)->tilenullarray = 0;
+ }
+
+ 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 = 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 +
+ ( (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",
+ (long) rowlen, (long) 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 */
+ LONGLONG *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;
+ LONGLONG nbytes;
+ tcolumn *colptr;
+ char message[FLEN_ERRMSG], *cptr;
+
+ 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 = colptr->trepeat; /* one byte per char */
+ }
+ else if (colptr->tdatatype == TBIT)
+ {
+ nbytes = ( colptr->trepeat + 7) / 8;
+ }
+ else if (colptr->tdatatype > 0)
+ {
+ nbytes = colptr->trepeat * (colptr->tdatatype / 10);
+ }
+ else {
+
+ cptr = colptr->tform;
+ while (isdigit(*cptr)) cptr++;
+
+ if (*cptr == 'P')
+ /* this is a 'P' variable length descriptor (neg. tdatatype) */
+ nbytes = colptr->trepeat * 8;
+ else if (*cptr == 'Q')
+ /* this is a 'Q' variable length descriptor (neg. tdatatype) */
+ nbytes = colptr->trepeat * 16;
+
+ else {
+ sprintf(message,
+ "unknown binary table column type: %s", colptr->tform);
+ ffpmsg(message);
+ *status = BAD_TFORM;
+ return(*status);
+ }
+ }
+
+ *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;
+ LONGLONG jjvalue;
+ double dvalue;
+ char tvalue[FLEN_VALUE], *loc;
+ 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 = (LONGLONG) repeat; /* field repeat count */
+
+ /* Don't overwrite the unit string width if it was previously */
+ /* set by a TDIMn keyword and has a legal value */
+ if (datacode == TSTRING) {
+ if (colptr->twidth == 0 || colptr->twidth > repeat)
+ colptr->twidth = width; /* width of a unit string */
+
+ } else {
+ 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 (ffc2jj(value, &jjvalue, &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 = jjvalue; /* null value for integer column */
+ }
+ }
+ else if(!FSTRNCMP(name + 1, "DIM", 3) )
+ {
+ if ((fptr->Fptr)->hdutype == ASCII_TBL) /* ASCII table */
+ return(*status); /* ASCII tables don't support TDIMn keyword */
+
+ /* get the index number */
+ if( ffc2ii(name + 4, &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 */
+
+ /* uninitialized columns have tdatatype set = -9999 */
+ if (colptr->tdatatype != -9999 && colptr->tdatatype != TSTRING)
+ return(*status); /* this is not an ASCII string column */
+
+ loc = strchr(value, '(' ); /* find the opening parenthesis */
+ if (!loc)
+ return(*status); /* not a proper TDIM keyword */
+
+ loc++;
+ width = strtol(loc, &loc, 10); /* read size of first dimension */
+ if (colptr->trepeat != 1 && colptr->trepeat < width)
+ return(*status); /* string length is greater than column width */
+
+ colptr->twidth = width; /* set width of a unit string in chars */
+ }
+ 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 (ffc2jj(value, &jjvalue, &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 = jjvalue; /* starting byte of the heap */
+ return(*status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgcprll( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number (1 = 1st column of table) */
+ LONGLONG firstrow, /* I - first row (1 = 1st row of table) */
+ LONGLONG firstelem, /* I - first element within vector (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG *startpos,/* O - offset in file to starting row & column */
+ LONGLONG *elemnum, /* O - starting element number ( 0 = 1st element) */
+ long *incre, /* O - byte offset between elements within a row */
+ LONGLONG *repeat, /* O - number of elements in a row (vector column) */
+ LONGLONG *rowlen, /* O - length of a row, in bytes */
+ int *hdutype, /* O - HDU type: 0, 1, 2 = primary, table, bintable */
+ LONGLONG *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;
+ LONGLONG datastart, endpos;
+ long nblock;
+ LONGLONG heapoffset, lrepeat, endrow, nrows, tbcol;
+ char message[81];
+ tcolumn *colptr;
+
+ if (fptr->HDUposition != (fptr->Fptr)->curhdu) {
+ /* reset position to the correct HDU if necessary */
+ 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);
+
+ } else if (writemode > 0) {
+
+ /* Only terminate the header with the END card if */
+ /* writing to the stdout stream (don't have random access). */
+
+ /* Initialize STREAM_DRIVER to be the device number for */
+ /* writing FITS files directly out to the stdout stream. */
+ /* This only needs to be done once and is thread safe. */
+ if (STREAM_DRIVER <= 0 || STREAM_DRIVER > 40) {
+ urltype2driver("stream://", &STREAM_DRIVER);
+ }
+
+ if (((fptr->Fptr)->driver == STREAM_DRIVER)) {
+ if ((fptr->Fptr)->ENDpos !=
+ maxvalue((fptr->Fptr)->headend , (fptr->Fptr)->datastart -2880)) {
+ ffwend(fptr, 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: %.0f",
+ (double) firstrow);
+ ffpmsg(message);
+ return(*status = BAD_ROW_NUM);
+ }
+ else
+ {
+ sprintf(message, "Starting row number is less than 1: %.0f",
+ (double) 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: %.0f",
+ (double) 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;
+
+ 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 */
+ }
+ else if (*hdutype == BINARY_TBL && *tcode == -TSTRING) {
+ /* variable length string */
+ *incre = 1;
+ *twidth = (long) nelem;
+ }
+
+ 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 + ((LONGLONG)(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 %.0f new rows in table.",
+ (double) nrows);
+ ffpmsg(message);
+ return(*status);
+ }
+ }
+ else
+ {
+ /* update heap starting address */
+ (fptr->Fptr)->heapstart +=
+ ((LONGLONG)(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,", (long) firstrow);
+ ffpmsg(message);
+
+ sprintf(message,
+ "however the HDU only contains %ld group(s).",
+ (long) ((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.",
+ (long) nelem, (long) firstelem);
+ ffpmsg(message);
+ }
+ }
+ else
+ {
+ ffpmsg("Attempt to read past end of table:");
+ sprintf(message,
+ " Table has %.0f rows with %.0f elements per row;",
+ (double) ((fptr->Fptr)->numrows), (double) *repeat);
+ ffpmsg(message);
+
+ sprintf(message,
+ " Tried to read %.0f elements starting at row %.0f, element %.0f.",
+ (double) nelem, (double) firstrow, (double) ((*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 = (long) *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 )
+ {
+ ffgdesll(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, *repeat / 2,
+ heapoffset, status);
+ }
+ else
+ {
+ ffpdes(fptr, colnum, firstrow, *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 %.0f new rows in table.",
+ (double) 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, *repeat / 2,
+ (fptr->Fptr)->heapsize, status);
+ }
+ else
+ {
+ ffpdes(fptr, colnum, firstrow, *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 + ( *repeat * (*incre));
+
+ if (endpos > (fptr->Fptr)->headstart[ (fptr->Fptr)->curhdu + 1])
+ {
+ /* calc the number of blocks that need to be added */
+ nblock = (long) (((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 += ( *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 %.0f rows and tried to read row %.0f.",
+ (double) ((fptr->Fptr)->numrows), (double) firstrow);
+ ffpmsg(message);
+ return(*status = BAD_ROW_NUM);
+ }
+
+ ffgdesll(fptr, colnum, firstrow, &lrepeat, &heapoffset, status);
+ *repeat = 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 */
+ LONGLONG *heapsz, /* O - current size of the heap */
+ LONGLONG *unused, /* O - no. of unused bytes in the heap */
+ LONGLONG *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, theapsz, nbytes;
+ LONGLONG repeat, offset, 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);
+
+ if ((fptr->Fptr)->heapsize > LONG_MAX) {
+ ffpmsg("Heap is too big to test ( > 2**31 bytes). (fftheap)");
+ return(*status = MEMORY_ALLOCATION);
+ }
+
+ theapsz = (long) (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;
+
+ for (ii = 1; ii <= (fptr->Fptr)->numrows; ii++)
+ {
+ ffgdesll(fptr, jj, ii, &repeat, &offset, status);
+ if (typecode == -TBIT)
+ nbytes = (long) (repeat + 7) / 8;
+ else
+ nbytes = (long) 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, buffsize = 10000, nblock, nbytes;
+ LONGLONG unused, overlap;
+ LONGLONG repeat, offset;
+ char *buffer, *tbuff, comm[FLEN_COMMENT];
+ char message[81];
+ LONGLONG pcount;
+ LONGLONG 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 = (char *) 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++)
+ {
+ ffgdesll(tptr, jj, ii, &repeat, &offset, status);
+ if (typecode == -TBIT)
+ nbytes = (long) (repeat + 7) / 8;
+ else
+ nbytes = (long) 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 = (long) (((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 = (long) (( (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) */
+ ffmaky(fptr, 2, status); /* reset to beginning of header */
+
+ ffgkyjj(fptr, "PCOUNT", &pcount, comm, status);
+ if ((fptr->Fptr)->heapsize != pcount)
+ {
+ ffmkyj(fptr, "PCOUNT", (fptr->Fptr)->heapsize, comm, 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) */
+ LONGLONG 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.
+*/
+{
+ LONGLONG lengthjj, heapaddrjj;
+
+ if (ffgdesll(fptr, colnum, rownum, &lengthjj, &heapaddrjj, status) > 0)
+ return(*status);
+
+ /* convert the temporary 8-byte values to 4-byte values */
+ /* check for overflow */
+ if (length) {
+ if (lengthjj > LONG_MAX)
+ *status = NUM_OVERFLOW;
+ else
+ *length = (long) lengthjj;
+ }
+
+ if (heapaddr) {
+ if (heapaddrjj > LONG_MAX)
+ *status = NUM_OVERFLOW;
+ else
+ *heapaddr = (long) heapaddrjj;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgdesll(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number (1 = 1st column of table) */
+ LONGLONG rownum, /* I - row number (1 = 1st row of table) */
+ LONGLONG *length, /* O - number of elements in the row */
+ LONGLONG *heapaddr, /* O - heap pointer to the data */
+ int *status) /* IO - error status */
+/*
+ get (read) the variable length vector descriptor from the binary table.
+ This is similar to ffgdes, except it supports the full 8-byte range of the
+ length and offset values in 'Q' columns, as well as 'P' columns.
+*/
+{
+ LONGLONG bytepos;
+ unsigned int descript4[2] = {0,0};
+ LONGLONG descript8[2] = {0,0};
+ 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;
+ return(*status);
+ }
+
+ bytepos = (fptr->Fptr)->datastart +
+ ((fptr->Fptr)->rowlength * (rownum - 1)) +
+ colptr->tbcol;
+
+ if (colptr->tform[0] == 'P' || colptr->tform[1] == 'P')
+ {
+ /* read 4-byte descriptor */
+ if (ffgi4b(fptr, bytepos, 2, 4, (INT32BIT *) descript4, status) <= 0)
+ {
+ if (length)
+ *length = (LONGLONG) descript4[0]; /* 1st word is the length */
+ if (heapaddr)
+ *heapaddr = (LONGLONG) descript4[1]; /* 2nd word is the address */
+ }
+
+ }
+ else /* this is for 'Q' columns */
+ {
+ /* read 8 byte descriptor */
+ if (ffgi8b(fptr, bytepos, 2, 8, (long *) descript8, status) <= 0)
+ {
+ if (length)
+ *length = descript8[0]; /* 1st word is the length */
+ if (heapaddr)
+ *heapaddr = descript8[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) */
+ LONGLONG firstrow, /* I - first row (1 = 1st row of table) */
+ LONGLONG 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.
+*/
+{
+ LONGLONG rowsize, bytepos;
+ long ii;
+ INT32BIT descript4[2] = {0,0};
+ LONGLONG descript8[2] = {0,0};
+ 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;
+ return(*status);
+ }
+
+ rowsize = (fptr->Fptr)->rowlength;
+ bytepos = (fptr->Fptr)->datastart +
+ (rowsize * (firstrow - 1)) +
+ colptr->tbcol;
+
+ if (colptr->tform[0] == 'P' || colptr->tform[1] == 'P')
+ {
+ /* read 4-byte descriptors */
+ for (ii = 0; ii < nrows; ii++)
+ {
+ /* read descriptors */
+ if (ffgi4b(fptr, bytepos, 2, 4, descript4, status) <= 0)
+ {
+ if (length) {
+ *length = (long) descript4[0]; /* 1st word is the length */
+ length++;
+ }
+
+ if (heapaddr) {
+ *heapaddr = (long) descript4[1]; /* 2nd word is the address */
+ heapaddr++;
+ }
+ bytepos += rowsize;
+ }
+ else
+ return(*status);
+ }
+ }
+ else /* this is for 'Q' columns */
+ {
+ /* read 8-byte descriptors */
+ for (ii = 0; ii < nrows; ii++)
+ {
+ /* read descriptors */
+ if (ffgi8b(fptr, bytepos, 2, 8, (long *) descript8, status) <= 0)
+ {
+ if (length) {
+ if (descript8[0] > LONG_MAX)*status = NUM_OVERFLOW;
+ *length = (long) descript8[0]; /* 1st word is the length */
+ length++;
+ }
+ if (heapaddr) {
+ if (descript8[1] > LONG_MAX)*status = NUM_OVERFLOW;
+ *heapaddr = (long) descript8[1]; /* 2nd word is the address */
+ heapaddr++;
+ }
+ bytepos += rowsize;
+ }
+ else
+ return(*status);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgdessll(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number (1 = 1st column of table) */
+ LONGLONG firstrow, /* I - first row (1 = 1st row of table) */
+ LONGLONG nrows, /* I - number or rows to read */
+ LONGLONG *length, /* O - number of elements in the row */
+ LONGLONG *heapaddr, /* O - heap pointer to the data */
+ int *status) /* IO - error status */
+/*
+ get (read) a range of variable length vector descriptors from the table.
+*/
+{
+ LONGLONG rowsize, bytepos;
+ long ii;
+ unsigned int descript4[2] = {0,0};
+ LONGLONG descript8[2] = {0,0};
+ 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;
+ return(*status);
+ }
+
+ rowsize = (fptr->Fptr)->rowlength;
+ bytepos = (fptr->Fptr)->datastart +
+ (rowsize * (firstrow - 1)) +
+ colptr->tbcol;
+
+ if (colptr->tform[0] == 'P' || colptr->tform[1] == 'P')
+ {
+ /* read 4-byte descriptors */
+ for (ii = 0; ii < nrows; ii++)
+ {
+ /* read descriptors */
+ if (ffgi4b(fptr, bytepos, 2, 4, (INT32BIT *) descript4, status) <= 0)
+ {
+ if (length) {
+ *length = (LONGLONG) descript4[0]; /* 1st word is the length */
+ length++;
+ }
+
+ if (heapaddr) {
+ *heapaddr = (LONGLONG) descript4[1]; /* 2nd word is the address */
+ heapaddr++;
+ }
+ bytepos += rowsize;
+ }
+ else
+ return(*status);
+ }
+ }
+ else /* this is for 'Q' columns */
+ {
+ /* read 8-byte descriptors */
+ for (ii = 0; ii < nrows; ii++)
+ {
+ /* read descriptors */
+ /* cast to type (long *) even though it is actually (LONGLONG *) */
+ if (ffgi8b(fptr, bytepos, 2, 8, (long *) descript8, status) <= 0)
+ {
+ if (length) {
+ *length = descript8[0]; /* 1st word is the length */
+ length++;
+ }
+
+ if (heapaddr) {
+ *heapaddr = descript8[1]; /* 2nd word is the address */
+ heapaddr++;
+ }
+ bytepos += rowsize;
+ }
+ else
+ return(*status);
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpdes(fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number (1 = 1st column of table) */
+ LONGLONG rownum, /* I - row number (1 = 1st row of table) */
+ LONGLONG length, /* I - number of elements in the row */
+ LONGLONG heapaddr, /* I - heap pointer to the data */
+ int *status) /* IO - error status */
+/*
+ put (write) the variable length vector descriptor to the table.
+*/
+{
+ LONGLONG bytepos;
+ unsigned int descript4[2];
+ LONGLONG descript8[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;
+
+ bytepos = (fptr->Fptr)->datastart +
+ ((fptr->Fptr)->rowlength * (rownum - 1)) +
+ colptr->tbcol;
+
+ ffmbyt(fptr, bytepos, IGNORE_EOF, status); /* move to element */
+
+ if (colptr->tform[0] == 'P' || colptr->tform[1] == 'P')
+ {
+ if (length > UINT_MAX || length < 0 ||
+ heapaddr > UINT_MAX || heapaddr < 0) {
+ ffpmsg("P variable length column descriptor is out of range");
+ *status = NUM_OVERFLOW;
+ return(*status);
+ }
+
+ descript4[0] = (unsigned int) length; /* 1st word is the length */
+ descript4[1] = (unsigned int) heapaddr; /* 2nd word is the address */
+
+ ffpi4b(fptr, 2, 4, (INT32BIT *) descript4, status); /* write the descriptor */
+ }
+ else /* this is a 'Q' descriptor column */
+ {
+ descript8[0] = length; /* 1st word is the length */
+ descript8[1] = heapaddr; /* 2nd word is the address */
+
+ ffpi8b(fptr, 2, 8, (long *) descript8, 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];
+ int stdriver;
+
+ /* 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)
+ {
+ urltype2driver("stream://", &stdriver);
+
+ /* don't rescan header in special case of writing to stdout */
+ if (((fptr->Fptr)->driver != stdriver))
+ ffrdef(fptr, status);
+
+ if ((fptr->Fptr)->heapsize > 0) {
+ ffuptf(fptr, status); /* update the variable length TFORM values */
+ }
+
+ ffpdfl(fptr, status); /* insure correct data fill 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;
+
+ /* free the tile-compressed image cache, if it exists */
+ if ((fptr->Fptr)->tiledata) {
+ free((fptr->Fptr)->tiledata);
+ (fptr->Fptr)->tiledata = 0;
+ (fptr->Fptr)->tilerow = 0;
+ (fptr->Fptr)->tiledatasize = 0;
+ (fptr->Fptr)->tiletype = 0;
+ }
+
+ if ((fptr->Fptr)->tilenullarray) {
+ free((fptr->Fptr)->tilenullarray);
+ (fptr->Fptr)->tilenullarray = 0;
+ }
+ }
+ }
+
+ 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;
+ LONGLONG length, addr, maxlen, naxis2, jj;
+ char comment[FLEN_COMMENT], keyname[FLEN_KEYWORD];
+ char tform[FLEN_VALUE], newform[FLEN_VALUE], lenval[40];
+ char card[FLEN_CARD];
+ char message[FLEN_ERRMSG];
+ char *tmp;
+
+ ffmaky(fptr, 2, status); /* reset to beginning of header */
+ ffgkyjj(fptr, "NAXIS2", &naxis2, comment, status);
+ ffgkyj(fptr, "TFIELDS", &tflds, 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' || tform[0] == 'Q' || tform[1] == 'Q')
+ {
+ /* get the max length */
+ maxlen = 0;
+ for (jj=1; jj <= naxis2; jj++)
+ {
+ ffgdesll(fptr, ii, jj, &length, &addr, status);
+
+ if (length > maxlen)
+ maxlen = length;
+ }
+
+ /* construct the new keyword value */
+ strcpy(newform, "'");
+ tmp = strchr(tform, '('); /* truncate old length, if present */
+ if (tmp) *tmp = 0;
+ strcat(newform, tform);
+
+ /* print as double, because the string-to-64-bit */
+ /* conversion is platform dependent (%lld, %ld, %I64d) */
+
+ sprintf(lenval, "(%.0f)", (double) 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;
+ LONGLONG naxis2;
+ LONGLONG 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)
+ {
+ ffmaky(fptr, 2, status);
+ if (ffgkyjj(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 */
+
+ /* print as double because the 64-bit int conversion */
+ /* is platform dependent (%lld, %ld, %I64 ) */
+
+ sprintf(valstring, "%.0f", (double) ((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)
+ {
+ ffmaky(fptr, 2, status);
+ ffgkyjj(fptr, "PCOUNT", &pcount, comm, status);
+ if ((fptr->Fptr)->heapsize != pcount)
+ {
+ ffmkyj(fptr, "PCOUNT", (fptr->Fptr)->heapsize, comm, 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.
+*/
+{
+ LONGLONG 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;
+ LONGLONG 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 = (long) (( (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 (tstatus) break;
+ 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) {
+
+ /* store this position, for later reference */
+ (fptr->Fptr)->ENDpos = endpos;
+
+ 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 */
+
+ /* store this position, for later reference */
+ (fptr->Fptr)->ENDpos = endpos;
+
+ 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];
+ LONGLONG 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 = (long) ((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;
+ LONGLONG 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=(long) (((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;
+ LONGLONG 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 = (long) ((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;
+ LONGLONG 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 = (LONGLONG*) realloc( (fptr->Fptr)->headstart,
+ ((fptr->Fptr)->MAXHDU + 1001) * sizeof(LONGLONG) );
+
+ 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 */
+
+ /* any other needed resets */
+
+ /* reset the dithering offset that may have been calculated for the */
+ /* previous HDU back to the requested default value */
+ (fptr->Fptr)->dither_offset = (fptr->Fptr)->request_dither_offset;
+ }
+
+ 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;
+ LONGLONG 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 - ((LONGLONG)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] -= ((LONGLONG)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_reentrant(void)
+/*
+ Was CFITSIO compiled with the -D_REENTRANT flag? 1 = yes, 0 = no.
+ Note that specifying the -D_REENTRANT flag is required, but may not be
+ sufficient, to ensure that CFITSIO can be safely used in a multi-threaded
+ environoment.
+*/
+{
+#ifdef _REENTRANT
+ return(1);
+#else
+ return(0);
+#endif
+}
+/*--------------------------------------------------------------------------*/
+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 ffgiprll(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) */
+ LONGLONG *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_sizell(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);
+
+ /* reset to beginning of header */
+ ffmaky(fptr, 1, status); /* simply move to beginning of header */
+
+ 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, 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);
+
+ /* reset to beginning of header */
+ ffmaky(fptr, 2, status); /* simply move to beginning of header */
+
+ 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);
+
+ }
+
+ /* 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 = (long) bzero;
+ lngscale = (long) 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)
+ These values are cached for faster access.
+*/
+{
+ 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)
+ {
+ *naxis = (fptr->Fptr)->imgdim;
+ }
+ else if ((fptr->Fptr)->compressimg)
+ {
+ *naxis = (fptr->Fptr)->zndim;
+ }
+ 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)
+ These values are cached for faster access.
+
+*/
+{
+ int ii, naxis;
+
+ 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)
+ {
+ naxis = minvalue((fptr->Fptr)->imgdim, nlen);
+ for (ii = 0; ii < naxis; ii++)
+ {
+ naxes[ii] = (long) (fptr->Fptr)->imgnaxis[ii];
+ }
+ }
+ else if ((fptr->Fptr)->compressimg)
+ {
+ naxis = minvalue( (fptr->Fptr)->zndim, nlen);
+ for (ii = 0; ii < naxis; ii++)
+ {
+ naxes[ii] = (long) (fptr->Fptr)->znaxis[ii];
+ }
+ }
+ else
+ {
+ *status = NOT_IMAGE;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgiszll( fitsfile *fptr, /* I - FITS file pointer */
+ int nlen, /* I - number of axes to return */
+ LONGLONG *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;
+
+ 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)
+ {
+ naxis = minvalue((fptr->Fptr)->imgdim, nlen);
+ for (ii = 0; ii < naxis; ii++)
+ {
+ naxes[ii] = (fptr->Fptr)->imgnaxis[ii];
+ }
+ }
+ else if ((fptr->Fptr)->compressimg)
+ {
+ naxis = minvalue( (fptr->Fptr)->zndim, nlen);
+ for (ii = 0; ii < naxis; ii++)
+ {
+ naxes[ii] = (fptr->Fptr)->znaxis[ii];
+ }
+ }
+ else
+ {
+ *status = NOT_IMAGE;
+ }
+
+ 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];
+ LONGLONG *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 = (LONGLONG*) realloc( (fptr->Fptr)->headstart,
+ (hdunum + 1001) * sizeof(LONGLONG) );
+
+ 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;
+ int slen, putback = 0, chopped = 0;
+ long extver;
+
+ if (*status > 0)
+ return(*status);
+
+ extnum = fptr->HDUposition + 1; /* save the current HDU number */
+
+ /*
+ This is a kludge to deal with a special case where the
+ user specified a hduname that ended with a # character, which
+ CFITSIO previously interpreted as a flag to mean "don't copy any
+ other HDUs in the file into the virtual file in memory. If the
+ remaining hduname does not end with a # character (meaning that
+ the user originally entered a hduname ending in 2 # characters)
+ then there is the possibility that the # character should be
+ treated literally, if the actual EXTNAME also ends with a #.
+ Setting putback = 1 means that we need to test for this case later on.
+ */
+
+ if ((fptr->Fptr)->only_one) { /* if true, name orignally ended with a # */
+ slen = strlen(hduname);
+ if (hduname[slen - 1] != '#') /* This will fail if real EXTNAME value */
+ putback = 1; /* ends with 2 # characters. */
+ }
+
+ for (ii=1; 1; ii++) /* loop over all HDUs until EOF */
+ {
+ tstatus = 0;
+ if (ffmahd(fptr, ii, &hdutype, &tstatus)) /* move to next HDU */
+ {
+ ffmahd(fptr, extnum, 0, status); /* restore original file position */
+ return(*status = BAD_HDU_NUM); /* couldn't find desired HDU */
+ }
+
+ alttype = -1;
+ if (fits_is_compressed_image(fptr, status))
+ alttype = BINARY_TBL;
+
+ /* Does this HDU have a matching type? */
+ if (exttype == ANY_HDU || hdutype == exttype || hdutype == alttype)
+ {
+ ffmaky(fptr, 2, status); /* reset to the 2nd keyword in the header */
+ if (ffgkys(fptr, "EXTNAME", extname, 0, &tstatus) <= 0) /* get keyword */
+ {
+ if (putback) { /* more of the kludge */
+ /* test if the EXTNAME value ends with a #; if so, chop it */
+ /* off before comparing the strings */
+ chopped = 0;
+ slen = strlen(extname);
+ if (extname[slen - 1] == '#') {
+ extname[slen - 1] = '\0';
+ chopped = 1;
+ }
+ }
+
+ /* see if the strings are an exact match */
+ ffcmps(extname, hduname, CASEINSEN, &match, &exact);
+ }
+
+ /* if EXTNAME keyword doesn't exist, or it does not match, then try HDUNAME */
+ if (tstatus || !exact)
+ {
+ tstatus = 0;
+ if (ffgkys(fptr, "HDUNAME", extname, 0, &tstatus) <= 0)
+ {
+ if (putback) { /* more of the kludge */
+ chopped = 0;
+ slen = strlen(extname);
+ if (extname[slen - 1] == '#') {
+ extname[slen - 1] = '\0'; /* chop off the # */
+ chopped = 1;
+ }
+ }
+
+ /* see if the strings are an exact match */
+ ffcmps(extname, hduname, CASEINSEN, &match, &exact);
+ }
+ }
+
+ if (!tstatus && exact) /* found a matching name */
+ {
+ 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)
+ {
+ if (chopped) {
+ /* The # was literally part of the name, not a flag */
+ (fptr->Fptr)->only_one = 0;
+ }
+ return(*status); /* found matching name and vers */
+ }
+ }
+ else
+ {
+ if (chopped) {
+ /* The # was literally part of the name, not a flag */
+ (fptr->Fptr)->only_one = 0;
+ }
+ return(*status); /* found matching name */
+ }
+ } /* end of !tstatus && exact */
+
+ } /* end of matching HDU type */
+ } /* end of loop over HDUs */
+}
+/*--------------------------------------------------------------------------*/
+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;
+ LONGLONG 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;
+ LONGLONG 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 = (long) (((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 + ((LONGLONG) 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 += ((LONGLONG) nblock * 2880);
+
+ /* update following HDU addresses */
+ for (ii = (fptr->Fptr)->curhdu; ii <= (fptr->Fptr)->maxhdu; ii++)
+ (fptr->Fptr)->headstart[ii + 1] += ((LONGLONG) 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'
+ ZSIMPLE, ZTENSION, ZEXTEND, ZBLOCKED, ZPCOUNT, ZGCOUNT
+
+ 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:
+ WCAXES, 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 (FSTRNCMP (card1, "SIMPLE ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "TENSION", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "EXTEND ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "BLOCKED", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "PCOUNT ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ else if (FSTRNCMP (card1, "GCOUNT ", 7) == 0)
+ return (TYP_CMPRS_KEY);
+ }
+ else if (*card == ' ')
+ {
+ 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 (tcard, "COMMENT and Astrophysics', volume 376, page 3",
+ 47) == 0)
+ return (TYP_STRUC_KEY);
+
+ /* original COMMENT strings from 1993 - 2001 */
+ if (FSTRNCMP (tcard, "COMMENT FITS (Flexible Image Transport System",
+ 47) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (tcard, "COMMENT Astrophysics Supplement Series v44/p3",
+ 47) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (tcard, "COMMENT Contact the NASA Science Office of St",
+ 47) == 0)
+ return (TYP_STRUC_KEY);
+ if (FSTRNCMP (tcard, "COMMENT FITS Definition document #100 and oth",
+ 47) == 0)
+ return (TYP_STRUC_KEY);
+
+ if (*(card + 7) == ' ')
+ 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, "RDER",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "SYER",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);
+ if (FSTRNCMP (card1, "ATE-OBS", 7) == 0)
+ return (TYP_REFSYS_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, "QUI",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ 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) == ' ')
+ 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);
+ if (FSTRNCMP (card1, "ONP",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "ATP",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ }
+ else if (*card == 'M')
+ {
+ if (FSTRNCMP (card1, "JD-OBS ", 7) == 0)
+ return (TYP_REFSYS_KEY);
+ if (FSTRNCMP (card1, "JDOB",4) == 0)
+ {
+ if (*(card+5) >= '0' && *(card+5) <= '9')
+ 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);
+ if (*card1 == 'C')
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (*card1 == 'V')
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (*card1 == 'S')
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_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);
+ if (FSTRNCMP (card1, "ADE",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ 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, "CTY",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '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, "CUN",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '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, "CRV",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '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, "CRP",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '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, "CDE",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CRD",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CSY",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "WCS",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "C",1) == 0)
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "P",1) == 0)
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "V",1) == 0)
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "S",1) == 0)
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ }
+ else if (*card == 'X')
+ {
+ if (FSTRNCMP (card1, "TENSION", 7) == 0)
+ return (TYP_STRUC_KEY);
+ }
+ else if (*card == 'W')
+ {
+ if (FSTRNCMP (card1, "CSAXES", 6) == 0)
+ return (TYP_WCS_KEY);
+ if (FSTRNCMP (card1, "CSNAME", 6) == 0)
+ return (TYP_WCS_KEY);
+ if (FSTRNCMP (card1, "CAX", 3) == 0)
+ {
+ if (*(card + 4) >= '0' && *(card + 4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CSN", 3) == 0)
+ {
+ if (*(card + 4) >= '0' && *(card + 4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ }
+
+ else if (*card >= '0' && *card <= '9')
+ {
+ if (*card1 == 'C')
+ {
+ if (FSTRNCMP (card1, "CTYP",4) == 0)
+ {
+ if (*card5 >= '0' && *card5 <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CTY",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '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, "CUN",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '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, "CRV",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '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, "CRP",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '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, "CDE",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CRD",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "CSY",3) == 0)
+ {
+ if (*(card+4) >= '0' && *(card+4) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ }
+ else if (FSTRNCMP (card1, "V",1) == 0)
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (FSTRNCMP (card1, "S",1) == 0)
+ {
+ if (*(card + 2) >= '0' && *(card + 2) <= '9')
+ return (TYP_WCS_KEY);
+ }
+ else if (*card1 >= '0' && *card1 <= '9')
+ { /* 2 digits at beginning of keyword */
+
+ if ( (*(card + 2) == 'P') && (*(card + 3) == 'C') )
+ {
+ if (*(card + 4) >= '0' && *(card + 4) <= '9')
+ return (TYP_WCS_KEY); /* ijPCn keyword */
+ }
+ else if ( (*(card + 2) == 'C') && (*(card + 3) == 'D') )
+ {
+ if (*(card + 4) >= '0' && *(card + 4) <= '9')
+ return (TYP_WCS_KEY); /* ijCDn keyword */
+ }
+ }
+
+ }
+
+ 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 ffinttyp(char *cval, /* I - formatted string representation of the integer */
+ int *dtype, /* O - datatype code: TBYTE, TSHORT, TUSHORT, etc */
+ int *negative, /* O - is cval negative? */
+ int *status) /* IO - error status */
+/*
+ determine implicit datatype of input integer string.
+ This assumes that the string conforms to the FITS standard
+ for integer keyword value, so may not detect all invalid formats.
+*/
+{
+ int ii, len;
+ char *p;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ *dtype = 0; /* initialize to NULL */
+ p = cval;
+
+ if (*p == '+') {
+ p++; /* ignore leading + sign */
+ } else if (*p == '-') {
+ p++;
+ *negative = 1; /* this is a negative number */
+ }
+
+ if (*p == '0') {
+ while (*p == '0') p++; /* skip leading zeros */
+
+ if (*p == 0) { /* the value is a string of 1 or more zeros */
+ *dtype = TSBYTE;
+ return(*status);
+ }
+ }
+
+ len = strlen(p);
+ for (ii = 0; ii < len; ii++) {
+ if (!isdigit(*(p+ii))) {
+ *status = BAD_INTKEY;
+ return(*status);
+ }
+ }
+
+ /* check for unambiguous cases, based on length of the string */
+ if (len == 0) {
+ *status = VALUE_UNDEFINED;
+ } else if (len < 3) {
+ *dtype = TSBYTE;
+ } else if (len == 4) {
+ *dtype = TSHORT;
+ } else if (len > 5 && len < 10) {
+ *dtype = TINT;
+ } else if (len > 10 && len < 19) {
+ *dtype = TLONGLONG;
+ } else if (len > 19) {
+ *status = BAD_INTKEY;
+ } else {
+
+ if (!(*negative)) { /* positive integers */
+ if (len == 3) {
+ if (strcmp(p,"127") <= 0 ) {
+ *dtype = TSBYTE;
+ } else if (strcmp(p,"255") <= 0 ) {
+ *dtype = TBYTE;
+ } else {
+ *dtype = TSHORT;
+ }
+ } else if (len == 5) {
+ if (strcmp(p,"32767") <= 0 ) {
+ *dtype = TSHORT;
+ } else if (strcmp(p,"65535") <= 0 ) {
+ *dtype = TUSHORT;
+ } else {
+ *dtype = TINT;
+ }
+ } else if (len == 10) {
+ if (strcmp(p,"2147483647") <= 0 ) {
+ *dtype = TINT;
+ } else if (strcmp(p,"4294967295") <= 0 ) {
+ *dtype = TUINT;
+ } else {
+ *dtype = TLONGLONG;
+ }
+ } else if (len == 19) {
+ if (strcmp(p,"9223372036854775807") <= 0 ) {
+ *dtype = TLONGLONG;
+ } else {
+ *status = BAD_INTKEY;
+ }
+ }
+
+ } else { /* negative integers */
+ if (len == 3) {
+ if (strcmp(p,"128") <= 0 ) {
+ *dtype = TSBYTE;
+ } else {
+ *dtype = TSHORT;
+ }
+ } else if (len == 5) {
+ if (strcmp(p,"32768") <= 0 ) {
+ *dtype = TSHORT;
+ } else {
+ *dtype = TINT;
+ }
+ } else if (len == 10) {
+ if (strcmp(p,"2147483648") <= 0 ) {
+ *dtype = TINT;
+ } else {
+ *dtype = TLONGLONG;
+ }
+ } else if (len == 19) {
+ if (strcmp(p,"9223372036854775808") <= 0 ) {
+ *dtype = TLONGLONG;
+ } else {
+ *status = BAD_INTKEY;
+ }
+ }
+ }
+ }
+
+ 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 ffc2xx(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 */
+ LONGLONG *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')
+ ffc2jj(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 ffc2j(char *cval, /* I - string representation of the value */
+ LONGLONG *ival, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert formatted string to a LONGLONG 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 */
+ ffc2xx(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) LONGLONG_MAX || dval < (double) LONGLONG_MIN)
+ *status = NUM_OVERFLOW;
+ else
+ *ival = (LONGLONG) dval;
+ }
+ }
+ else if (dtype == 'F')
+ {
+ if (dval > (double) LONGLONG_MAX || dval < (double) LONGLONG_MIN)
+ *status = NUM_OVERFLOW;
+ else
+ *ival = (LONGLONG) dval;
+ }
+ else if (dtype == 'L')
+ {
+ *ival = (LONGLONG) lval;
+ }
+
+ if (*status > 0)
+ {
+ *ival = 0;
+ strcpy(msg,"Error in ffc2j evaluating string as a long 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 ffc2jj(char *cval, /* I - string representation of the value */
+ LONGLONG *ival, /* O - numerical value of the input string */
+ int *status) /* IO - error status */
+/*
+ convert null-terminated formatted string to an long long integer value
+*/
+{
+ char *loc, msg[81];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ errno = 0;
+ *ival = 0;
+
+#if defined(_MSC_VER)
+
+ /* Microsoft Visual C++ 6.0 does not have the strtoll function */
+ *ival = _atoi64(cval);
+ loc = cval;
+ while (*loc == ' ') loc++; /* skip spaces */
+ if (*loc == '-') loc++; /* skip minus sign */
+ if (*loc == '+') loc++; /* skip plus sign */
+ while (isdigit(*loc)) loc++; /* skip digits */
+
+#elif (USE_LL_SUFFIX == 1)
+ *ival = strtoll(cval, &loc, 10); /* read the string as an integer */
+#else
+ *ival = strtol(cval, &loc, 10); /* read the string as an integer */
+#endif
+
+ /* check for read error, or junk following the integer */
+ if (*loc != '\0' && *loc != ' ' )
+ *status = BAD_C2I;
+
+ if (errno == ERANGE)
+ {
+ strcpy(msg,"Range Error in ffc2jj converting string to longlong 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], tval[73];
+ struct lconv *lcc = 0;
+ static char decimalpt = 0;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (!decimalpt) { /* only do this once for efficiency */
+ lcc = localeconv(); /* set structure containing local decimal point symbol */
+ decimalpt = *(lcc->decimal_point);
+ }
+
+ errno = 0;
+ *fval = 0.;
+
+ if (strchr(cval, 'D') || decimalpt == ',') {
+ /* strtod expects a comma, not a period, as the decimal point */
+ strcpy(tval, cval);
+
+ /* The C language does not support a 'D'; replace with 'E' */
+ if (loc = strchr(tval, 'D')) *loc = 'E';
+
+ if (decimalpt == ',') {
+ /* strtod expects a comma, not a period, as the decimal point */
+ if (loc = strchr(tval, '.')) *loc = ',';
+ }
+
+ *fval = (float) strtod(tval, &loc); /* read the string as an float */
+ } else {
+ *fval = (float) strtod(cval, &loc);
+ }
+
+ /* 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 *loc, msg[81], tval[73];
+ struct lconv *lcc = 0;
+ static char decimalpt = 0;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (!decimalpt) { /* only do this once for efficiency */
+ lcc = localeconv(); /* set structure containing local decimal point symbol */
+ decimalpt = *(lcc->decimal_point);
+ }
+
+ errno = 0;
+ *dval = 0.;
+
+ if (strchr(cval, 'D') || decimalpt == ',') {
+ /* need to modify a temporary copy of the string before parsing it */
+ strcpy(tval, cval);
+ /* The C language does not support a 'D'; replace with 'E' */
+ if (loc = strchr(tval, 'D')) *loc = 'E';
+
+ if (decimalpt == ',') {
+ /* strtod expects a comma, not a period, as the decimal point */
+ if (loc = strchr(tval, '.')) *loc = ',';
+ }
+
+ *dval = strtod(tval, &loc); /* read the string as an double */
+ } else {
+ *dval = strtod(cval, &loc);
+ }
+
+ /* 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/vendor/cfitsio/fitsfile.tpt b/vendor/cfitsio/fitsfile.tpt
new file mode 100644
index 00000000..44d4aa1b
--- /dev/null
+++ b/vendor/cfitsio/fitsfile.tpt
@@ -0,0 +1,8 @@
+xtension = 'bintable'
+naxis2 = 20
+TTYPE1 = 'SIZE' / comment here
+TFORM1 = 1J / my first column
+TTYPE2 = 'DISTANCE'
+TFORM2 = 1E / my second column
+mykey = 16 / this is my comment
+
diff --git a/vendor/cfitsio/fitsio.doc b/vendor/cfitsio/fitsio.doc
new file mode 100644
index 00000000..1da75b14
--- /dev/null
+++ b/vendor/cfitsio/fitsio.doc
@@ -0,0 +1,6607 @@
+ FITSIO - An Interface to FITS Format Files for Fortran Programmers
+
+ William D Pence, HEASARC, NASA/GSFC
+ Version 3.0
+
+
+[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: William.D.Pence@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]
+ [--enable-sse2] [--enable-ssse3]
+ > 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 optional --enable-sse2 and --enable-ssse3 flags will cause configure to
+attempt to build CFITSIO using faster byte-swapping algorithms.
+See the "Optimizing Programs" section of this manual for
+more information about these options.
+
+By default, the Makefile will be configured to build 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 statically 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\_3xxx\_vcc.zip, where
+'3xxx' 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
+boundaries 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.
+
+On Windows platforms, linking Fortran programs with a C library
+often depends on the particular compilers involved. Some users have
+found the following commands work when using the Intel Fortran compiler:
+-
+ifort /libs.dll cfitsio.lib /MD testf77.f /Gm
+
+or possibly,
+
+ifort /libs:dll cfitsio.lib /MD /fpp /extfpp:cfortran.h,fitsio.h
+ /iface:cvf testf77.f
+-
+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 performs 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
+necessary 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.
+
+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."
+
+**G. Acknowledgments
+
+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.
+
+Martin Reinecke (Max Planck Institute, Garching)) provided the modifications to
+cfortran.h that are necessary to support 64-bit integer values when calling
+C routines from fortran programs. The cfortran.h macros were originally developed
+by Burkhard Burow (CERN).
+
+Julian Taylor (ESO, Garching) provided the fast byte-swapping algorithms
+that use the SSE2 and SSSE3 machine instructions available on x86\_64 CPUs.
+
+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. Six different primary
+datatypes are supported: Unsigned 8-bit bytes, 16, 32, and 64-bit signed
+integers, and 32 and 64-bit floating point reals. FITS also has a
+convention for storing 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, 64, -32, -64 for
+unsigned 8--bit byte, 16--bit signed integer, 32--bit signed integer,
+64--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 further information about the FITS format and related software
+packages.
+
+
+
+*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.
+
+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, 32-bit integer)
+ k - long long integer (I*8, 64-bit integer)
+ 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)' or `1Qt(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. This is also not
+supported when reading floating-point images that have been compressed
+with the FITS tiled image compression convention that is discussed in
+section 5.6; the pixels values in tile compressed images are
+represented by scaled integers, and a reserved integer value
+(not a NaN) is used to represent undefined pixels.
+
+
+**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
+
+CFITSIO supports 2 ways to specify that a character column in a binary
+table contains an array of fixed-length strings. The first way, which
+is officially supported by the FITS Standard document, uses the TDIMn keyword.
+For example, if TFORMn = '60A' and TDIMn = '(12,5)' then that
+column will be interpreted as containing an array of 5 strings, each 12
+characters long.
+
+FITSIO also supports 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.
+
+***2. Optimization Strategies
+
+1. Because the data in FITS files is always stored in "big-endian" byte order,
+where the first byte of numeric values contains the most significant bits and the
+last byte contains the least significant bits, CFITSIO must swap the order of the bytes
+when reading or writing FITS files when running on little-endian machines (e.g.,
+Linux and Microsoft Windows operating systems running on PCs with x86 CPUs).
+
+On fairly new CPUs that support "SSSE3" machine instructions
+(e.g., starting with Intel Core 2 CPUs in 2007, and in AMD CPUs
+beginning in 2011) significantly faster 4-byte and 8-byte swapping
+algorithms are available. These faster byte swapping functions are
+not used by default in CFITSIO (because of the potential code
+portablility issues), but users can enable them on supported
+platforms by adding the appropriate compiler flags (-mssse3 with gcc
+or icc on linux) when compiling the swapproc.c source file, which will
+allow the compiler to generate code using the SSSE3 instruction set.
+A convenient way to do this is to configure the CFITSIO library
+with the following command:
+-
+ > ./configure --enable-ssse3
+-
+Note, however, that a binary executable file that is
+created using these faster functions will only run on
+machines that support the SSSE3 machine instructions. It will
+crash on machines that do not support them.
+
+For faster 2-byte swaps on virtually all x86-64 CPUs (even those that
+do not support SSSE3), a variant using only SSE2 instructions exists.
+SSE2 is enabled by default on x86\_64 CPUs with 64-bit operating systems
+(and is also automatically enabled by the --enable-ssse3 flag).
+When running on x86\_64 CPUs with 32-bit operating systems, these faster
+2-byte swapping algorithms are not used by default in CFITSIO, but can be
+enabled explicitly with:
+-
+./configure --enable-sse2
+-
+Preliminary testing indicates that these SSSE3 and SSE2 based
+byte-swapping algorithms can boost the CFITSIO performance when
+reading or writing FITS images by 20\% - 30\% or more.
+It is important to note, however, that compiler optimization must be
+turned on (e.g., by using the -O1 or -O2 flags in gcc) when building
+programs that use these fast byte-swapping algorithms in order
+to reap the full benefit of the SSSE3 and SSE2 instructions; without
+optimization, the code may actually run slower than when using
+more traditional byte-swapping techniques.
+
+2. 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.
+
+3. 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
+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.
+
+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,
+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.
+
+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 ftpscl or
+fttscl) and then read or write the raw unscaled values in the FITS
+file.
+
+7. 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.
+
+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. In practice, this is probably not a significant efficiency issue.
+
+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 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.
+
+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
+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?).
+
+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.
+
+
+
+*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 FTDKOPEN 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 FTDKINIT 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 existing primary array will be
+ converted to an IMAGE extension. The new extension (or primary
+ array) will become the CHDU. The FTIIMGLL routine is identical
+ to the FTIIMG routine except that the 4th parameter (the length
+ of each axis) is an array of 64-bit integers rather than an array
+> of 32-bit integers.
+-
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+ FTIIMGLL(unit,bitpix,naxis,naxesll, > 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. The FTITABLL
+ routine is identical
+ to the FTITAB routine except that the 2nd and 3rd parameters (that give
+ the size of the table) are 64-bit integers rather than
+ 32-bit integers. Under normal circumstances, the nrows and nrowsll
+ paramenters should have a value of 0; CFITSIO will automatically update
+> the number of rows as data is written to the table.
+-
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+ FTITABLL(unit,rowlenll,nrowsll,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. The FTIBINLL
+ routine is identical
+ to the FTIBIN routine except that the 2nd parameter (that gives
+ the length of the table) is a 64-bit integer rather than
+ a 32-bit integer. Under normal circumstances, the nrows and nrowsll
+ paramenters should have a value of 0; CFITSIO will automatically update
+> the number of rows as data is written to the table.
+-
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+ FTIBINLL(unit,nrowsll,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[JKLS](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[EDJKLS](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[BIJKED](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[BIJKED](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[SLBIJKEDCM](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[SBIJKEDCM](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. The
+FTDKOPEN routine simply opens the specified file without trying to
+interpret the filename using the extended filename syntax. FTDOPN opens
+the file and
+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)
+ FTDKOPEN(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.
+ The FTDKINIT 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 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 (0), ASCII\_TBL (1), BINARY\_TBL (2), or ANY\_HDU (-1)
+ 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 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 existing primary array will be
+ converted to an IMAGE extension. The new extension (or primary
+ array) will become the CHDU. The FTIIMGLL routine is identical
+ to the FTIIMG routine except that the 4th parameter (the length
+ of each axis) is an array of 64-bit integers rather than an array
+> of 32-bit integers.
+-
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+ FTIIMGLL(unit,bitpix,naxis,naxesll, > 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. The FTITABLL
+ routine is identical
+ to the FTITAB routine except that the 2nd and 3rd parameters (that give
+ the size of the table) are 64-bit integers rather than
+> 32-bit integers.
+-
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+ FTITABLL(unit,rowlenll,nrowsll,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. The FTIBINLL
+ routine is identical
+ to the FTIBIN routine except that the 2nd parameter (that gives
+ the length of the table) is a 64-bit integer rather than
+> a 32-bit integer.
+-
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+ FTIBINLL(unit,nrowsll,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. The FTRSIMLL routine is identical
+ to the FTRSIM routine except that the 4th parameter (the length
+ of each axis) is an array of 64-bit integers rather than an array
+> of 32-bit integers.
+-
+ FTRSIM(unit,bitpix,naxis,naxes,status)
+ FTRSIMLL(unit,bitpix,naxis,naxesll,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' (an integer parameter) is
+ not equal to 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 not equal
+ to zero, 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[JKLS](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[JKLS](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.
+-
+ FTCPKY(inunit, 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[JKLS](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[EDJKLS](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[EDJKLS](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[JKLS](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[JKLS](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,
+ 32. or 64 This does not create or change the value of the BLANK keyword in
+ the header. FTPNULLL is identical to FTPNUL except that the blank
+> value is a 64-bit integer instead of a 32-bit integer.
+-
+ FTPNUL(unit,blank, > status)
+ FTPNULLL(unit,blankll, > 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', 'J', or 'K').
+ This does not create or change the value of the TNULLn keyword.
+ FTTNULLL is identical to FTTNUL except that the tnull
+> value is a 64-bit integer instead of a 32-bit integer.
+-
+ FTTNUL(unit,colnum,tnull > status)
+ FTTNULLL(unit,colnum,tnullll > 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, 64, -32, or -64 corresponding to unsigned byte,
+ signed 2-byte integer, signed 4-byte integer, signed 8-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. The FTGISZLL
+> routine returns an array of 64-bit integers instead of 32-bit integers.
+-
+ FTGISZ(unit, maxdim, > naxes,status)
+ FTGISZLL(unit, maxdim, > naxesll,status)
+-
+>4 Get the parameters that define the type and size of the image. This
+ routine simply combines calls to the above 3 routines. The FTGIPRLL
+> routine returns an array of 64-bit integers instead of 32-bit integers.
+
+-
+ FTGIPR(unit, maxdim, > bitpix, naxis, naxes, int *status)
+ FTGIPRLL(unit, maxdim, > bitpix, naxis, naxesll, int *status)
+-
+>>5 Put elements into the data array
+-
+ FTPPR[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](unit,group,fpixel,nelements, > values,flagvals,anyf,status)
+-
+>>10 Put values into group parameters
+-
+ FTPGP[BIJKED](unit,group,fparm,nparm,values, > status)
+-
+>>11 Get values from group parameters
+-
+ FTGGP[BIJKED](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[BIJKED](unit,group,dim1,naxis1,naxis2,image, > status)
+-
+>>12 Put 3-D cube into the data array
+-
+ FTP3D[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](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. The FTGNRWLL routine is identical to FTGNRW except
+ that the number of rows is returned as a 64-bit integer rather
+> than a 32-bit integer.
+-
+ FTGNRW(unit, > nrows, status)
+ FTGNRWLL(unit, > nrowsll, 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.
+-
+ 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 TDIMn
+ keyword may also be used to specify the unit string length; The pair
+ of keywords TFORMn = '60A' and TDIMn = '(12,5)' would have the
+ same effect as TFORMn = '60A12').
+
+ 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 multidimensional 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 or FROWLL equals 0 then the blank rows are inserted at the beginning of the
+ table. These routines modify the NAXIS2 keyword to reflect the new
+ number of rows in the table. Note that it is *not* necessary to insert rows in a table before
+ writing data to those rows (indeed, it would be inefficient to do so).
+ Instead, one may simply write data to any row of the table, whether that
+> row of data already exists or not.
+-
+ FTIROW(unit,frow,nrows, > status)
+ FTIROWLL(unit,frowll,nrowsll, > status)
+-
+>2 Delete rows from an existing ASCII or binary table (in the CDU).
+ The NROWS (or NROWSLL) is the number of rows are deleted, starting
+ with row FROW (or FROWLL), and
+ any remaining rows in the table are shifted up to fill in the space.
+ These routines modify the NAXIS2 keyword to reflect the new number
+> of rows in the table.
+-
+ FTDROW(unit,frow,nrows, > status)
+ FTDROWLL(unit,frowll,nrowsll, > 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.
+Note that it is *not* necessary to insert rows in a table before
+writing data to those rows (indeed, it would be inefficient to do so).
+Instead, one may simply write data to any row of the table, whether that
+row of data already exists or not.
+
+ 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).
+
+ The alternate version of these routines, whose names end in 'LL'
+ after the datatype character, support large tables with more then
+ 2*31 rows. When calling these routines, the frow and felem parameters
+> *must* be 64-bit integer*8 variables, instead of normal 4-byte integers.
+-
+ FTPCL[SLBIJKEDCM](unit,colnum,frow,felem,nelements,values, > status)
+ FTPCL[LBIJKEDCM]LL(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. 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.
+
+ The alternate version of these routines, whose names end in 'LL'
+ after the datatype character, support large tables with more then
+ 2*31 rows. When calling these routines, the frow and felem parameters
+> *must* be 64-bit integer*8 variables, instead of normal 4-byte integers.
+-
+ FTPCN[SBIJKED](unit,colnum,frow,felem,nelements,values,nullval > status)
+ FTPCN[SBIJKED]LL(unit,colnum,(I*8) frow,(I*8) 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).
+
+ The alternate version of these routines, whose names end in 'LL'
+ after the datatype character, support large tables with more then
+ 2*31 rows. When calling these routines, the frow and felem parameters
+> *must* be 64-bit integer*8 variables, instead of normal 4-byte integers.
+-
+ FTGCL(unit,colnum,frow,felem,nelements, > values,status)
+ FTGCV[SBIJKEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+ FTGCV[BIJKEDCM]LL(unit,colnum,(I*8) frow, (I*8) 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).
+
+ The alternate version of these routines, whose names end in 'LL'
+ after the datatype character, support large tables with more then
+ 2*31 rows. When calling these routines, the frow and felem parameters
+> *must* be 64-bit integer*8 variables, instead of normal 4-byte integers.
+-
+ FTGCF[SLBIJKEDCM](unit,colnum,frow,felem,nelements, >
+ values,flagvals,anyf,status)
+ FTGCF[BIJKED]LL(unit,colnum, (I*8) frow, (I*8) 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[BIJKED](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[BIJKED](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)
+ FTGDESLL(unit,colnum,rownum, > nelementsll,offsetll,status)
+
+ FFGDESS(unit,colnum,firstrow,nrows > nelements,offset, status)
+ FFGDESSLL(unit,colnum,firstrow,nrows > nelementsll,offsetll, status)
+-
+>12 Write the descriptor for a variable length column in a binary table.
+ These subroutines 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)
+ FTPDESLL(unit,colnum,rownum,nelementsll,offsetll, > 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 output
+table is not empty, then this routine will append the new
+selected rows after the existing rows. 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 dimension and type information
+on the result. The returned dimensions correspond to a single row entry
+of the requested expression, and are equivalent to the result of fits\_read\_tdim().
+Note that strings are considered to be one element regardless of string length.
+>If maxdim == 0, then naxes is optional.
+-
+ FTTEXP(unit, expr, maxdim > 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 external 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. The '\#' character will match any consecutive string
+ of decimal digits (0 - 9). 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, staThe '\#' character will match any consecutive string
+ of decimal digits (0 - 9). tus)
+-
+>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.
+ If the value token is a character string that contains 1 or more
+ embedded blank space characters or slash ('/') characters then the
+> entire character string must be enclosed in single quotes.
+
+>- The COMMENT token is optional, but if present must be separated from
+> the VALUE token by a blank space or a '/' character.
+
+>- 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)
+-
+
+
+
+*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 repeatedly 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.
+
+
+
+*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
+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 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
+ supports username:password just like the ftp driver.
+ Proxy HTTP servers are supported using the http_proxy
+ environment variable (see following note).
+ stream:// - special driver to read an input FITS file from the stdin
+ stream, and/or write an output FITS file to the stdout
+ stream. This driver is fragile and has limited
+ functionality (see the following note).
+ gsiftp:// - access files on a computational grid using the gridftp
+ protocol in the Globus toolkit (see following note).
+ 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 stream filetype driver
+
+The stream driver can be used to efficiently read a FITS file from the stdin
+file stream or write a FITS to the stdout file stream. However, because these
+input and output streams must be accessed sequentially, the FITS file reading or
+writing application must also read and write the file sequentially, at least
+within the tolerances described below.
+
+CFITSIO supports 2 different methods for accessing FITS files on the stdin and
+stdout streams. The original method, which is invoked by specifying a dash
+character, "-", as the name of the file when opening or creating it, works by
+storing a complete copy of the entire FITS file in memory. In this case, when
+reading from stdin, CFITSIO will copy the entire stream into memory before doing
+any processing of the file. Similarly, when writing to stdout, CFITSIO will
+create a copy of the entire FITS file in memory, before finally flushing it out
+to the stdout stream when the FITS file is closed. Buffering the entire FITS
+file in this way allows the application to randomly access any part of the FITS
+file, in any order, but it also requires that the user have sufficient available
+memory (or virtual memory) to store the entire file, which may not be possible
+in the case of very large files.
+
+The newer stream filetype provides a more memory-efficient method of accessing
+FITS files on the stdin or stdout streams. Instead of storing a copy of the
+entire FITS file in memory, CFITSIO only uses a set of internal buffer which by
+default can store 40 FITS blocks, or about 100K bytes of the FITS file. The
+application program must process the FITS file sequentially from beginning to
+end, within this 100K buffer. Generally speaking the application program must
+conform to the following restrictions:
+
+\begin{itemize}
+\item
+The program must finish reading or writing the header keywords
+before reading or writing any data in the HDU.
+\item
+The HDU can contain at most about 1400 header keywords. This is the
+maximum that can fit in the nominal 40 FITS block buffer. In principle,
+this limit could be increased by recompiling CFITSIO with a larger
+buffer limit, which is set by the NIOBUF parameter in fitsio2.h.
+\item
+The program must read or write the data in a sequential manner from the
+beginning to the end of the HDU. Note that CFITSIO's internal
+100K buffer allows a little latitude in meeting this requirement.
+\item
+The program cannot move back to a previous HDU in the FITS file.
+\item
+Reading or writing of variable length array columns in binary tables is not
+supported on streams, because this requires moving back and forth between the
+fixed-length portion of the binary table and the following heap area where the
+arrays are actually stored.
+\item
+Reading or writing of tile-compressed images is not supported on streams,
+because the images are internally stored using variable length arrays.
+\end{itemize}
+
+***3. Notes about the gsiftp filetype
+
+DEPENDENCIES: Globus toolkit (2.4.3 or higher) (GT) should be installed.
+There are two different ways to install GT:
+
+1) goto the globus toolkit web page www.globus.org and follow the
+ download and compilation instructions;
+
+2) goto the Virtual Data Toolkit web page http://vdt.cs.wisc.edu/
+ and follow the instructions (STRONGLY SUGGESTED);
+
+Once a globus client has been installed in your system with a specific flavour
+it is possible to compile and install the CFITSIO libraries.
+Specific configuration flags must be used:
+
+1) --with-gsiftp[[=PATH]] Enable Globus Toolkit gsiftp protocol support
+ PATH=GLOBUS\_LOCATION i.e. the location of your globus installation
+
+2) --with-gsiftp-flavour[[=PATH] defines the specific Globus flavour
+ ex. gcc32
+
+Both the flags must be used and it is mandatory to set both the PATH and the
+flavour.
+
+USAGE: To access files on a gridftp server it is necessary to use a gsiftp prefix:
+
+example: gsiftp://remote\_server\_fqhn/directory/filename
+
+The gridftp driver uses a local buffer on a temporary file the file is located
+in the /tmp directory. If you have special permissions on /tmp or you do not have a /tmp
+directory, it is possible to force another location setting the GSIFTP\_TMPFILE environment
+variable (ex. export GSIFTP\_TMPFILE=/your/location/yourtmpfile).
+
+Grid FTP supports multi channel transfer. By default a single channel transmission is
+available. However, it is possible to modify this behavior setting the GSIFTP\_STREAMS
+environment variable (ex. export GSIFTP\_STREAMS=8).
+
+***4. 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.
+
+***5. 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 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. 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. Image Transform Filters
+
+CFITSIO can apply a user-specified mathematical function to the value
+of every pixel in a FITS image, thus creating a new virtual image
+in computer memory that is then opened and read by the application
+program. The original FITS image is not modified by this process.
+
+The image transformation specifier is appended to the input
+FITS file name and is enclosed in square brackets. It begins with the
+letters 'PIX' to distinguish it from other types of FITS file filters
+that are recognized by CFITSIO. The image transforming function may
+use any of the mathematical operators listed in the following
+'Row Filtering Specification' section of this document.
+Some examples of image transform filters are:
+-
+ [pix X * 2.0] - multiply each pixel by 2.0
+ [pix sqrt(X)] - take the square root of each pixel
+ [pix X + #ZEROPT - add the value of the ZEROPT keyword
+ [pix X>0 ? log10(X) : -99.] - if the pixel value is greater
+ than 0, compute the base 10 log,
+ else set the pixel = -99.
+-
+Use the letter 'X' in the expression to represent the current pixel value
+in the image. The expression is evaluated
+independently for each pixel in the image and may be a function of 1) the
+original pixel value, 2) the value of other pixels in the image at
+a given relative offset from the position of the pixel that is being
+evaluated, and 3) the value of
+any header keywords. Header keyword values are represented
+by the name of the keyword preceded by the '\#' sign.
+
+
+To access the the value of adjacent pixels in the image,
+specify the (1-D) offset from the current pixel in curly brackets.
+For example
+-
+ [pix (x{-1} + x + x{+1}) / 3]
+-
+will replace each pixel value with the running mean of the values of that
+pixel and it's 2 neighboring pixels. Note that in this notation the image
+is treated as a 1-D array, where each row of the image (or higher dimensional
+cube) is appended one after another in one long array of pixels.
+It is possible to refer to pixels
+in the rows above or below the current pixel by using the value of the
+NAXIS1 header keyword. For example
+-
+ [pix (x{-#NAXIS1} + x + x{#NAXIS1}) / 3]
+-
+will compute the mean of each image pixel and the pixels immediately
+above and below it in the adjacent rows of the image.
+The following more complex example
+creates a smoothed virtual image where each pixel
+is a 3 x 3 boxcar average of the input image pixels:
+-
+ [pix (X + X{-1} + X{+1}
+ + X{-#NAXIS1} + X{-#NAXIS1 - 1} + X{-#NAXIS1 + 1}
+ + X{#NAXIS1} + X{#NAXIS1 - 1} + X{#NAXIS1 + 1}) / 9.]
+-
+If the pixel offset
+extends beyond the first or last pixel in the image, the function will
+evaluate to undefined, or NULL.
+
+For complex or commonly used image filtering operations,
+one can write the expression into an external text file and
+then import it into the
+filter using the syntax '[pix @filename.txt]'. The mathematical
+expression can
+extend over multiple lines of text in 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.
+
+By default, the datatype of the resulting image will be the same as
+the original image, but one may force a different datatype by appended
+a code letter to the 'pix' keyword:
+-
+ pixb - 8-bit byte image with BITPIX = 8
+ pixi - 16-bit integer image with BITPIX = 16
+ pixj - 32-bit integer image with BITPIX = 32
+ pixr - 32-bit float image with BITPIX = -32
+ pixd - 64-bit float image with BITPIX = -64
+-
+Also by default, any other HDUs in the input file will be copied without
+change to the
+output virtual FITS file, but one may discard the other HDUs by adding
+the number '1' to the 'pix' keyword (and following any optional datatype code
+letter). For example:
+-
+ myfile.fits[3][pixr1 sqrt(X)]
+-
+will create a virtual FITS file containing only a primary array image
+with 32-bit floating point pixels that have a value equal to the square
+root of the pixels in the image that is in the 3rd extension
+of the 'myfile.fits' file.
+
+
+
+**I. 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 commas or 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). If the keyword name ends with a
+pound sign '\#', then cfitsio will substitute the number of the
+most recently referenced column for the \# character .
+This is especially useful when writing
+a column-related keyword like TUNITn for a newly created column,
+as shown in the following examples.
+
+\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. If no columns to be deleted are specified, then only the
+columns that are explicitly listed will be included in the filtered
+output table. To include all the columns, add the '*' wildcard
+specifier at the end of the list, as shown in the examples.
+
+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; #TUNIT#(column units) = 'counts';*]
+ - creates new PI column from PHA values
+ and also writes the TUNITn keyword
+ for the new column. The final '*'
+ expression means preserve all the
+ columns in the input table in the
+ virtual output table; without the '*'
+ the output table would only contain
+ the single 'PI' column.
+
+ [col rate = rate/exposure; TUNIT#(&) = 'counts/s';*]
+ - recomputes the rate column by dividing
+ it by the EXPOSURE keyword value. This
+ also modifies the value of the TUNITn
+ keyword for this column. The use of the
+ '&' character for the keyword comment
+ string means preserve the existing
+ comment string for that keyword. The
+ final '*' preserves all the columns
+ in the input table in the virtual
+ output table.
+-
+
+**J. 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 enclose 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(y,x)
+ "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" x % y "random # [0.0,1.0)" random()
+ "random Gaussian" randomn() "random Poisson" randomp(x)
+ "minimum" min(x,y) "maximum" max(x,y)
+ "cumulative sum" accum(x) "sequential difference" seqdiff(x)
+ "if-then-else" b?x:y
+ "angular separation" angsep(ra1,dec1,ra2,de2) (all in degrees)
+ "substring" strmid(s,p,n) "string search" strstr(s,r)
+-
+Three different random number functions are provided: random(), with no
+arguments, produces a uniform random deviate between 0 and 1; randomn(),
+also with no arguments, produces a normal (Gaussian) random deviate with
+zero mean and unit standard deviation; randomp(x) produces a Poisson random
+deviate whose expected number of counts is X. X may be any positive real
+number of expected counts, including fractional values, but the return value
+is an integer.
+
+When the random functions are used in a vector expression, by default
+the same random value will be used when evaluating each element of the vector.
+If different random numbers are desired, then the name of a vector
+column should be supplied as the single argument to the random
+function (e.g., "flux + 0.1 * random(flux)", where "flux' is the
+name of a vector column). This will create a vector of
+random numbers that will be used in sequence when evaluating each
+element of the vector expression.
+
+ 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.
+
+In the if-then-else expression, "b?x:y", b is an explicit boolean
+value or expression. There is no automatic type conversion from
+numeric to boolean values, so one needs to use "iVal!=0" instead of
+merely "iVal" as the boolean argument. x and y can be any scalar data
+type (including string).
+
+ The angsep function computes the angular separation in degrees
+ between 2 celestial positions, where the first 2 parameters
+ give the RA-like and Dec-like coordinates (in decimal degrees)
+ of the first position, and the 3rd and 4th parameters give the
+ coordinates of the second position.
+
+The substring function strmid(S,P,N) extracts a substring from S,
+starting at string position P, with a substring length N. The first
+character position in S is labeled as 1. If P is 0, or refers to a
+position beyond the end of S, then the extracted substring will be
+NULL. S, P, and N may be functions of other columns.
+
+The string search function strstr(S,R) searches for the first occurrence
+of the substring R in S. The result is an integer, indicating the
+character position of the first match (where 1 is the first character
+position of S). If no match is found, then strstr() returns a NULL
+value.
+
+ The following type casting operators are available, where the
+ enclosing 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)
+ "summation" 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 STDDEV() function computes the sample
+ standard deviation, i.e. it is proportional to 1/SQRT(N-1) instead
+ of 1/SQRT(N), where N is NVALID(V).
+
+ 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. There are 2 supported formats for the
+ region file: ASCII file or FITS binary table. The region file
+ 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. The FITS region file format is defined in a document
+ available from the FITS Support Office at
+ http://fits.gsfc.nasa.gov/ registry/ region.html
+
+ In its simplest 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 semi-major/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.
+-
+
+**K. 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.
+
+
+*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[JKLS](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[JKLS](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[JKLS](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[EDJKLS](unit,keyword, > keyval,comment,status)
+ FTGKN[EDJKLS](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[JKLS](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[JKLS](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[BIJKED](unit,group,fpixel,nelements,values, > status)
+ FTPPN[BIJKED](unit,group,fpixel,nelements,values,nullval > status)
+ FTPPRU(unit,group,fpixel,nelements, > status)
+ FTGPV[BIJKED](unit,group,fpixel,nelements,nullval, > values,anyf,status)
+ FTGPF[BIJKED](unit,group,fpixel,nelements, > values,flagvals,anyf,status)
+ FTPGP[BIJKED](unit,group,fparm,nparm,values, > status)
+ FTGGP[BIJKED](unit,group,fparm,nparm, > values,status)
+ FTP2D[BIJKED](unit,group,dim1,naxis1,naxis2,image, > status)
+ FTP3D[BIJKED](unit,group,dim1,dim2,naxis1,naxis2,naxis3,cube, > status)
+ FTG2D[BIJKED](unit,group,nullval,dim1,naxis1,naxis2, > image,anyf,status)
+ FTG3D[BIJKED](unit,group,nullval,dim1,dim2,naxis1,naxis2,naxis3, >
+ cube,anyf,status)
+ FTPSS[BIJKED](unit,group,naxis,naxes,fpixels,lpixels,array, > status)
+ FTGSV[BIJKED](unit,group,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+ FTGSF[BIJKED](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[SLBIJKEDCM](unit,colnum,frow,felem,nelements,values, > status)
+ FTPCN[BIJKED](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[SBIJKEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+ FTGCF[SLBIJKEDCM](unit,colnum,frow,felem,nelements, >
+ values,flagvals,anyf,status)
+ FTGSV[BIJKED](unit,colnum,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+ FTGSF[BIJKED](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
+blank - (integer*8) 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
+current - (integer) if not equal to 0, copy the current HDU
+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
+following - (integer) if not equal to 0, copy all following HDUs in the input file
+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)
+frowll - (integer*8) 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 = any HDU type or unknown type
+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
+naxesll - (integer*8 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
+nelementsll - (integer*8) 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
+nrowsll - (integer*8) 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
+offsetll - (integer*8) 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)
+previous - (integer) if not equal to 0, copy all previous HDUs in the input file
+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
+rowlenll - (integer*8) 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
+tnullll - (integer*8) 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
+206 illegal indexed keyword name (e.g. 'TFORM1000')
+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/vendor/cfitsio/fitsio.h b/vendor/cfitsio/fitsio.h
new file mode 100644
index 00000000..d6c83edb
--- /dev/null
+++ b/vendor/cfitsio/fitsio.h
@@ -0,0 +1,1934 @@
+/* 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
+
+#define CFITSIO_VERSION 3.31
+#define CFITSIO_MINOR 31
+#define CFITSIO_MAJOR 3
+
+#include <stdio.h>
+
+/* the following was provided by Michael Greason (GSFC) to fix a */
+/* C/Fortran compatibility problem on an SGI Altix system running */
+/* SGI ProPack 4 [this is a Novell SuSE Enterprise 9 derivative] */
+/* and using the Intel C++ and Fortran compilers (version 9.1) */
+#if defined(__INTEL_COMPILER) && defined(__itanium__)
+# define mipsFortran 1
+# define _MIPS_SZLONG 64
+#endif
+
+#if defined(linux) || defined(__APPLE__) || defined(__sgi)
+# 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 newer '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
+#elif defined(_MSC_VER) && (_MSC_VER>= 1400)
+# define OFF_T long long
+#else
+# define OFF_T long
+#endif
+
+/* this block determines if the the string function name is
+ strtol or strtoll, and whether to use %ld or %lld in printf statements */
+
+/*
+ The following 2 cases for that Athon64 were removed on 4 Jan 2006;
+ they appear to be incorrect now that LONGLONG is always typedef'ed
+ to 'long long'
+ || defined(__ia64__) \
+ || defined(__x86_64__) \
+*/
+#if (defined(__alpha) && ( defined(__unix__) || defined(__NetBSD__) )) \
+ || defined(__sparcv9) || (defined(__sparc__) && defined(__arch64__)) \
+ || defined(__powerpc64__) || defined(__64BIT__) \
+ || (defined(_MIPS_SZLONG) && _MIPS_SZLONG == 64) \
+ || defined( _MSC_VER)|| defined(__BORLANDC__)
+
+# define USE_LL_SUFFIX 0
+#else
+# define USE_LL_SUFFIX 1
+#endif
+
+/*
+ Determine what 8-byte integer data type is available.
+ 'long long' is now supported by most compilers, but
+ older MS Visual C++ compilers before V7.0 use '__int64' instead.
+*/
+
+#ifndef LONGLONG_TYPE /* this may have been previously defined */
+#if defined(_MSC_VER) /* Microsoft Visual C++ */
+
+#if (_MSC_VER < 1300) /* versions earlier than V7.0 do not have 'long long' */
+ typedef __int64 LONGLONG;
+#else /* newer versions do support 'long long' */
+ typedef long long LONGLONG;
+#endif
+
+#elif defined( __BORLANDC__) /* for the Borland 5.5 compiler, in particular */
+ typedef __int64 LONGLONG;
+#else
+ typedef long long LONGLONG;
+#endif
+
+#define LONGLONG_TYPE
+#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(__alpha) && ( defined(__unix__) || defined(__NetBSD__) )) \
+ || defined(__sparcv9) \
+ || defined(__ia64__) \
+ || defined(__x86_64__) \
+ || defined(_SX) \
+ || defined(__powerpc64__) || defined(__64BIT__) \
+ || (defined(_MIPS_SZLONG) && _MIPS_SZLONG == 64)
+/* 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 9223372036854775807LL /* max 64-bit integer */
+#define LONGLONG_MIN (-LONGLONG_MAX -1LL) /* min 64-bit integer */
+
+#endif
+#endif /* end of ndef LONGLONG_MAX section */
+
+
+/* ================================================================= */
+
+
+/* The following exclusion if __CINT__ is defined is needed for ROOT */
+#ifndef __CINT__
+#include "longnam.h"
+#endif
+
+#define NIOBUF 40 /* number of IO buffers to create (default = 40) */
+ /* !! Significantly increasing NIOBUF may degrade performance !! */
+
+#define IOBUFLEN 2880 /* size in bytes of each IO buffer (DONT CHANGE!) */
+
+/* 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
+
+/* compression algorithm type codes */
+#define SUBTRACTIVE_DITHER_1 1
+#define MAX_COMPRESS_DIM 6
+#define RICE_1 11
+#define GZIP_1 21
+#define GZIP_2 22
+#define PLIO_1 31
+#define HCOMPRESS_1 41
+#define BZIP2_1 51 /* not publicly supported; only for test purposes */
+#define NOCOMPRESS 0
+
+#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; */
+ LONGLONG tbcol; /* offset in row to first byte of each column */
+ int tdatatype; /* datatype code of each column */
+ LONGLONG trepeat; /* repeat count of column; number of elements */
+ double tscale; /* FITS TSCALn linear scaling factor */
+ double tzero; /* FITS TZEROn linear scaling zero point */
+ LONGLONG 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 */
+ int only_one; /* flag meaning only copy the specified extension */
+ LONGLONG filesize; /* current size of the physical disk file in bytes */
+ LONGLONG logfilesize; /* logical size of file, including unflushed buffers */
+ int lasthdu; /* is this the last HDU in the file? 0 = no, else yes */
+ LONGLONG bytepos; /* current logical I/O pointer position in file */
+ LONGLONG 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 */
+ LONGLONG *headstart; /* byte offset in file to start of each HDU */
+ LONGLONG headend; /* byte offest in file to end of the current HDU header */
+ LONGLONG ENDpos; /* byte offest to where the END keyword was last written */
+ LONGLONG nextkey; /* byte offset in file to beginning of next keyword */
+ LONGLONG datastart; /* byte offset in file to start of the current data unit */
+ int imgdim; /* dimension of image; cached for fast access */
+ LONGLONG imgnaxis[99]; /* length of each axis; cached for fast access */
+ int tfield; /* number of fields in the table (primary array has 2 */
+ LONGLONG origrows; /* original number of rows (value of NAXIS2 keyword) */
+ LONGLONG numrows; /* number of rows in the table (dynamically updated) */
+ LONGLONG rowlength; /* length of a table row or image size (bytes) */
+ tcolumn *tableptr; /* pointer to the table structure */
+ LONGLONG heapstart; /* heap start byte relative to start of data unit */
+ LONGLONG 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 */
+
+ float request_hcomp_scale; /* requested HCOMPRESS scale factor */
+ int request_hcomp_smooth; /* requested HCOMPRESS smooth parameter */
+ int request_quantize_dither ; /* requested dithering mode when quantizing */
+ /* floating point images to integer */
+ int request_dither_offset; /* starting offset into the array of random dithering */
+ int request_lossy_int_compress; /* lossy compress integer image as if float image? */
+
+ int compressimg; /* 1 if HDU contains a compressed image, else 0 */
+ int quantize_dither; /* floating point pixel quantization algorithm */
+ 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 byte length of tile compressed arrays */
+
+ int cn_compressed; /* column number for COMPRESSED_DATA column */
+ int cn_uncompressed; /* column number for UNCOMPRESSED_DATA column */
+ int cn_gzip_data; /* column number for GZIP2 lossless compressed data */
+ 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 (may be reset) */
+ double cn_actual_bzero; /* actual value of the BZERO keyword */
+ int zblank; /* value for null pixels, if not a column */
+
+ int rice_blocksize; /* first compression parameter: pixels/block */
+ int rice_bytepix; /* 2nd compression parameter: bytes/pixel */
+ float quantize_level; /* floating point quantization level */
+ int dither_offset; /* starting offset into the array of random dithering */
+ float hcomp_scale; /* 1st hcompress compression parameter */
+ int hcomp_smooth; /* 2nd hcompress compression parameter */
+
+ int tilerow; /* row number of the uncompressed tiledata */
+ long tiledatasize; /* length of the tile data in bytes */
+ int tiletype; /* datatype of the tile (TINT, TSHORT, etc) */
+ void *tiledata; /* uncompressed tile of data, for row tilerow */
+ char *tilenullarray; /* optional array of null value flags */
+ int tileanynull; /* anynulls in this tile? */
+
+ char *iobuffer; /* pointer to FITS file I/O buffers */
+ long bufrecnum[NIOBUF]; /* file record number of each of the buffers */
+ int dirty[NIOBUF]; /* has the corresponding buffer been modified? */
+ int ageindex[NIOBUF]; /* relative age of each buffer */
+} 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 */
+
+/*=============================================================================
+*
+* The following wtbarr typedef is used in the fits_read_wcstab() routine,
+* which is intended for use with the WCSLIB library written by Mark
+* Calabretta, http://www.atnf.csiro.au/~mcalabre/index.html
+*
+* In order to maintain WCSLIB and CFITSIO as independent libraries it
+* was not permissible for any CFITSIO library code to include WCSLIB
+* header files, or vice versa. However, the CFITSIO function
+* fits_read_wcstab() accepts an array of structs defined by wcs.h within
+* WCSLIB. The problem then was to define this struct within fitsio.h
+* without including wcs.h, especially noting that wcs.h will often (but
+* not always) be included together with fitsio.h in an applications
+* program that uses fits_read_wcstab().
+*
+* Of the various possibilities, the solution adopted was for WCSLIB to
+* define "struct wtbarr" while fitsio.h defines "typedef wtbarr", a
+* untagged struct with identical members. This allows both wcs.h and
+* fitsio.h to define a wtbarr data type without conflict by virtue of
+* the fact that structure tags and typedef names share different
+* namespaces in C. Therefore, declarations within WCSLIB look like
+*
+* struct wtbarr *w;
+*
+* while within CFITSIO they are simply
+*
+* wtbarr *w;
+*
+* but as suggested by the commonality of the names, these are really the
+* same aggregate data type. However, in passing a (struct wtbarr *) to
+* fits_read_wcstab() a cast to (wtbarr *) is formally required.
+*===========================================================================*/
+
+#ifndef WCSLIB_GETWCSTAB
+#define WCSLIB_GETWCSTAB
+
+typedef struct {
+ int i; /* Image axis number. */
+ int m; /* Array axis number for index vectors. */
+ int kind; /* Array type, 'c' (coord) or 'i' (index). */
+ char extnam[72]; /* EXTNAME of binary table extension. */
+ int extver; /* EXTVER of binary table extension. */
+ int extlev; /* EXTLEV of binary table extension. */
+ char ttype[72]; /* TTYPEn of column containing the array. */
+ long row; /* Table row number. */
+ int ndim; /* Expected array dimensionality. */
+ int *dimlen; /* Where to write the array axis lengths. */
+ double **arrayp; /* Where to write the address of the array */
+ /* allocated to store the array. */
+} wtbarr;
+
+int fits_read_wcstab(fitsfile *fptr, int nwtb, wtbarr *wtb, int *status);
+
+#endif /* WCSLIB_GETWCSTAB */
+
+/* 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_INDEX_KEY 206 /* illegal indexed keyword name */
+#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 ffifile (char *url, char *urltype, char *infile,
+ char *outfile, char *extspec, char *rowfilter,
+ char *binspec, char *colspec, char *pixfilter, int *status);
+int ffifile2 (char *url, char *urltype, char *infile,
+ char *outfile, char *extspec, char *rowfilter,
+ char *binspec, char *colspec, char *pixfilter, char *compspec, 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 fits_copy_cell2image(fitsfile *fptr, fitsfile *newptr, char *colname,
+ long rownum, int *status);
+int fits_copy_image2cell(fitsfile *fptr, fitsfile *newptr, char *colname,
+ long rownum, int copykeyflag, int *status);
+int fits_copy_pixlist2image(fitsfile *infptr, fitsfile *outfptr, int firstkey, /* I - first HDU record number to start with */
+ int naxis, int *colnum, int *status);
+int ffimport_file( char *filename, char **contents, int *status );
+int ffrwrg( char *rowlist, LONGLONG maxrows, int maxranges, int *numranges,
+ long *minrow, long *maxrow, int *status);
+int ffrwrgll( char *rowlist, LONGLONG maxrows, int maxranges, int *numranges,
+ LONGLONG *minrow, LONGLONG *maxrow, int *status);
+/*---------------- FITS file I/O routines -------------*/
+int fits_init_cfitsio(void);
+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 ffopentest(double version, 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);
+int fits_delete_iraf_file(char *filename, 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(const char *keyword, int *status);
+int fftrec(char *card, int *status);
+int ffnchk(fitsfile *fptr, int *status);
+int ffkeyn(const 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 ffinttyp(char *cval, int *datatype, int *negative, 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 fits_translate_keyword(char *inrec, char *outrec, char *patterns[][2],
+ int npat, int n_value, int n_offset, int n_range, int *pat_num,
+ int *i, int *j, int *m, int *n, int *status);
+int fits_translate_keywords(fitsfile *infptr, fitsfile *outfptr,
+ int firstkey, char *patterns[][2],
+ int npat, int n_value, int n_offset, int n_range, 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 ffbnfmll(char *tform, int *datacode, LONGLONG *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);
+/* ffmbyt should not normally be used in application programs, but it is
+ defined here as a publicly available routine because there are a few
+ rare cases where it is needed
+*/
+int ffmbyt(fitsfile *fptr, LONGLONG bytpos, int ignore_err, int *status);
+/*----------------- write single keywords --------------*/
+int ffpky(fitsfile *fptr, int datatype, const char *keyname, void *value,
+ const 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, const char *keyname, char *unit, int *status);
+int ffphis(fitsfile *fptr, const char *history, int *status);
+int ffpdat(fitsfile *fptr, int *status);
+int ffverifydate(int year, int month, int day, 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, const char *keyname, const char *comm, int *status);
+int ffpkys(fitsfile *fptr, const char *keyname, char *value, const char *comm,int *status);
+int ffpkls(fitsfile *fptr, const char *keyname, const char *value, const char *comm,int *status);
+int ffplsw(fitsfile *fptr, int *status);
+int ffpkyl(fitsfile *fptr, const char *keyname, int value, const char *comm, int *status);
+int ffpkyj(fitsfile *fptr, const char *keyname, LONGLONG value, const char *comm, int *status);
+int ffpkyf(fitsfile *fptr, const char *keyname, float value, int decim, const char *comm,
+ int *status);
+int ffpkye(fitsfile *fptr, const char *keyname, float value, int decim, const char *comm,
+ int *status);
+int ffpkyg(fitsfile *fptr, const char *keyname, double value, int decim, const char *comm,
+ int *status);
+int ffpkyd(fitsfile *fptr, const char *keyname, double value, int decim, const char *comm,
+ int *status);
+int ffpkyc(fitsfile *fptr, const char *keyname, float *value, int decim, const char *comm,
+ int *status);
+int ffpkym(fitsfile *fptr, const char *keyname, double *value, int decim, const char *comm,
+ int *status);
+int ffpkfc(fitsfile *fptr, const char *keyname, float *value, int decim, const char *comm,
+ int *status);
+int ffpkfm(fitsfile *fptr, const char *keyname, double *value, int decim, const char *comm,
+ int *status);
+int ffpkyt(fitsfile *fptr, const char *keyname, long intval, double frac, const char *comm,
+ int *status);
+int ffptdm( fitsfile *fptr, int colnum, int naxis, long naxes[], int *status);
+int ffptdmll( fitsfile *fptr, int colnum, int naxis, LONGLONG naxes[], int *status);
+
+/*----------------- write array of keywords --------------*/
+int ffpkns(fitsfile *fptr, const char *keyroot, int nstart, int nkey, char *value[],
+ char *comm[], int *status);
+int ffpknl(fitsfile *fptr, const char *keyroot, int nstart, int nkey, int *value,
+ char *comm[], int *status);
+int ffpknj(fitsfile *fptr, const char *keyroot, int nstart, int nkey, long *value,
+ char *comm[], int *status);
+int ffpknjj(fitsfile *fptr, const char *keyroot, int nstart, int nkey, LONGLONG *value,
+ char *comm[], int *status);
+int ffpknf(fitsfile *fptr, const char *keyroot, int nstart, int nkey, float *value,
+ int decim, char *comm[], int *status);
+int ffpkne(fitsfile *fptr, const char *keyroot, int nstart, int nkey, float *value,
+ int decim, char *comm[], int *status);
+int ffpkng(fitsfile *fptr, const char *keyroot, int nstart, int nkey, double *value,
+ int decim, char *comm[], int *status);
+int ffpknd(fitsfile *fptr, const 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 ffphpsll( fitsfile *fptr, int bitpix, int naxis, LONGLONG naxes[], int *status);
+int ffphpr( fitsfile *fptr, int simple, int bitpix, int naxis, long naxes[],
+ LONGLONG pcount, LONGLONG gcount, int extend, int *status);
+int ffphprll( fitsfile *fptr, int simple, int bitpix, int naxis, LONGLONG naxes[],
+ LONGLONG pcount, LONGLONG gcount, int extend, int *status);
+int ffphtb(fitsfile *fptr, LONGLONG naxis1, LONGLONG naxis2, int tfields, char **ttype,
+ long *tbcol, char **tform, char **tunit, const char *extname, int *status);
+int ffphbn(fitsfile *fptr, LONGLONG naxis2, int tfields, char **ttype,
+ char **tform, char **tunit, const char *extname, LONGLONG pcount, int *status);
+int ffphext( fitsfile *fptr, const char *xtension, int bitpix, int naxis, long naxes[],
+ LONGLONG pcount, LONGLONG gcount, 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, const char *keyname, char *card, int *status);
+int ffgstr(fitsfile *fptr, const char *string, char *card, int *status);
+int ffgunt(fitsfile *fptr, const char *keyname, char *unit, int *status);
+int ffgkyn(fitsfile *fptr, int nkey, char *keyname, char *keyval, char *comm,
+ int *status);
+int ffgkey(fitsfile *fptr, const char *keyname, char *keyval, char *comm,
+ int *status);
+
+int ffgky( fitsfile *fptr, int datatype, const char *keyname, void *value,
+ char *comm, int *status);
+int ffgkys(fitsfile *fptr, const char *keyname, char *value, char *comm, int *status);
+int ffgkls(fitsfile *fptr, const char *keyname, char **value, char *comm, int *status);
+int fffree(void *value, int *status);
+int fffkls(char *value, int *status);
+int ffgkyl(fitsfile *fptr, const char *keyname, int *value, char *comm, int *status);
+int ffgkyj(fitsfile *fptr, const char *keyname, long *value, char *comm, int *status);
+int ffgkyjj(fitsfile *fptr, const char *keyname, LONGLONG *value, char *comm, int *status);
+int ffgkye(fitsfile *fptr, const char *keyname, float *value, char *comm,int *status);
+int ffgkyd(fitsfile *fptr, const char *keyname, double *value,char *comm,int *status);
+int ffgkyc(fitsfile *fptr, const char *keyname, float *value, char *comm,int *status);
+int ffgkym(fitsfile *fptr, const char *keyname, double *value,char *comm,int *status);
+int ffgkyt(fitsfile *fptr, const 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 ffgtdmll(fitsfile *fptr, int colnum, int maxdim, int *naxis, LONGLONG naxes[],
+ int *status);
+int ffdtdm(fitsfile *fptr, char *tdimstr, int colnum, int maxdim,
+ int *naxis, long naxes[], int *status);
+int ffdtdmll(fitsfile *fptr, char *tdimstr, int colnum, int maxdim,
+ int *naxis, LONGLONG naxes[], int *status);
+
+/*------------------ read array of keywords -----------------*/
+int ffgkns(fitsfile *fptr, const char *keyname, int nstart, int nmax, char *value[],
+ int *nfound, int *status);
+int ffgknl(fitsfile *fptr, const char *keyname, int nstart, int nmax, int *value,
+ int *nfound, int *status);
+int ffgknj(fitsfile *fptr, const char *keyname, int nstart, int nmax, long *value,
+ int *nfound, int *status);
+int ffgknjj(fitsfile *fptr, const char *keyname, int nstart, int nmax, LONGLONG *value,
+ int *nfound, int *status);
+int ffgkne(fitsfile *fptr, const char *keyname, int nstart, int nmax, float *value,
+ int *nfound, int *status);
+int ffgknd(fitsfile *fptr, const 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);
+int ffcnvthdr2str( 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 ffghprll(fitsfile *fptr, int maxdim, int *simple, int *bitpix, int *naxis,
+ LONGLONG 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 ffghtbll(fitsfile *fptr,int maxfield, LONGLONG *naxis1, LONGLONG *naxis2,
+ int *tfields, char **ttype, LONGLONG *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);
+
+int ffghbnll(fitsfile *fptr, int maxfield, LONGLONG *naxis2, int *tfields,
+ char **ttype, char **tform, char **tunit, char *extname,
+ LONGLONG *pcount, int *status);
+
+/*--------------------- update keywords ---------------*/
+int ffuky(fitsfile *fptr, int datatype, const char *keyname, void *value,
+ char *comm, int *status);
+int ffucrd(fitsfile *fptr, const char *keyname, char *card, int *status);
+int ffukyu(fitsfile *fptr, const char *keyname, char *comm, int *status);
+int ffukys(fitsfile *fptr, const char *keyname, char *value, char *comm, int *status);
+int ffukls(fitsfile *fptr, const char *keyname, char *value, char *comm, int *status);
+int ffukyl(fitsfile *fptr, const char *keyname, int value, char *comm, int *status);
+int ffukyj(fitsfile *fptr, const char *keyname, LONGLONG value, char *comm, int *status);
+int ffukyf(fitsfile *fptr, const char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffukye(fitsfile *fptr, const char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffukyg(fitsfile *fptr, const char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffukyd(fitsfile *fptr, const char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffukyc(fitsfile *fptr, const char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffukym(fitsfile *fptr, const char *keyname, double *value, int decim, char *comm,
+ int *status);
+int ffukfc(fitsfile *fptr, const char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffukfm(fitsfile *fptr, const 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, const char *keyname, char *card, int *status);
+int ffmnam(fitsfile *fptr, const char *oldname, const char *newname, int *status);
+int ffmcom(fitsfile *fptr, const char *keyname, char *comm, int *status);
+int ffmkyu(fitsfile *fptr, const char *keyname, char *comm, int *status);
+int ffmkys(fitsfile *fptr, const char *keyname, char *value, char *comm,int *status);
+int ffmkls(fitsfile *fptr, const char *keyname, char *value, char *comm,int *status);
+int ffmkyl(fitsfile *fptr, const char *keyname, int value, char *comm, int *status);
+int ffmkyj(fitsfile *fptr, const char *keyname, LONGLONG value, char *comm, int *status);
+int ffmkyf(fitsfile *fptr, const char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffmkye(fitsfile *fptr, const char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffmkyg(fitsfile *fptr, const char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffmkyd(fitsfile *fptr, const char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffmkyc(fitsfile *fptr, const char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffmkym(fitsfile *fptr, const char *keyname, double *value, int decim, char *comm,
+ int *status);
+int ffmkfc(fitsfile *fptr, const char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffmkfm(fitsfile *fptr, const 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, const char *keyname, char *comm, int *status);
+int ffikys(fitsfile *fptr, const char *keyname, char *value, char *comm,int *status);
+int ffikls(fitsfile *fptr, const char *keyname, char *value, char *comm,int *status);
+int ffikyl(fitsfile *fptr, const char *keyname, int value, char *comm, int *status);
+int ffikyj(fitsfile *fptr, const char *keyname, LONGLONG value, char *comm, int *status);
+int ffikyf(fitsfile *fptr, const char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffikye(fitsfile *fptr, const char *keyname, float value, int decim, char *comm,
+ int *status);
+int ffikyg(fitsfile *fptr, const char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffikyd(fitsfile *fptr, const char *keyname, double value, int decim, char *comm,
+ int *status);
+int ffikyc(fitsfile *fptr, const char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffikym(fitsfile *fptr, const char *keyname, double *value, int decim, char *comm,
+ int *status);
+int ffikfc(fitsfile *fptr, const char *keyname, float *value, int decim, char *comm,
+ int *status);
+int ffikfm(fitsfile *fptr, const char *keyname, double *value, int decim, char *comm,
+ int *status);
+
+/*--------------------- delete keywords ---------------*/
+int ffdkey(fitsfile *fptr, const char *keyname, int *status);
+int ffdstr(fitsfile *fptr, const char *string, 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 ffghadll(fitsfile *fptr, LONGLONG *headstart, LONGLONG *datastart,
+ LONGLONG *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 ffgiprll(fitsfile *fptr, int maxaxis, int *imgtype, int *naxis,
+ LONGLONG *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);
+int ffgiszll(fitsfile *fptr, int nlen, LONGLONG *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 ffcrimll(fitsfile *fptr, int bitpix, int naxis, LONGLONG *naxes, int *status);
+int ffcrtb(fitsfile *fptr, int tbltype, LONGLONG naxis2, int tfields, char **ttype,
+ char **tform, char **tunit, const char *extname, int *status);
+int ffiimg(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status);
+int ffiimgll(fitsfile *fptr, int bitpix, int naxis, LONGLONG *naxes, int *status);
+int ffitab(fitsfile *fptr, LONGLONG naxis1, LONGLONG naxis2, int tfields, char **ttype,
+ long *tbcol, char **tform, char **tunit, const char *extname, int *status);
+int ffibin(fitsfile *fptr, LONGLONG naxis2, int tfields, char **ttype, char **tform,
+ char **tunit, const char *extname, LONGLONG pcount, int *status);
+int ffrsim(fitsfile *fptr, int bitpix, int naxis, long *naxes, int *status);
+int ffrsimll(fitsfile *fptr, int bitpix, int naxis, LONGLONG *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 ffwrhdu(fitsfile *fptr, FILE *outstream, 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, LONGLONG nulvalue, int *status);
+int fftscl(fitsfile *fptr, int colnum, double scale, double zero, int *status);
+int fftnul(fitsfile *fptr, int colnum, LONGLONG 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 ffgtclll(fitsfile *fptr, int colnum, int *typecode, LONGLONG *repeat,
+ LONGLONG *width, int *status);
+int ffeqty(fitsfile *fptr, int colnum, int *typecode, long *repeat,
+ long *width, int *status);
+int ffeqtyll(fitsfile *fptr, int colnum, int *typecode, LONGLONG *repeat,
+ LONGLONG *width, int *status);
+int ffgncl(fitsfile *fptr, int *ncols, int *status);
+int ffgnrw(fitsfile *fptr, long *nrows, int *status);
+int ffgnrwll(fitsfile *fptr, LONGLONG *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 ffgbclll(fitsfile *fptr, int colnum, char *ttype, char *tunit,
+ char *dtype, LONGLONG *repeat, double *tscal, double *tzero,
+ LONGLONG *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, LONGLONG nelem,
+ void *nulval, void *array, int *anynul, int *status);
+int ffgpxvll(fitsfile *fptr, int datatype, LONGLONG *firstpix, LONGLONG nelem,
+ void *nulval, void *array, int *anynul, int *status);
+int ffgpxf(fitsfile *fptr, int datatype, long *firstpix, LONGLONG nelem,
+ void *array, char *nullarray, int *anynul, int *status);
+int ffgpxfll(fitsfile *fptr, int datatype, LONGLONG *firstpix, LONGLONG 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, LONGLONG firstelem, LONGLONG nelem,
+ void *nulval, void *array, int *anynul, int *status);
+int ffgpf(fitsfile *fptr, int datatype, LONGLONG firstelem, LONGLONG nelem,
+ void *array, char *nullarray, int *anynul, int *status);
+int ffgpvb(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem, unsigned
+ char nulval, unsigned char *array, int *anynul, int *status);
+int ffgpvsb(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem, signed
+ char nulval, signed char *array, int *anynul, int *status);
+int ffgpvui(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned short nulval, unsigned short *array, int *anynul,
+ int *status);
+int ffgpvi(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ short nulval, short *array, int *anynul, int *status);
+int ffgpvuj(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned long nulval, unsigned long *array, int *anynul,
+ int *status);
+int ffgpvj(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ long nulval, long *array, int *anynul, int *status);
+int ffgpvjj(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ LONGLONG nulval, LONGLONG *array, int *anynul, int *status);
+int ffgpvuk(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned int nulval, unsigned int *array, int *anynul, int *status);
+int ffgpvk(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ int nulval, int *array, int *anynul, int *status);
+int ffgpve(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ float nulval, float *array, int *anynul, int *status);
+int ffgpvd(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ double nulval, double *array, int *anynul, int *status);
+
+int ffgpfb(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned char *array, char *nularray, int *anynul, int *status);
+int ffgpfsb(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ signed char *array, char *nularray, int *anynul, int *status);
+int ffgpfui(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned short *array, char *nularray, int *anynul, int *status);
+int ffgpfi(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ short *array, char *nularray, int *anynul, int *status);
+int ffgpfuj(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned long *array, char *nularray, int *anynul, int *status);
+int ffgpfj(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ long *array, char *nularray, int *anynul, int *status);
+int ffgpfjj(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ LONGLONG *array, char *nularray, int *anynul, int *status);
+int ffgpfuk(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned int *array, char *nularray, int *anynul, int *status);
+int ffgpfk(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ int *array, char *nularray, int *anynul, int *status);
+int ffgpfe(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ float *array, char *nularray, int *anynul, int *status);
+int ffgpfd(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ double *array, char *nularray, int *anynul, int *status);
+
+int ffg2db(fitsfile *fptr, long group, unsigned char nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, unsigned char *array,
+ int *anynul, int *status);
+int ffg2dsb(fitsfile *fptr, long group, signed char nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, signed char *array,
+ int *anynul, int *status);
+int ffg2dui(fitsfile *fptr, long group, unsigned short nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, unsigned short *array,
+ int *anynul, int *status);
+int ffg2di(fitsfile *fptr, long group, short nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, short *array,
+ int *anynul, int *status);
+int ffg2duj(fitsfile *fptr, long group, unsigned long nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, unsigned long *array,
+ int *anynul, int *status);
+int ffg2dj(fitsfile *fptr, long group, long nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, long *array,
+ int *anynul, int *status);
+int ffg2djj(fitsfile *fptr, long group, LONGLONG nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, LONGLONG *array,
+ int *anynul, int *status);
+int ffg2duk(fitsfile *fptr, long group, unsigned int nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, unsigned int *array,
+ int *anynul, int *status);
+int ffg2dk(fitsfile *fptr, long group, int nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, int *array,
+ int *anynul, int *status);
+int ffg2de(fitsfile *fptr, long group, float nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, float *array,
+ int *anynul, int *status);
+int ffg2dd(fitsfile *fptr, long group, double nulval, LONGLONG ncols,
+ LONGLONG naxis1, LONGLONG naxis2, double *array,
+ int *anynul, int *status);
+
+int ffg3db(fitsfile *fptr, long group, unsigned char nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ unsigned char *array, int *anynul, int *status);
+int ffg3dsb(fitsfile *fptr, long group, signed char nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ signed char *array, int *anynul, int *status);
+int ffg3dui(fitsfile *fptr, long group, unsigned short nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ unsigned short *array, int *anynul, int *status);
+int ffg3di(fitsfile *fptr, long group, short nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ short *array, int *anynul, int *status);
+int ffg3duj(fitsfile *fptr, long group, unsigned long nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ unsigned long *array, int *anynul, int *status);
+int ffg3dj(fitsfile *fptr, long group, long nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ long *array, int *anynul, int *status);
+int ffg3djj(fitsfile *fptr, long group, LONGLONG nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ LONGLONG *array, int *anynul, int *status);
+int ffg3duk(fitsfile *fptr, long group, unsigned int nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ unsigned int *array, int *anynul, int *status);
+int ffg3dk(fitsfile *fptr, long group, int nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ int *array, int *anynul, int *status);
+int ffg3de(fitsfile *fptr, long group, float nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG naxis3,
+ float *array, int *anynul, int *status);
+int ffg3dd(fitsfile *fptr, long group, double nulval, LONGLONG ncols,
+ LONGLONG nrows, LONGLONG naxis1, LONGLONG naxis2, LONGLONG 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, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG nelem, void *nulval, void *array, int *anynul,
+ int *status);
+int ffgcf( fitsfile *fptr, int datatype, int colnum, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG nelem, void *array, char *nullarray,
+ int *anynul, int *status);
+int ffgcvs(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char *nulval, char **array, int *anynul, int *status);
+int ffgcl (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char *array, int *status);
+int ffgcvl (fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char nulval, char *array, int *anynul, int *status);
+int ffgcvb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned char nulval, unsigned char *array,
+ int *anynul, int *status);
+int ffgcvsb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, signed char nulval, signed char *array,
+ int *anynul, int *status);
+int ffgcvui(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned short nulval, unsigned short *array,
+ int *anynul, int *status);
+int ffgcvi(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, short nulval, short *array, int *anynul, int *status);
+int ffgcvuj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned long nulval, unsigned long *array, int *anynul,
+ int *status);
+int ffgcvj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long nulval, long *array, int *anynul, int *status);
+int ffgcvjj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, LONGLONG nulval, LONGLONG *array, int *anynul,
+ int *status);
+int ffgcvuk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned int nulval, unsigned int *array, int *anynul,
+ int *status);
+int ffgcvk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int nulval, int *array, int *anynul, int *status);
+int ffgcve(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, float nulval, float *array, int *anynul, int *status);
+int ffgcvd(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, double nulval, double *array, int *anynul, int *status);
+int ffgcvc(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, float nulval, float *array, int *anynul, int *status);
+int ffgcvm(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, double nulval, double *array, int *anynul, int *status);
+
+int ffgcx(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstbit,
+ LONGLONG nbits, char *larray, int *status);
+int ffgcxui(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG nrows,
+ long firstbit, int nbits, unsigned short *array, int *status);
+int ffgcxuk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG nrows,
+ long firstbit, int nbits, unsigned int *array, int *status);
+
+int ffgcfs(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char **array, char *nularray, int *anynul, int *status);
+int ffgcfl(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char *array, char *nularray, int *anynul, int *status);
+int ffgcfb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned char *array, char *nularray, int *anynul, int *status);
+int ffgcfsb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, signed char *array, char *nularray, int *anynul, int *status);
+int ffgcfui(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned short *array, char *nularray, int *anynul,
+ int *status);
+int ffgcfi(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, short *array, char *nularray, int *anynul, int *status);
+int ffgcfuj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned long *array, char *nularray, int *anynul,
+ int *status);
+int ffgcfj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long *array, char *nularray, int *anynul, int *status);
+int ffgcfjj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, LONGLONG *array, char *nularray, int *anynul, int *status);
+int ffgcfuk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned int *array, char *nularray, int *anynul,
+ int *status);
+int ffgcfk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int *array, char *nularray, int *anynul, int *status);
+int ffgcfe(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, float *array, char *nularray, int *anynul, int *status);
+int ffgcfd(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, double *array, char *nularray, int *anynul, int *status);
+int ffgcfc(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, float *array, char *nularray, int *anynul, int *status);
+int ffgcfm(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, double *array, char *nularray, int *anynul, int *status);
+
+int ffgdes(fitsfile *fptr, int colnum, LONGLONG rownum, long *length,
+ long *heapaddr, int *status);
+int ffgdesll(fitsfile *fptr, int colnum, LONGLONG rownum, LONGLONG *length,
+ LONGLONG *heapaddr, int *status);
+int ffgdess(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG nrows, long *length,
+ long *heapaddr, int *status);
+int ffgdessll(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG nrows, LONGLONG *length,
+ LONGLONG *heapaddr, int *status);
+int ffpdes(fitsfile *fptr, int colnum, LONGLONG rownum, LONGLONG length,
+ LONGLONG heapaddr, int *status);
+int fftheap(fitsfile *fptr, LONGLONG *heapsize, LONGLONG *unused, LONGLONG *overlap,
+ int *valid, int *status);
+int ffcmph(fitsfile *fptr, int *status);
+
+int ffgtbb(fitsfile *fptr, LONGLONG firstrow, LONGLONG firstchar, LONGLONG nchars,
+ unsigned char *values, int *status);
+
+int ffgextn(fitsfile *fptr, LONGLONG offset, LONGLONG nelem, void *array, int *status);
+int ffpextn(fitsfile *fptr, LONGLONG offset, LONGLONG nelem, void *array, int *status);
+
+/*------------ write primary array or image elements -------------*/
+int ffppx(fitsfile *fptr, int datatype, long *firstpix, LONGLONG nelem,
+ void *array, int *status);
+int ffppxll(fitsfile *fptr, int datatype, LONGLONG *firstpix, LONGLONG nelem,
+ void *array, int *status);
+int ffppxn(fitsfile *fptr, int datatype, long *firstpix, LONGLONG nelem,
+ void *array, void *nulval, int *status);
+int ffppxnll(fitsfile *fptr, int datatype, LONGLONG *firstpix, LONGLONG nelem,
+ void *array, void *nulval, int *status);
+int ffppr(fitsfile *fptr, int datatype, LONGLONG firstelem,
+ LONGLONG nelem, void *array, int *status);
+int ffpprb(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, unsigned char *array, int *status);
+int ffpprsb(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, signed char *array, int *status);
+int ffpprui(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, unsigned short *array, int *status);
+int ffppri(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, short *array, int *status);
+int ffppruj(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, unsigned long *array, int *status);
+int ffpprj(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, long *array, int *status);
+int ffppruk(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, unsigned int *array, int *status);
+int ffpprk(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, int *array, int *status);
+int ffppre(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, float *array, int *status);
+int ffpprd(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, double *array, int *status);
+int ffpprjj(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, LONGLONG *array, int *status);
+
+int ffppru(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ int *status);
+int ffpprn(fitsfile *fptr, LONGLONG firstelem, LONGLONG nelem, int *status);
+
+int ffppn(fitsfile *fptr, int datatype, LONGLONG firstelem, LONGLONG nelem,
+ void *array, void *nulval, int *status);
+int ffppnb(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned char *array, unsigned char nulval, int *status);
+int ffppnsb(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ signed char *array, signed char nulval, int *status);
+int ffppnui(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, unsigned short *array, unsigned short nulval,
+ int *status);
+int ffppni(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, short *array, short nulval, int *status);
+int ffppnj(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, long *array, long nulval, int *status);
+int ffppnuj(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned long *array, unsigned long nulval, int *status);
+int ffppnuk(fitsfile *fptr, long group, LONGLONG firstelem, LONGLONG nelem,
+ unsigned int *array, unsigned int nulval, int *status);
+int ffppnk(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, int *array, int nulval, int *status);
+int ffppne(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, float *array, float nulval, int *status);
+int ffppnd(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, double *array, double nulval, int *status);
+int ffppnjj(fitsfile *fptr, long group, LONGLONG firstelem,
+ LONGLONG nelem, LONGLONG *array, LONGLONG nulval, int *status);
+
+int ffp2db(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, unsigned char *array, int *status);
+int ffp2dsb(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, signed char *array, int *status);
+int ffp2dui(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, unsigned short *array, int *status);
+int ffp2di(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, short *array, int *status);
+int ffp2duj(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, unsigned long *array, int *status);
+int ffp2dj(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, long *array, int *status);
+int ffp2duk(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, unsigned int *array, int *status);
+int ffp2dk(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, int *array, int *status);
+int ffp2de(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, float *array, int *status);
+int ffp2dd(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, double *array, int *status);
+int ffp2djj(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG *array, int *status);
+
+int ffp3db(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, unsigned char *array, int *status);
+int ffp3dsb(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, signed char *array, int *status);
+int ffp3dui(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, unsigned short *array, int *status);
+int ffp3di(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, short *array, int *status);
+int ffp3duj(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, unsigned long *array, int *status);
+int ffp3dj(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, long *array, int *status);
+int ffp3duk(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, unsigned int *array, int *status);
+int ffp3dk(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, int *array, int *status);
+int ffp3de(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, float *array, int *status);
+int ffp3dd(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG naxis3, double *array, int *status);
+int ffp3djj(fitsfile *fptr, long group, LONGLONG ncols, LONGLONG nrows, LONGLONG naxis1,
+ LONGLONG naxis2, LONGLONG 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, LONGLONG firstrow,
+ LONGLONG firstelem, LONGLONG nelem, void *array, int *status);
+int ffpcls(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char **array, int *status);
+int ffpcll(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char *array, int *status);
+int ffpclb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned char *array, int *status);
+int ffpclsb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, signed char *array, int *status);
+int ffpclui(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned short *array, int *status);
+int ffpcli(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, short *array, int *status);
+int ffpcluj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned long *array, int *status);
+int ffpclj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long *array, int *status);
+int ffpcluk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned int *array, int *status);
+int ffpclk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int *array, int *status);
+int ffpcle(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, float *array, int *status);
+int ffpcld(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, double *array, int *status);
+int ffpclc(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, float *array, int *status);
+int ffpclm(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, double *array, int *status);
+int ffpclu(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int *status);
+int ffprwu(fitsfile *fptr, LONGLONG firstrow, LONGLONG nrows, int *status);
+int ffpcljj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, LONGLONG *array, int *status);
+int ffpclx(fitsfile *fptr, int colnum, LONGLONG frow, long fbit, long nbit,
+ char *larray, int *status);
+
+int ffpcn(fitsfile *fptr, int datatype, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, void *array, void *nulval, int *status);
+int ffpcns( fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char **array, char *nulvalue, int *status);
+int ffpcnl( fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, char *array, char nulvalue, int *status);
+int ffpcnb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned char *array, unsigned char nulvalue,
+ int *status);
+int ffpcnsb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, signed char *array, signed char nulvalue,
+ int *status);
+int ffpcnui(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned short *array, unsigned short nulvalue,
+ int *status);
+int ffpcni(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, short *array, short nulvalue, int *status);
+int ffpcnuj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned long *array, unsigned long nulvalue,
+ int *status);
+int ffpcnj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long *array, long nulvalue, int *status);
+int ffpcnuk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, unsigned int *array, unsigned int nulvalue,
+ int *status);
+int ffpcnk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int *array, int nulvalue, int *status);
+int ffpcne(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, float *array, float nulvalue, int *status);
+int ffpcnd(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, double *array, double nulvalue, int *status);
+int ffpcnjj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, LONGLONG *array, LONGLONG nulvalue, int *status);
+int ffptbb(fitsfile *fptr, LONGLONG firstrow, LONGLONG firstchar, LONGLONG nchars,
+ unsigned char *values, int *status);
+
+int ffirow(fitsfile *fptr, LONGLONG firstrow, LONGLONG nrows, int *status);
+int ffdrow(fitsfile *fptr, LONGLONG firstrow, LONGLONG nrows, int *status);
+int ffdrrg(fitsfile *fptr, char *ranges, int *status);
+int ffdrws(fitsfile *fptr, long *rownum, long nrows, int *status);
+int ffdrwsll(fitsfile *fptr, LONGLONG *rownum, LONGLONG 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, LONGLONG 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);
+int ffcprw(fitsfile *infptr, fitsfile *outfptr, LONGLONG firstrow,
+ LONGLONG nrows, 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 ffgicsa(fitsfile *fptr, char version, 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 */
+ /* ffhist2 is a newer version which is strongly recommended instead of ffhist */
+
+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 ffhist2(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_copy_image_section(fitsfile *infptr, fitsfile *outfile,
+ char *imagesection, int *status);
+
+int fits_calc_binning(fitsfile *fptr, 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], int *colnum, long *haxes, float *amin,
+ float *amax, float *binsize, int *status);
+
+int fits_write_keys_histo(fitsfile *fptr, fitsfile *histptr,
+ int naxis, int *colnum, int *status);
+int fits_rebin_wcs( fitsfile *fptr, int naxis, float *amin, float *binsize,
+ int *status);
+int fits_make_hist(fitsfile *fptr, fitsfile *histptr, int bitpix,int naxis,
+ long *naxes, int *colnum, float *amin, float *amax, float *binsize,
+ float weight, int wtcolnum, int recip, char *selectrow, int *status);
+
+typedef struct
+{
+ /* input(s) */
+ int count;
+ char ** path;
+ char ** tag;
+ fitsfile ** ifptr;
+
+ char * expression;
+
+ /* output control */
+ int bitpix;
+ long blank;
+ fitsfile * ofptr;
+ char keyword[FLEN_KEYWORD];
+ char comment[FLEN_COMMENT];
+} PixelFilter;
+
+
+int fits_pixel_filter (PixelFilter * filter, 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);
+
+int fits_img_stats_short(short *array,long nx, long ny, int nullcheck,
+ short nullvalue,long *ngoodpix, short *minvalue, short *maxvalue, double *mean,
+ double *sigma, double *noise1, double *noise2, double *noise3, double *noise5, int *status);
+int fits_img_stats_int(int *array,long nx, long ny, int nullcheck,
+ int nullvalue,long *ngoodpix, int *minvalue, int *maxvalue, double *mean,
+ double *sigma, double *noise1, double *noise2, double *noise3, double *noise5, int *status);
+int fits_img_stats_float(float *array, long nx, long ny, int nullcheck,
+ float nullvalue,long *ngoodpix, float *minvalue, float *maxvalue, double *mean,
+ double *sigma, double *noise1, double *noise2, double *noise3, double *noise5, 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_set_quantize_level(fitsfile *fptr, float qlevel, int *status);
+int fits_set_hcomp_scale(fitsfile *fptr, float scale, int *status);
+int fits_set_hcomp_smooth(fitsfile *fptr, int smooth, int *status);
+int fits_set_quantize_dither(fitsfile *fptr, int dither, int *status);
+int fits_set_dither_offset(fitsfile *fptr, int offset, int *status);
+int fits_set_lossy_int(fitsfile *fptr, int lossy_int, 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_quantize_level(fitsfile *fptr, float *qlevel, int *status);
+int fits_get_noise_bits(fitsfile *fptr, int *noisebits, int *status);
+int fits_get_hcomp_scale(fitsfile *fptr, float *scale, int *status);
+int fits_get_hcomp_smooth(fitsfile *fptr, int *smooth, int *status);
+int fits_get_dither_offset(fitsfile *fptr, int *offset, int *status);
+
+int fits_img_compress(fitsfile *infptr, fitsfile *outfptr, 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_is_reentrant(void);
+int fits_decompress_img (fitsfile *infptr, fitsfile *outfptr, int *status);
+int fits_img_decompress_header(fitsfile *infptr, fitsfile *outfptr, int *status);
+int fits_img_decompress (fitsfile *infptr, fitsfile *outfptr, int *status);
+
+/* H-compress routines */
+int fits_hcompress(int *a, int nx, int ny, int scale, char *output,
+ long *nbytes, int *status);
+int fits_hcompress64(LONGLONG *a, int nx, int ny, int scale, char *output,
+ long *nbytes, int *status);
+int fits_hdecompress(unsigned char *input, int smooth, int *a, int *nx,
+ int *ny, int *scale, int *status);
+int fits_hdecompress64(unsigned char *input, int smooth, LONGLONG *a, int *nx,
+ int *ny, int *scale, int *status);
+
+int fits_transpose_table(fitsfile *infptr, fitsfile *outfptr, int *status);
+int fits_compress_table_fast(fitsfile *infptr, fitsfile *outfptr, int *status);
+int fits_compress_table_best(fitsfile *infptr, fitsfile *outfptr, int *status);
+int fits_compress_table_rice(fitsfile *infptr, fitsfile *outfptr, int *status);
+int fits_uncompress_table(fitsfile *infptr, fitsfile *outfptr, int *status);
+int fits_gzip_datablocks(fitsfile *fptr, size_t *size, int *status);
+
+/* The following exclusion if __CINT__ is defined is needed for ROOT */
+#ifndef __CINT__
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif
+
diff --git a/vendor/cfitsio/fitsio.pdf b/vendor/cfitsio/fitsio.pdf
new file mode 100644
index 00000000..31ebd2b3
--- /dev/null
+++ b/vendor/cfitsio/fitsio.pdf
Binary files differ
diff --git a/vendor/cfitsio/fitsio.ps b/vendor/cfitsio/fitsio.ps
new file mode 100644
index 00000000..769e1bbb
--- /dev/null
+++ b/vendor/cfitsio/fitsio.ps
@@ -0,0 +1,11353 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.96.1 Copyright 2007 Radical Eye Software
+%%Title: fitsio.dvi
+%%CreationDate: Wed Jul 18 13:51:22 2012
+%%Pages: 136
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 612 792
+%%DocumentFonts: CMBX12 CMR12 CMR10 CMBX10 CMSL10 CMTT10 CMSY10 CMMI10
+%%DocumentPaperSizes: Letter
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -o fitsio.ps fitsio.dvi
+%DVIPSParameters: dpi=600
+%DVIPSSource: TeX output 2012.07.18:1350
+%%BeginProcSet: tex.pro 0 0
+%!
+/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/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]{Ci}imagemask
+restore}B/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
+%%BeginProcSet: texps.pro 0 0
+%!
+TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2
+index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll
+exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]FontType 0
+ne{/Metrics exch def dict begin Encoding{exch dup type/integertype ne{
+pop pop 1 sub dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get
+div def}ifelse}forall Metrics/Metrics currentdict end def}{{1 index type
+/nametype eq{exit}if exch pop}loop}ifelse[2 index currentdict end
+definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{dup
+sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1 roll
+mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def dup[
+exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}if}
+forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}def
+end
+
+%%EndProcSet
+%%BeginFont: CMMI10
+%!PS-AdobeFont-1.1: CMMI10 1.100
+%%CreationDate: 1996 Jul 23 07:53:57
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.100) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMMI10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle -14.04 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMMI10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 62 /greater put
+readonly def
+/FontBBox{-32 -250 1048 750}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE
+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B
+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470
+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B
+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE
+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958
+9E394A533A081C36D456A09920001A3D2199583EB9B84B4DEE08E3D12939E321
+990CD249827D9648574955F61BAAA11263A91B6C3D47A5190165B0C25ABF6D3E
+6EC187E4B05182126BB0D0323D943170B795255260F9FD25F2248D04F45DFBFB
+DEF7FF8B19BFEF637B210018AE02572B389B3F76282BEB29CC301905D388C721
+59616893E774413F48DE0B408BC66DCE3FE17CB9F84D205839D58014D6A88823
+D9320AE93AF96D97A02C4D5A2BB2B8C7925C4578003959C46E3CE1A2F0EAC4BF
+8B9B325E46435BDE60BC54D72BC8ACB5C0A34413AC87045DC7B84646A324B808
+6FD8E34217213E131C3B1510415CE45420688ED9C1D27890EC68BD7C1235FAF9
+1DAB3A369DD2FC3BE5CF9655C7B7EDA7361D7E05E5831B6B8E2EEC542A7B38EE
+03BE4BAC6079D038ACB3C7C916279764547C2D51976BABA94BA9866D79F13909
+95AA39B0F03103A07CBDF441B8C5669F729020AF284B7FF52A29C6255FCAACF1
+74109050FBA2602E72593FBCBFC26E726EE4AEF97B7632BC4F5F353B5C67FED2
+3EA752A4A57B8F7FEFF1D7341D895F0A3A0BE1D8E3391970457A967EFF84F6D8
+47750B1145B8CC5BD96EE7AA99DDC9E06939E383BDA41175233D58AD263EBF19
+AFC0E2F840512D321166547B306C592B8A01E1FA2564B9A26DAC14256414E4C8
+42616728D918C74D13C349F4186EC7B9708B86467425A6FDB3A396562F7EE4D8
+40B43621744CF8A23A6E532649B66C2A0002DD04F8F39618E4F572819DD34837
+B5A08E643FDCA1505AF6A1FA3DDFD1FA758013CAED8ACDDBBB334D664DFF5B53
+9560176676ABB71BBD0EE56B4CC492C0652750227CEC7B86E4740EB7B8775564
+332769DD30794E501BBB0E4E5CB665F3628E10B1137CC8BC5C0A64A310B5E27E
+5FD6E3B04DA3914C15987E638A72790AF4073CE9CDBF6E3C749CB4DFF9C54951
+A58C386C54BC4E98B102B5E91E8567D2EEEF048F2CBD5D243701D20909290B4B
+A3083F632D8552D42DEE0C69A4B14D8B15AA082DECC12B2ECAE6F663E6D09F81
+EE2979EF41FBF12C9D8BF23B77E0A20088EBD107C5BF9DD6F03FFC3AB65B69A7
+54953327E1D4AEF5A146273392BBDB321D4CC9A8FFFCFE5C515B466E21546CC7
+C6209E5A76F916B03DB98BC6CED334F33E7B373D42761696F5A876CA6F93F16E
+15A07E2E102148CA4F62A99C
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMBX12
+%!PS-AdobeFont-1.1: CMBX12 1.0
+%%CreationDate: 1991 Aug 20 16:34:54
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.0) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMBX12) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Bold) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMBX12 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 11 /ff put
+dup 12 /fi put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+readonly def
+/FontBBox{-53 -251 1139 750}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5F0364CD5660F74BEE96790DE35AFA90CCF712
+B1805DA88AE375A04D99598EADFC625BDC1F9C315B6CF28C9BD427F32C745C99
+AEBE70DAAED49EA45AF94F081934AA47894A370D698ABABDA4215500B190AF26
+7FCFB7DDA2BC68605A4EF61ECCA3D61C684B47FFB5887A3BEDE0B4D30E8EBABF
+20980C23312618EB0EAF289B2924FF4A334B85D98FD68545FDADB47F991E7390
+B10EE86A46A5AF8866C010225024D5E5862D49DEB5D8ECCB95D94283C50A363D
+68A49071445610F03CE3600945118A6BC0B3AA4593104E727261C68C4A47F809
+D77E4CF27B3681F6B6F3AC498E45361BF9E01FAF5527F5E3CC790D3084674B3E
+26296F3E03321B5C555D2458578A89E72D3166A3C5D740B3ABB127CF420C316D
+F957873DA04CF0DB25A73574A4DE2E4F2D5D4E8E0B430654CF7F341A1BDB3E26
+77C194764EAD58C585F49EF10843FE020F9FDFD9008D660DE50B9BD7A2A87299
+BC319E66D781101BB956E30643A19B93C8967E1AE4719F300BFE5866F0D6DA5E
+C55E171A24D3B707EFA325D47F473764E99BC8B1108D815CF2ACADFA6C4663E8
+30855D673CE98AB78F5F829F7FA226AB57F07B3E7D4E7CE30ED3B7EB0D3035C5
+148DA8D9FA34483414FDA8E3DC9E6C479E3EEE9A11A0547FC9085FA4631AD19C
+E936E0598E3197207FA7BB6E55CFD5EF72AEC12D9A9675241C7A71316B2E148D
+E2A1732B3627109EA446CB320EBBE2E78281CDF0890E2E72B6711335857F1E23
+337C75E729701E93D5BEC0630CDC7F4E957233EC09F917E5CA703C7E93841598
+0E73843FC6619DE017C8473A6D1B2BE5142DEBA285B98FA1CC5E64D2ADB981E6
+472971848451A245DDF6AA3B8225E9AC8E4630B0FF32D679EC27ACAD85C6394E
+A6F71023B660EE883D8B676837E9EBA4E42BA8F365433A900F1DC3A9F0E88A26
+30F40A9C74C8E7773BE601C0E245E7FC10C02939848C3D28D823057B3EA23EC9
+E2BFF7851FB65FB12A4318A21D2C88EF9245D4C7BF21C81C4FC4CE0149E96278
+48F7BF97A5C3691E6CE038033AF54DE91D320EABF2B2E98617FD4145BFE5EBBF
+1A5634DA07B00257A51966FFC009CA416D37AD30F4BEE6D72AB64CB2D62466F0
+42D66D6D33EF9107272835EA9C1C8FA04562864BE684FD5F8E6DF19916FF8346
+F39F3E1FA2975B5CED24EB160FEF6149954F76C359E9D15A209EDD7445BB6303
+6AFF9E1373CDD50B93DB137F3896D282F5C04AF0AC84AA02D5421A73E3AFB735
+80EBE676C2870822BA89F4BA85034D6431BC4A44CC264DDD10EA146913E9063B
+038BD787A659C6A88C42FD5FBC51234664A8A1621A38C73ACB7199592AA5EA84
+B78BB5DBA7CA43E30CA8D3957CFF478712556EEAB1990C97B9BAB47ADB75E327
+B361D3039A3629B09EB84CF814773858F1D354AD8D526E85EAFD50944CBCE042
+367D1153D7B4EC4DD597DB0F57379DD63304869DEA4FA008D411E30ECFD62E41
+29F51841A9E07E066F06BB4829F87B7722562686FB801D6690F73233053B2EEC
+473B9899F284296BB634358A22DBF361C2A57C59438C429EFB04B80BE083E238
+A6749D6AAD1F17F318B880D26D230B86F80A99C27B87F7605DE40A0848543DE2
+4AF7D5BF61CA6B00FA156DBB9ABE7BB0EC79CE8FD5A2FC5BE17050F2A74E8905
+75A9982E12698B289E2213DAFAAE40DD22B424562D7417E8B82A5E3DDA814669
+D4CC949397B0DD2B0787016CB8FDFD09318719D7C47DB72E094C12C6DF3EDE88
+663D6357CE7BFE51FD4A93887F022E3A22DCBE39CA86E104CE54C05AA0B5E469
+0AB9DA29D19ED5E783225ECD1122BFFF5E4E63488FF215A9F555C190ECDAF130
+B34E6BFC66AB1F7D000CC09CA9872299E23EC9B0A8ED04135C982978B9D7C4E5
+F9C7968B540837CC667196C7B40F579E8258C8C7AC569AB787BB112C046D0068
+86AEC034183A3DE02FB82C2CD3E252746C012F2385493F59DDEFD5AA95A26C61
+BA64D85CE90339A0C19F538C6E0516513B9E7661505AB81F45AEA04618CEB379
+12F6BB94E2812F2B3C69BAFC9135B439D74C6A94C0317E1B2A2EA514536AA990
+7B94105AF7DA13148A807CB2F679DBDEE10B09BDCC8BDC7365166C910AA450C7
+4FD88CA8BB639F1BA53A4B108D2E1633C5DB38E64DF4881E0FC1118559A078E8
+52A0E2A87F98461EE7B0B56DFB6C3F340430E3D5C41C12141E4332951B4DF03A
+6824E8CEEA4AE8AC9F51981184287EC2710E4A51DB5E09DCFF4DFCE6B82A0B5C
+D2E658D38FA7B2854778650A78AF230E97A4C195865C404EC18A5FA99EA30FE8
+755EE5B11397D3CCAECD81EE3F3D1EE1A1B1FD6B669270912948134ECBA3D5B3
+011CD3286DD6729DBCFC9A8FC93356BC70A876AB636E5C8EFA89881D3A6E0592
+D4CDDBBD21A67033AB3354BA1333206874D2F7D0E571AAD845A96057F005F730
+C98EBDFB006EF8874CC386A0B611389F9CF5204C65AD951306B0E090BB287EF9
+CB7DB38F2A58E2ED6813F2138922E28FA44792E5C57A70C6152B4A6E73462F8C
+869886D1E5718C85F1CD5E7EC4BD73C6A4E3218A7118D42CFE42BB83A6B72729
+0E096EA902F81330771203309DEA91A560B56DE63911EBB6147600BB9B6A5166
+A818B7B8CE58279E22D776B2CF423897110CFF24807319C84A2063CA464C7616
+8260B36124AFE08188795E334864712574CC3DE12C3F0962D51734A44289BFE2
+2525F5D641EF82F25C1EAEA56C621525EC86FB6D09D99941D18094B7D77719E0
+3957294DBF2D221A49807B44323098D816A21C8F1BB888BC1075E2D6FD770014
+829050B6F8E297853701C467BFE76C1E52E8AFD5AF67B3FAD5A608C23E925F0A
+87E7F56B0D05F4D4276CE619190A983BB19417E280B53060AF777BCEA0D1F4D1
+B803687D9C2050D0B2EBF3EFCB9FE42E02AFFA5233A49D27550BF8B32B1A3A3D
+A8F58FC0FEC58439D12CC87CEEBED10BB6D9BE84DDDA7FE7A7283D2639212CEE
+2DA539DE06298BF452F896FE103A4BF864E5399C3F220FFFD82AF1975FCFA69B
+8C9782842F016682EFAE7269A34FDC5ED188E3E6E24FAA0345D9558B19521D16
+9FB47306CD1D15F36C9386347FCC9906A5420F4F6E030B007DF4D311B8E102DA
+A653AB0BA300D9467B092165B016C6F28E8D417E1B93A6A176329A67C5E0FF79
+167F9CD8E2EDD33D5B11348EC7BF4C88C3226377DBA6C4723CBE67A7118F3CBA
+34EF78E08A4211C39205325D138840E3F3FAA9CCEE74569B8F59CCE7E7D35D3A
+0999DB04EC83483BA245883D764A3CF556949BE4B121C6483ED26D192405EBFF
+089A97C4BA9649916F1A922F48CD04B7338EABDAEADAC52F42CF48272EAB9192
+C17906F59CD98D5A54443BD474385AF6B51B9C14EA8AEA27AE3473DC12DE901B
+42DC378872B001B2C929C54117E6EDAC6202BF1028AD2793FEA3620935539071
+9BA89FBFB98229EF30B0382D9D603BB451634BFD08901432F16B31C9245D3645
+28456E44DC8B6C9C052B9446107116AFCC2EC0F39F0CC7B5E146FD9E995594A2
+DDDE2BD3DDAE13B9659969623BDE57219731BD3893B63B77D5218B94FF535FAF
+2595C30EB0A003B144461C8115C5EC93595B4FAC2BC0D084E326E1F2CD14AC0D
+D9B4C1467961E2FFC04BD2DCDC1A16E9582653B1CECD98AEB6ABF1E88086FD2F
+347774D628A4E70B6803EA481996C07D6D84661D003CF3C92D32791A06405C2D
+BDDED14EA55744AA956D04CADD4B2F5A0FBA5D29CFC84CC54CBCA53B19FBB69B
+6199174100938FC1E16E7EC73BF85B058E235E282B17116250CC9965706D80F4
+EAE76E2F7E96E901CE29AFBDE9CF9E19CC2432DE75B4E67DBB7BF62C6A3A0C4A
+1800F457B745F18AAAACAB8DEA973869EFED9464631EA2CBE95F78133B4DA06D
+394AB1CB50B6EED8E868AEA0EABDB783EFB7F0431A450D9C48492A04BFE3A0A7
+9BFDE3B9DB2235EE46EF0D3E754F95819B6FD407E974856C83228A3C2A076966
+02E3F0F2F27CAE5C820FCF3AC5FF38C715B3DC3CE9AC77FB13382D2B606F469F
+768D1B82CE3D66F1AB552902B3BFC8E1B3A5A45D3C3D914D304070AAB6C49393
+028CD984C44C2D8DEDEB61AB45A4B2237A236C0D3088AAC5A7F89EDFF9A09639
+8B1887E2CB29D9E9B5630A45879069E58DA52E5603D026339E637D7B83E6550E
+CBD4349FB018A01749E171C987C30F8C36651501653A4421869F04A9B8BF792F
+41B8D1E9F9101B658EF726DE26BA616A20A667FE7B571F68FF3BC77B127EF315
+64D1D39C07799B45A40CA2D4FD81633368EC9654282A91B8F38066B3D781E8EF
+3DCF9CB050096E84E8DE000568251ADFB56AB4AECF2D29BB47110D277E5A1634
+D2813F9239951645D505C53CA91481C2B0F9DB72CC4C3EBB12D2BEB7B4201C23
+BE8EFE99CCC6A0D520F6282F0876E6A69CF5ED38AAA9066196A9456C5DEC58F3
+341797EFFF3040BB65E2479165581DD67AD36EDF24DA29DE341106F258C5FEA2
+D538201FBB6C0C3A132487E01488FAF2EE5A61E7079547278DFA812C5D822454
+F5B0E67620BEBAED135E63C8A55B29F685CA3CCCCBA06E2AEEECBD92E29B985A
+23B93078BF8A6F41125529C1C171D7A8C1AFD9017CC089570E45E873E74D7FEA
+7193C263492D4A6E73C65531C324FEA1CF9C4EBB6E501562EAA0EC4DA6C5FF7C
+49DAFA4DA93D9F35F06616002A66468D7ABF3B3CAFE293A7CE0D1034B971B063
+EF162C62E480D259E5AD6383DDCCB0F2CE0059E7E04681106CA6378D59F3EEE7
+0AF84F11FCB538E4155CEB05D48678FBADF22F99B9D6589629FAAA181F78BD79
+9D97F53E9FC10919970EF6CECCC6464540FB4A8EAD144B5662A4B0BAD31DEFA4
+9C1F280C18BBB0FB005896075E3F4C52C9F11A2C0DD60CFE581C771A72273053
+796AB48AD2500600E3355CE0C91E26DBF8C135C6B12FB3B2E89B9011CCAA3D2C
+AF8E2F38BE8D2BD82966B0037DA0B64A955AFC5181D3F2DA0F4FAE47875B5D3B
+ABCF48A2C3D1ADF69F5A3BB51D456B19085363318C3D371221A7319EDA644EA0
+C30EB56AF819CAE5DEA47A7495B463E388562FB76C94621CA7F0DF9FA6C080EC
+9F8AFC21AAAEAE2359869EFEFC8BCC433B683EE1DBE927463CEB19CCBE08ACA5
+B925E88AB69BF8EB7A0781F57FADC2111659F9A480B8B4158806CDBFD950C4A7
+0D792235486658CF8A96B0FDA2EE36468788225B794AE541683D2F5568B1239B
+2956E585AE96E5C0FEF1D632895B3A0E0FCC57EEDBAF40F395547F77D7F4F6D5
+23066F8B08FD44B1F26E89083C70FF24CE2AA2168AA8B09BDFD763286A243BC3
+0431A22C8CC88A524E2C3DB01F1B65A1540A8C2EF5CEA9303DFC3F3CDB20EA23
+600F870EC83EF9992A976ABA1D086EE4018DD3F7004301A7A431694DAAB46B29
+538000BA28F999C70C3F72C1DB5CD7B1A4FDE6A0A87BA98332EDD260D30CE677
+7176F2FE3D12C3434985AB6CC12AB6BD4872F5376AE6E6CA9C4871007D6DEF15
+6D15C96C0433ACFD3AD8DB22100ED3D696FFA7DEDDA0449A14F435E9868DC2CB
+8C1306330A68C38FCC010442A51DDC47BBFC474BCBA5A404A5705A0812B1DDB6
+CDE7EFD4D833C7DB0D4C91561C7369AEF96E849D23FBC55429427FDAF7E2DEFD
+18E2BA193293C0BF21F7241626E30573F2BB36C0BDF9A1065B2AE02DCE822156
+0AD58921ED46E65C40FE54C0F9C58AD8531536208F5A6F538836B74090AD8191
+486F29CED44DF9C4A547FDE7C40F833887845BDDCC68D84F2F445CD4D871FE87
+52681595A6D0DC3FE1E2B00C53AD686E866FEFC39F6C7FFCAFF8191C13F7598D
+3EBDCD33CA548FE31C67AA26568BE071A4D5750F9246695A4184042DB2FB0680
+C0E1FF57CF2E9E360828CCE1C7F22D5CC921A995DBAE0D2469D4C5147D607923
+455D9390580E120416B814A310E5588A0D54160728CCE53712D266C090F7175D
+96725CE1CF85B0E3772347D9DB0CB282F04A2CE1A1358675ADAB4F5504554189
+B141B5FA5BE5D2DD4FD88C91AE99E6504365853F95620C378657DBC98D06A4F0
+38DAC9CB25A11D8A9D224C9CAD1369245B4A8E19AA55523BA8402CF056FA7818
+DA762A53F9A2F02F17E23C97A38C14ECC34B985B1EABF9900698E122F11EB4AA
+E5524C3DA713271DAB8969B693A7CBD313F28120C7A68F4B3037AC043C992D7E
+F5829F11930CA70B580A161635228ECF20C5BA4D3B1587FD7A1D52C2530FAF7D
+C2C9431C7B4521296D391A3436642230E0E5D74E6D5E94277373513DC443B09C
+0BC80C1EA1F22A7F2F4CE3627E852B5A636DEC22ECE7FE76F53FFC41AAF1B490
+15E8060C6448F07997AE8D012B640630D72B11D77FBFF41F65B6EE2D70345A6D
+E6137355349A55DEA19D1DF5551B54F1E2F57E85568954AF23B2CA6D60859F11
+2BCF6FB935BC106B9BBCD8E8DD551D82C7D348E03B71BD4E052686F1A0D59091
+EE647EC64FBF77F558358129B938993D0F75673B45F41D2EDE54FACD6DDEF68A
+A8D55C257CEFC0E0D382C60A73C49DEC67AC68E5066749A1C00AE616A2C71A4E
+14A95123F58FB1D940E2A0E51EFA67C2F2BDEFF85376D211DD8F15D43F2CCE7B
+47B0CE25CEF1D450EFE17476BC3CFF661C1EFFC82E80E0A69FCCB25F39E51454
+E53912FF49EBFB3CD9593F6FAE81F1F0A9E167282286F8407F9F0023538D75E5
+76171E5A7005F053ECA82809C7073A1A480198BAE0085BA9BD1EF107D4324B24
+F96E24BB4FDD80B195546854618282F770631B5F3FEFDC035E6954AE76304038
+9ED525495644EA353E32F65140DEDEF41CD343B5333954D3A4C413BC3365B0B7
+3ED0DB1A27C60237A0E82407753C1F9817C4A0D7F07D328FE2216B34CB8A233D
+FC5A420704C8F1D42B57E69424267E5BFA8C2AE65BA324262DDA2812D893050F
+7D50D4487A5BBE53D7CF041DA6EF76A659DE8EE07DE413E940AC2160C994648A
+6D0D0A59860B4080977C18CF6540B5F5B3B4DB52EE9CDE105D965E9FE5999208
+02CFC8639767B033A3EBC2C42066F6E7CE3B8D6E2F25030D14957F7FA8E59A7A
+5685A8A8479545C373DE7778A5A65D7ED6139A2C8FADBE8AACD08D56C42D11E2
+CF01E2D78D4301556A8D7AFFF7642B10A36E93546EC8B2059870C472F5CD463C
+DE1DBB211CFF689095891B9980D9C9438FF7EC687DA72C548502B5EA0FFDFEE8
+D982B934E7A9F4D62428FC6719894C0ED4B0040BBA5D0FCBD0E3D80F2E245513
+4C78489DB71F2EDF17CEF7784370D080B75122290F59D4B4CAA0484A809CAD27
+94FE9EDD79994079695C3DC4440C6B2FE4AB0129F2514EFFD8615425F7E74567
+D93EADD0FB68FD8C6B9E3C1275F4FD32B8CFF3D8D04B185E2D702E46289456E7
+F6A2A0D83DCF29862BD08AD7AF05E3380AEE207F44E5B8C11A89E954AE0BAB81
+C5A8D1449693A0E5AE02D0AC8D1BF1CD96DBA29A747CF41292027ED8C05DD325
+8B92300CFA2FD33F14CEE073F8CA93E33BB952B2E58E666B1E12CB5634136777
+6D155B1855064842120EF87ED8B1CB6C95D74EF97C0B85DE90E266DD14793F70
+27038C774A64E5757DE6FFFDE5CCB2BFA4B771BD7D02FCF0530E0768DB74FA39
+2BE1C80A37A77AAC1B4972AA0335A6E51787781D482D01CCE8CD8FC732BFB1CD
+69E5BF80E44F7F484277E5D8B9611B8614ABB9C8865F26DA08108D355EA7B451
+2364F41F4EA9BA074CFD14377B092F4274F18F42B30C83ACFAF87513E8CC9716
+7ADFE45917E3B9D034F4ECE1455318BA74C68CD534B7DA3E3C1C94A10E7F5738
+46EF5ABAA7F58C0CB25A1F78F8FCF83DC2FA4F74B7F01E3141E1886C457FD285
+A44A1A57E968358BC29CAC2BC79CD14FEF92F522C9873ECFE82A01BC4191BAA4
+5D5212A7AFACEF600F738F4E6C691BD5D8D6F494187F43D42B1E876E6B12A02E
+8357B376CA901EF9945D7703E28549C291731B78BC185AB2D3EA810CAB3A500E
+2D2DF7934A616B3B0705F0928D97A742DB11392C51901CAB772C44113F1A5873
+54C74B49EA48DE55089AFFB75B288185955DFEF25610BEFF0789A40381A1ADFB
+95628B44B810062EF1AE97D6101B13B020276040FD886422F69A92254B222986
+500384843D82F4A706D5160CE4E35556253C2B73B539D101F166873974CB1819
+26D751F2E4DDA3D93FC7128C2515A75C676ACCAF8C07E2863951ACED319EB268
+87C5802B7C54317A414BF9DA26EA1B53C5A8A9536F54FBA1699E1FEC82403359
+66741ED2B98756BD5DE594C8CB2E0C24BB372EB2EE6F7910940CE6EE8D2770DE
+6343C52B4065B6AC1B3DE9C4575B8061DE6F05961E68FE6527BA66EC51AF4948
+8CEEC967F6E376BAA1DCCC8D50DC72C76DEE3644F890D4DFAD6E4B9115F43F9F
+25CB66AE9E46331F5233609A390523BFD6D642F6BEA65B7500C3F7C28D03C2D8
+A3B5C7ACCEB8147C62865F8DD2F844F294E8AA932F5D9482FE0A1461EF74BA57
+BF1848B7CE0CD572A583A6837F9D27B6844E62DB08DF1AC678861485877454E2
+FADCD5C87B57340824621B978982092C1334625551D36494A1E0246336B4104C
+B823C8ECEB49EAC4F8360867BA86FA2929918ABFEBC195C559BAF28B2396DE2C
+5A550C3A17CDB40C4E2A4683590B0BBE2031F525216083CA6D9DE3247D0B77A7
+7348225427CBD78F4C8DD795D010D66B5D16F513066C021F54DB36BC6902190E
+53470B96270C8DCE6AA8F836F926EC56E5A4C69BA37EEAAF22AB1D09860279BF
+97935068A4D11319146344CA8CA2B87E81D08345C699A81F0F4BAF56E39969AF
+A8094449E595CFFAF5CEC0540940DBBF79273B13D1A884BB2C354509CA95E582
+34284D9EE6992D5F3D2FCC09F99D1B8B31B59E651C17A174D98E2AE214332D44
+9F3769402AE4D2E6707450545C6A5322637648488BDE496DFA32BEBA617BDE88
+D07982B6948B94C91247FAAE6AC69A8727FD4AF3154C5F6B435379119898DC8C
+3110AC36907AA6653E28D292D7AFE2C3E54B6D29800BC7176B4F0D00E09904D2
+F5DF5805E4C8E4348F017ACB5C62DD8EE155F56AB87315F95BF1A7AF147B71B6
+AE4952942EE6676E491E9CA622504DCE2ADC678AABB16886ED89B6309EEEEE6E
+08D8133000ECFE0BE713E5D144DF17E98DDFC61C688E9A89302773835DDF9254
+A4985D6567AF8DFEB4335E1CD6B9D7DE23B009A7BEEED3BE0D7F77BEFB5BF2A1
+07A44B1F9CEF1EEB6D3F49804D6BC47AE26DF2F878E8ED4861FA691AF085A254
+688418486DAF652BE04054A8A8CE7EB42C5B30146C3ACC47502AD1BFB1A92DEE
+B3D317D4D2FB276BF7C4F11678AC10CBB01C3DA178A5C101BA5B995D18136261
+EE1EDCBF883B6BA4335CC33BCBB116EE70B1372E01E64DCFD534672D9C84FBDD
+79C8D2BDDE8D5C55F852E41FB5C1076D91B0D5C0E13F70B66904E08243EB3287
+C6257181962EF755E7A603AA23D63BCABF36F18684582182CC20CEA4F1DA0665
+1A8F1A4AF7C09F0351460919B10537E19A0ECA06DD9C00368137115979D3058F
+635AEB09C1C561D020B5E19358F216B8D17582A518FDEB4AD7735FFA2C746D5F
+163CA092531649865A1DA92CC8FDA32490826FAF4A9BA50653C2C3667F61D880
+D6523745251E5BADE8DB233EF3A62E7C92F21AA31618EB0A08D47F406FC07C54
+FC04404F5BF9DF6D2D53334DC93138323AE39E95F9CB2260995970E173C997B3
+414701687EFD2B2088E50ECBDF14FBCC612AEF323683D2800DC9B9EB054B8CF9
+3295728A29DFA6E22A98540806D6C89C34B188C29723DF52C50BBD4EF02C887B
+335A72FCC0F7C358AE98D26FF44F1632CAA1774AE6F8852EE8BC262FF77A2E24
+8B8833B7C9F9C65F94C889A06095776BC75361EA184FB5C5C8BA401A8D2D9771
+D0D71BEADEDFD70EF617B92FE12FEAEAFA5F6013A28DA3C666BEE78D103C8947
+3901E3B368BEE322935020EEE395B9701F65615D510809D8AF431537805E0B5A
+908D1B2C659582D0E54294B5BAFDF5FF482712179CE8F6820C3E72A73EE0A4C2
+43F792139AE3F8AB7A8D22A6D4C222B2B63CE37F0431157AD317A63E05067704
+85F00AD9B822B1506DA0551ED23099D53CF6E5127B5AB291B33EFBD26C21E9AA
+4096BA233B76B87EEFBBF8721EA8C37B933C5D901C4E451C1B05A5920CDAC618
+F9431CEED497EA77D36CDF497354E158B9016CC888DDE52EF00302C140B29C1E
+392F5974EF8EB272C054F3906F5D0B493C2478AEB0A83E469850BF76AE766B4C
+884B10B49EDB704B33AA96020522C5218D7258210572E8B274FBB05B51380F5F
+DD14C84263128C4D037314263E8B1ED48C816F06B39E32D5A894E114F9B1A2EA
+F255A824E41E768E70ABBB14964CA00C9C3EC281D14BCFB681BDC943BCF320C3
+0DB0B18DB7FDE42A3A2DEBF1746BE74E18BC0A8081DFAFDBCD64050ABBBF3A66
+72D0D7CA15E88ADD7F0A1E1F70D397D838AFECE3352FAF0B149D5DA940B518FA
+9594FF7171A2A6B77CD9CF96143DF0B708EF569CC135A2240343B3B50633437B
+BFCB0416AE4AADA1A480CFC134C1DBB9472279C4966B99B473272AF27150B683
+09C57E73A83E7339B022F0388640EF9561C518AF312EBF0EF120CDFFF9F193AC
+FD6FCCCC337922405224C8015431BA7610EDE19CE9176A6C1F552AC7413ABFCF
+EAE1FC65D1F56917B125E498E37D2E7AD170F0DB13DFD8D430523B774DF5B2B9
+971F0F78F0931E81A848B1E2D901BA1A011957B56831AA755DE617F8A40B843B
+470D96140340CA72B45C2BF0C0CB635A6D7B25A084AAD2830288ACFA119C3AF9
+5ACBEE18F38B244B7FD29210A7BF1D3A5EBD17E2B268C36CF439120B1947EBC2
+CF769AD003B5C178F5FBC3AB5D901682CAF6AEC1D66B3F3DF730C27F09430EF3
+81F32BE8B781338BCA00F8BB26B89804E750BEB587E558F48AE34A0516B1B4F8
+342A97EEE51D352EB39C2819A200790E5BEBBC50EF4FC2DB326FB61F969EC2C0
+98CD4F78F741C11D2744F26B443302392316A5C80A9ED122C7D27C1C89D098E3
+ED365F63F5F2DB3889A4EF86587722E0059123D95D3C471751D8D8E84941BB5A
+D14766DF319F648FB6FC6B39E94450BBAD6F83E43B92B72B5D4F6804031782D9
+9E40AAF10A291F048E4A0B6E726B1E81942615DD0A862087048BD3B261E8F8A4
+25D82D60D90E58A9F3C03CCF9593F0A8738F397E058AC523438F58B2AD206B85
+98B61EB8536BDEE0219867CD40F10F622EABC2D52297B257EA0DD929B0BB7938
+158C6A6BA70514C27CAD1F310C493FEFC4EBCA10CE4F77686C374E1125F69855
+9869DB3887046E82DA5EDDBDECABBEF1E050B26A91A6CF23D3F06B4206D5573F
+EDC6CB4DA302A355CD3CF80B54B270FA1844FB5DA988D08A754D30CC5F8DB71A
+5AFF8F08A67CF1DF916E3370D961EBC802E2AE36B25F0B2BD2F01DDC9D52E45E
+18D579D5C4A750F27262D2364A1CB2BB36B116626A9C1B6E35E22E81FF695E1F
+713B9461726F5427EBABD116AF543A84981796A6FB49F72BB7AEAB3ED5E771EC
+D1823DCED5EE170126069B5369BFBE2C1225EF0E5757B2ECC2360F8EB34EE3F2
+5F39660B7F714A82EFF3A61B7C9D26A32FD4C6EEEFABDB9914BF7DD6FB240198
+81F121394D0C2386738E343645A9CE8585145ED6957EB06466D5037B1FB3210D
+CF0E79E0920167C5DBD605FDF8A66F96CE741DA7DD85D629280681BFFCEF027D
+C9390E2EE59F24B714AE30A802F112BCA54AB3FCF419F65B4B27CB7A543B55ED
+350D9BE596B15AD6F79730DC86D82DD075390869201CD6FA2D22F77FEF7619AE
+6FB42C939079757BDD06BE3B8A7CE60AEA6D1B753658F858AA2584D4A4CBAF7F
+0D701BBC0379973E5753B848BCB7CF56FF30E5AC9D2E83F33B4D87DA222F1306
+1877A2D810123D951F5CE12B17862EFDD5A86DA3A3987D973F70541D70B0CB3D
+0F214AD4B1FFFA21A29E5C7856CE49FA93528E6D53570E3D8D6B17FA27B28AB3
+FD2BBCC63139FD7F86DE6A84A2204CB30FD14080D45EA14EA784A5471ADE8A70
+2864A204F10AA5B2A2C870521B97AD75CE3F6C078F1BACC99BBFC0E2F2387022
+6F72BF44DDB62051E1B81A1419CF2F033B77FE46C2208E7DA22F83392EC97328
+9A5E3DEF8BD6323E16D1D14FCFC890BEFAAC9F879198703CC9FD0FEEAA639EC1
+B787D77B325A213B71ED56F1ED09DAB41AD4F8E314FA8154BAACF480F110B939
+86477401D4ADE8FB386CE8959027A8B91C56C53028C7AD7EEB61DD986D303572
+86324689E1AFF282E10F789421EC2BBFC5637C18936B1F2B4D02C8C8D5039503
+D425992185042BA95E50C1ADD6563F3C661AAAF32E29F9A4BD3ADBA7A55962F9
+ADD1CA560CDF1D0BEF0C57E4EA11587CD17CAB65D9DD830CB738549C6F614612
+FACA8E3031BBF29682324D9E12BD792F9F3A24D7250D2AB55FC984C6CDBE070F
+5F6282F51C4DEAD075EFA1820E044174FDBFE9AABB68E6254F4B59E8F442DBCF
+D2AE8ED7ACAFDD486DD36530A71F9A0D9FF91B19FAF723B4909C9F99D5CB29F6
+2CB6384D6A3544359AE23E09770F82FF7C9327BD392BD0F6B607897B6D826C50
+B84B2E0722B0E27ADD479E5607B4500B8ED238B99C40B2BB47F02352BDACAD22
+262DBFBD38A9D4D1BAB79053F4F172397F8F7C00CBD37164A0C89B7E31EDB3C2
+25D32798F7F83582CCA56EC0F419316EDB2F3299E40BFFFE63C5C2A0ACDE3C9A
+414C2BF9F341F40FD4C8A5B1950EA05A26DD6CE187E181E6AA167F26AF6A4E5D
+6E4AE9430E0069749299D2B9D8ED6A3E647BF2707948B8F6D16D4DFBBC71BF61
+5EBDC349EAA9EC847880990795B75B118423D9153B05D5D6BF0D20E909F8B22D
+0DC9A8CD8CA5B43D92F4CB54344B375926EEFA5BF058B7BAB54B5C97BD5653FC
+F05BB1A5991B068C26B0420DECA3F1943D093997A3A8BB061BB25CFFC0CA1DCD
+D85CB203491D176C4C183BB124F22D57678841F08419028F250C30D1237A0213
+E5A392E60B27D2BE5240346B99EAFF9B57F108DA66B6AB826546C6411864F7CD
+FE404BEE7D58F28580C448AAB599D12B00A3FDB2BB93737971A5E13FD7CFA970
+656D45145A54DB1BDD0701097445ACF73861FEEB01835F35790E98EF162D5F37
+E1A5617CB2BC22074305FBDC8024E741C7BB0FA0E17F123AF953742E01AF56A0
+AFF35515ED55F9621AAA309D36964B0187F56FE1F02662B7DFD745F2F3BCCC43
+23C8FFD86F382E99DFF681A7D22CD133153C40C3FCBDF86DBED11FD36F9B6B3F
+C5FDBEFB72496F3C209BD61EB9558CB2BB1672CAD20F8086DF3492147770C0F5
+95444F8731D0A1F6036C3099DAC1993B2C838794554E8A3B96614090077BAB84
+A5954FF123B90550E1D1A4AB2CA6E8214C473B3CF56746959C062AB6C28EC09B
+F22096BF7FB6321338085C726C42745088742C6C55D4EA9854CAA71E7BAFEC70
+A29302F3C909A6E193ACDC6496F7929713DDD1F4B813D73E794377CC0B956B9C
+2D07F5AF8C01D7D9F932F114547E4EBB953ADCED8B20E83FF41B1F4FA5A02915
+0C63DC0619BD7E3B5E6FA60157A21794D7299C5774C0FF7D929FE9BC1EABB7F3
+193E83584567271D2123E6B069DC23889B93CBF2ECE77CD8CCD649AE853784CE
+A79337DC93FB835373CAB6E183F5CFEDCE41C418E8C0C48D02BDDDC0CD3D3B4B
+285195948E36529F28A6F925FDF16248F9331CBF5A08DC0ECDE2C36FB0A0AB89
+2DC0EA84D93C834DDC1BF962D89153901ED7784D9E68BD06357F279CCB7C602B
+CCF4F389CD7CB4197D2A9271D65097AC31DC2FFEF76884D0910639237DD0C020
+F0DDBBAD4C2883ED7313DFA0539D989C1FABB6A5ED54FC791B196AFE787363DE
+6688123AAD777F27E4DD19C32B7FAFB9E8E0552DE8DA00570B1AC3E8CA4C7866
+6CDE42B4CB89FA30F0AC964EC7F2F77D3F1980313330F26E545BC7A8F5072AA3
+2FB0329361BC8BE2C2B48FD060C89CAED6DD9BF6462BEE5FBA59C569D8EEEEFD
+8C1BBEA3B73A537D1256C7D6CC73A9CFA3DDB34252A3A4509536D62802A615DA
+4AC07C441743B45A15D85181482717316C5B12F6E52BF9A1C287801F3677CFEA
+6B60F505F9234792D6E82DCE04C72C308C0D17B80B14B291AA4B437DB7CE5E35
+436CC41F868ED6162F25BE5C9FE406FE656FAAA39A72CD5DE07569F21C55198E
+54678E869AB6959798013ED6CB2D9CAF568F43D2624ED5F602B7F16F9D27C12D
+48EE40743E1DA97E6702FC3634CEE0AF9E6FB3C4587346219C4CDC0B6CCF7F99
+E40B48B6C7F5BB21DA0656B683E71A4CC310B001A180D9E00BE05215B170D2B5
+C93C2636B61BA3A840076A5F41B8DB3E0B2A38C3848DB0CCD419E5E14DCD1397
+AD9811172CE82D7CC7D825B6722205E0072FC807FB647E0442333D42CF799579
+C7B7406D147A69C59E03536C8D2EF372AD9C374B977CE1A0784C83073742008E
+480EC148196F146C5278FF1EC8252E708B9042389C11547351F093CA8488DC3E
+1D5126DF92EB568240BBBDD84B2129B6E8FD6999651566BFB632984240E14F4A
+E8F5BC9C04ACFB19B327E5246E5BA5B73A0A308D930A588E57174574ED2FE506
+9512E3CD02D75AFDC1A36BFB585493E4164F3894679FA602BEDD8CE9E821D187
+47CD38794364E336B65126F61CD3CA861F9919F24CDD410E5F03AAFC4E45E30A
+486F6CB28CE7A6A2125C55CCCC11BA659E72234CE9D5F6
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMSY10
+%!PS-AdobeFont-1.1: CMSY10 1.0
+%%CreationDate: 1991 Aug 15 07:20:57
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.0) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMSY10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle -14.035 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMSY10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 15 /bullet put
+dup 102 /braceleft put
+dup 103 /braceright put
+dup 106 /bar put
+readonly def
+/FontBBox{-29 -960 1116 775}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052F09F9C8ADE9D907C058B87E9B6964
+7D53359E51216774A4EAA1E2B58EC3176BD1184A633B951372B4198D4E8C5EF4
+A213ACB58AA0A658908035BF2ED8531779838A960DFE2B27EA49C37156989C85
+E21B3ABF72E39A89232CD9F4237FC80C9E64E8425AA3BEF7DED60B122A52922A
+221A37D9A807DD01161779DDE7D31FF2B87F97C73D63EECDDA4C49501773468A
+27D1663E0B62F461F6E40A5D6676D1D12B51E641C1D4E8E2771864FC104F8CBF
+5B78EC1D88228725F1C453A678F58A7E1B7BD7CA700717D288EB8DA1F57C4F09
+0ABF1D42C5DDD0C384C7E22F8F8047BE1D4C1CC8E33368FB1AC82B4E96146730
+DE3302B2E6B819CB6AE455B1AF3187FFE8071AA57EF8A6616B9CB7941D44EC7A
+71A7BB3DF755178D7D2E4BB69859EFA4BBC30BD6BB1531133FD4D9438FF99F09
+4ECC068A324D75B5F696B8688EEB2F17E5ED34CCD6D047A4E3806D000C199D7C
+515DB70A8D4F6146FE068DC1E5DE8BC57030ACE57A0A31C99BEDB251A0ECAD78
+253AB321023D15FF7F55A3CE81514C1E7E76240C1FB36CD4874DDB761CC325F5
+D588700B294849D690F93526EF438A42B9B5B0508584EA3766D35F5B8D51C458
+ECB9FBD23A49576EAB06BACB7EA6D300985500835F4FE597D4A1110C8EABE6FC
+CE3E1F95CFD3A42446F25355381D476B2FFB6EF247BF58A6FFC5EC0E4CC207BE
+46485F8E07350B37DCA8C1864E62614332A1D3C9DEDDD6492181949A2C3498C9
+EC2A81C1F4FF989A4654E375F509D24D969B97D2A9940FAF43BBB286E08559C0
+F8D9674B0A294B36D3A050F7DED8C80E1D230812F6B8387B17948FD29FF050E2
+AAC5EBE5D96AFD0879534E2F4BB81613A1571750F9CF4215199F93813D815B5D
+1C79E11A0FCBB627CDE569F88C741CD502627777BB058ECAC09B6ACCFACA69B9
+8F8168B0B5A1A6EB13E884B348FBB2ACF9EB180F6E27D57F8503710CE037A34A
+F8B157201657C825E2A4B4A7696B58B7A988C05E43E66F0FF277A7694C555C54
+AFB1D32F6DE102136FC810E1F3B5CEA42476EAC7AAFB390E3252B2169DCDEE6E
+328507BD0E24734A85AAA263E0D2F64BE1607455BC855785BC27F8B30FE917B4
+23AB3C812975355942E955501AF85A3C0CE836911AF679EA44AD6A7D042A6549
+0C471FE294E8490024D93ADCADED460FAB7FBCDC29EFEBD2A9A127E11869E659
+961B29206CE63944B6FA4B9315BCC528EB1E0223CE94C795A5D5231A7FC8545D
+6B287B965F8EEDDB67A6774129DD01D5A21694ABE320BB2553043D4C42ACFF91
+1009372CB03381035BEEEEFD05631E026A0980A72A67B3703323A4E7C94FFCEE
+8D0B7407F9CCC043D3D184BEA4728385D6AB2FB0641DD8F5BA7E04035D30D628
+7E97D31C1486DFD5B1D076B84B4ABA4829ED4310321F1F24B847C44E00185A69
+37711A
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMTT10
+%!PS-AdobeFont-1.1: CMTT10 1.00B
+%%CreationDate: 1992 Apr 26 10:42:42
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.00B) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMTT10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle 0 def
+/isFixedPitch true def
+end readonly def
+/FontName /CMTT10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 33 /exclam put
+dup 34 /quotedbl put
+dup 35 /numbersign put
+dup 36 /dollar put
+dup 37 /percent put
+dup 38 /ampersand put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 42 /asterisk put
+dup 43 /plus put
+dup 44 /comma put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 59 /semicolon put
+dup 60 /less put
+dup 61 /equal put
+dup 62 /greater put
+dup 63 /question put
+dup 64 /at put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 74 /J put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 81 /Q put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+dup 91 /bracketleft put
+dup 92 /backslash put
+dup 93 /bracketright put
+dup 94 /asciicircum put
+dup 95 /underscore put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 106 /j put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 113 /q put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+dup 123 /braceleft put
+dup 124 /bar put
+dup 125 /braceright put
+dup 126 /asciitilde put
+readonly def
+/FontBBox{-4 -235 731 800}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5F00F963068B8232429ED8B7CF6A3D879A2D19
+38DD5C4467F9DD8C5D1A2000B3A6BF2F25629BAEC199AE8BD4BA6ED9BBF7DABF
+D0E153BAB1C17900D4FCE209622ACD19E7C74C2807D0397357ED07AB460D5204
+EB3A45B7AC4D106B7303AD8348853032A745F417943F9B4FED652B835AA49727
+A8B4117AFF1D4BCE831EB510B6851796D0BE6982B76620CB3CE0C22CACDD4593
+F244C14EEC0E5A7C4AC42392F81C01BC4257FE12AF33F4BFEA9108FF11CF9714
+4DD6EC70A2C4C1E4F328A1EB25E43525FB1E16C07E28CC359DF61F426B7D41EA
+6A0C84DD63275395A503AAE908E1C82D389FD12A21E86999799E7F24A994472E
+A10EAE77096709BE0D11AAD24A30D96E15A51D720AFB3B10D2E0AC8DC1A1204B
+E8725E00D7E3A96F9978BC19377034D93D080C4391E579C34FF9FC2379CB119F
+1E5BBEA91AE20F343C6420BE1E2BD0636B04FCCC0BEE0DC2D56D66F06DB22438
+452822CBEAF03EE9EAA8398F276EC0D92A7FB978C17805DB2F4A7DFBA56FD6AF
+8670EB364F01DE8FCAFBAF657D68C3A03112915736CEABAA8BA5C0AC25288369
+5D49BD891FABEFE8699A0AE3ED85B48ACB22229E15623399C93DE7D935734ADA
+DA7A1462C111D44AD53EA35B57E5D0B5FC0B481820E43222DB8EFCD5D30E15F9
+BA304FA879392EE0BCC0E1A61E74B3A1FC3A3D170218D7244580C7AA0DC65D19
+741FA5FE6F8CBF60250ACC27454BBF0897CA4B909C83A56672958752ED4B5E79
+E18660764F155E86F09EFA9F7685F2F5027EC85A775287B30E2069DE4E4D5712
+E7D033481A53A2702BA7542C71062173039030CF28D8B9C63B5596A9B42B33E7
+D922944A38713383D3648A4AF160A3B0C8F3379BA4372BE2E7EA49AABA75AEEE
+C5DDE1D8BF68483C3D21271280ABB91D54CC819680322EAB72E1250A760BC8DA
+726405EFE420635B5B7F0B48752C06083E92BDE06401C42A2C528C8A60381227
+CEBEF0C9440DC034DAD9C19FB27DB399BDAEE22053591D6538587C768C1B7B0B
+7D1E222D2D8AF3A6473CC4C0D6C3E0DB49068CEB8C9BD1C5CD486A50DAA10BC7
+7D6286142355E3F21DD254E27C00C442728A0BAEC9D3F17AE9CE320D365152E9
+EB0D5E3874F2BCEDA98521D23FCFC30B4B69DAD2ADBE80E5964ED0ABEF6C73B6
+DAD30E2C5061E3747FE536E1A5D190D028F2130AF608F5DDF9DDDF1E77DC8437
+ECB3EC93B33505DF47884DDBD1DC6BBE4098DF04A29AF6FA3AE344600D0AAB53
+B3820DD7ECB600A3B8001C51AF2CA7A39AE1485A087FD1752DF68F55B52B4DA7
+48030F2AA7E570B3D56C4EAD367B9B73FBC0A7356253233006178B9A6BC19081
+B815B5988AE76FE6FAFD7AC239072B1106A3F509381AAEE79B2F2154CAC4727B
+D199CDC8B4D05DF4BA006982512ABD7539E28D937B0F87FF79A3F84C29ECF943
+A8DCB8BDF8EA9E7A0E7CD60BC2308C96B3E889C797D0FF28FF4847016B3DA141
+E76FC6BE78A6EE9CE07E651FF86E720A1A1F075972D36E5C55162E3FE26BCE3A
+814BFEB12D4C5FD24340CFFED499C7CA183E57EC4F12CFFBE3291D43F7270575
+C6C3306F832EF182ADD0AA14C4D8669A17C09F632406AFA195F90C4DDC39779E
+EC0A77E590211592D6EE19563963225C06C2F13265EBB5A6CFB7C17D9E77650D
+11958305727AF662AE73AD0E3ED5F7E7086C5A0C3548A8129575980B06C715AF
+DD55C8DF869BED0A7883491030B1A7E82C5EB04E5A7D952E716DD8F2EF6275EE
+087614CFAB55FCE2BBECD7E8D9C90FD8359E929D5E0A416A23BD58158318B4FF
+87B095EB63F7F052B3A77F136FD66EB2C52BD46CD7DB3091A4B78A607112B12C
+4D171B2A00B78B0E1C44B0D90C20D9244281F5123DC1F6063F91E9E3E48DE78B
+C862D848BAD073A4FCB5EEC9FF54B5AB8E234CCC3C7439C62ABC4A13EF1B8897
+ABBF21F900C564C9A305FC36FC7224932F766E6E72C2EBB55953DFE2AFC2E3FD
+33A0C6F0FDFF086E9FD796E7242596AE85B877223532667625E371D2156E4C04
+0D7FFCD3337B93DF066CB6FE1E13960719EB7CB409EE805C08ACD2C06303ED9C
+E34C898787A43C1B428B896551C6FEB50A831C6F8CE2073EFC662EC286CB7555
+A3B42E58772E82FEE206948B8C439FEC5E4ECB9E11DC3A4CBC7611E30890E408
+637A01A2118441B4F9467A98BB2A1B03BB2F5D8E3DB7D1D15C188D9E856088EC
+B762F07B1C06024F7EF53A2FBD60C0A1F4C0275D07164545250ECEEF8CB15B04
+A2D8AC44DDE818C4E3CBD2A5FA0FE49750886CD7CFAAF8B780255F89DF7F4F5C
+BB594FE7C1597DA71813C2952AD3E811524459EB71D29696B450C924B6A5C843
+8F36A0F1D7DFE796FB9564333666D74AE614D0D698FAFF20F83C86524C894BB0
+272221C060544F3B653CB0E4E4F82B20D7530B3806E6A5830852C58070177815
+E287C847F19F64E854F1463C23DDD80093D6FEB8BAA22C5F05C21F99FBA7193A
+EB7CD49CFDF4308C6C68CC955A45FCFB54FCADA9A3BFBDE086B057DE88BE335D
+280F5338D7E66AD39FD08F9B55884F1F377FB6869FBABE3EAA4B7ACCD85BE672
+724B4B8F236B0889B6E7049CBA558A89F17863E82DF145DB8C7ED1F36332DE23
+3C0053B74E850FA14F9EC9EFC23AF18E153CC96FB0FFD910347370E57F0D81E9
+4A83E2D189EE5635E85A2BEAB5B1CB974546BFB2FC2ABA1E15DC0EC1BB3AF1DB
+B2F93538B92F504CBD7AAFE36F5F3AD45EB16378F169B17869FE81464CB826CB
+400D2F5441A496B6C60A4F15FD20ECCAC1F8F91015E7E1C1A10B7992A1554E52
+9FBEE905A3005336E49CB04BA7223F1674C0BBDFA06ACA34F7BFDA56906E04A7
+4DD79EC7E79B021A5008F3B1E04712D689366F520B0FA66A558F957011992728
+561BF4B75C2BE07C4024C172085E51CCC5CFA439F570297154CDDBB3AA25CD6A
+3004B936488851BA1E814260C06CD5479DCAB1A6AE21A5F4563024F973D738B4
+0DDB6C6DD2E3AC21B4F6D95CF9AACA782919F5D3E613D61F3224A982AF485C8D
+EA0037410EB70AB7D3EC174C6D5DE5C9C5A1220EF7C2B74499ADCEEFF077D1D3
+50C1124535F88C3C3F66477E42F1932665AD323E06B398D2805B9CEA632F5B1E
+50FA587B102A35E2F15EC22DD66E4DF06A3F4BB717A3ED7FBBE2458EB4D896DD
+AF00D1BC71FE1CCA27890ECBF9F0AF01D3E65CAA29427FAF06B3BE1E640522E0
+73B213D04491B93DB29113EF72211E31F4C5A7FD58451946CFC15FD805112FE2
+547D1131A46710DFB75659A33695FFAF3CDD40AE5260AD6766DA81DAB0A6E96B
+E89D57AAEF32B5EDBBE9F7CC033BB2595CA3FEDA2ABAC8E5395EBC35BC112FE9
+67EAF1F123228538091483050847F8FB5194203609502D3A09CDE811EADC18B9
+F039593782C27EFA7697182D6367E88E326AD5622C5A457FE2644FEADA88615D
+9DE3E483BFD9329667953CDB86F9D2F0D4F02DAB8A98FDEB1D17CAAED9B6E2E6
+0C55C1FEE25AB98FF59FC235876029CE03E4A713B75B3163BE3B2DC0D4472DBC
+473E10400C0F57E627AE97FD0C1CB0F78FD8E2FA831A3D2B1C2BB3F2D4E812A4
+194C8732B0C525361DC8480CB27C30CD4DCFF01318D2EB4F5234B4A42EA8C23E
+7B3EECA41B8E4F54D5458B37EF0FB2F49EB19F4EA8AD2B53820FA36E93DD309E
+48847F5C01B1118ECE7D0186E6B8953344EB775D655AAAD7BCDA642EA2E39A15
+855C027CBC0E3FA752900EEB464E2D39404D1B85072B40834748C6F9C74C5B6C
+3CEDE988343FD984CFE4B856A481E60E2E65D3BB41BAF2FA80AC0BFE381071C4
+573C6ED65C524FF777F34D82E9661E4A75E3878CC77BC59218244612219C5A92
+E95B90EC2C38614665550026F1730D11162F19D841681C04C401E102C047541B
+97B9264D86F47E25A347696AE5EF0FF3ECD9BA32C92901DEDD816F7D73ED1216
+0A98771892472CD625A8F7F19DEFCF5CA2AE57F8AD3898F2C1005B187DEC6F2A
+A31C32720EBC934178E0E9979013B3C9AEDA4051DF63D8C903A399DC88F83DCB
+A73F1B2083819D1BBEA5235F8FE1D098F32A2BA6274424A99A4975FE4BFD59AD
+79B40A8003CC0AA728EA79D6BDCBBD73DF45B7918BC099C5BE4A068BF64A30B1
+C39442CED98AAE1BD495F6CA32D564A72E3BF753B49E4178927E4BBC0F06048F
+96DE7C30AF580B0BFFDB330B3B87D7F6532A24F403680BD9F15E758CDF04EB94
+E83C7E644FDE5BEE7CE73EFAC75669E41BDFB20A5B8ADE1137378DD8102A0DBE
+19499A623770417CBF5211395A6BA9F4490F4707A46F1F9B3FBE642DEA0CA053
+9ABC307B1E71DC2B069DDDBB4EAE378BCC75AD61DA900AF8BA6DF0E27A8D2258
+DC80205305AB6ABFE3726703E60869BFAFF1874F3C0E05FAD9C05D7D89ECECA9
+DD2AF5F777D7514208697E712B52448B364D3ECEFD8127043DDC9D0757B7CC37
+5CDE8001D007A6E961EA24D7FFC92410F3B13A32946F12A50DFFA256249BC8D7
+C1842FB84AD51B41008EC4604F6B70990510EE13E6DA34F864A572D99A13FFC7
+3609EF2BB1FCDEDF37A6018248C545E086EAD1BA1143E74AC60B684E755E59E7
+36557B915F92EF78FC177621D49F777A2AF39F3C2AA6EC74750AAAE08BCC21CA
+A71CCDC91DD45E6050D83ABA49ECE425B55EEE137C55619037F1C30530BD0A6E
+CD2004B6A040405064D7E87C55536680364E09248BFAA3FDF95CDA0708E55F4C
+F7D0A92A93DEE0C7B69638F171B28B7F854CCC6EBC6AEE14864BF5144EA36D46
+A9C297225AB0325E28EF6BD06D7E40E3A724EA1E50C4C6163B195CFFD5DD291D
+D7BBE9AF4324A69394117EFD62F08D6BA6A8F0AC3E2353492999AF28FBA758C3
+A50B6840CC72054355E6CBDBD86F683537A4115049BC1616BA35C2B0B6F5CC32
+3F6831DE4E6029310738DE23D36D2C6E82F04EB675FB89789F74AFE3B8854250
+51812FBEFBCF162947554324FADAB765C74B6DA89F60A734076D44BBE45263B1
+3FEFEEA90EC7948F23F34D4049087AF6563692417DDBCDD5A9552A373C2528F8
+0318D3C0669279F292127CBA40B0ABE08A1476BC9EBFA8BD5D622BC5CE7DBA20
+C689BDAF50D5B1EAA89E296787CC53845DB2BA54FDE363DCC98A7BA256663869
+E9E02E09077884DF1A2A41AA698B7EDE8DAFA621B552DDA91AD1E671D636FB36
+91C62B4D2D4112F2C169E0023EB7521F570CECC54ECA5EBA462049AABBE2ADEF
+E3234BFD71B26DFDD9D34DFA69E5E80FD90406E6505A6798F030A4B5172A7BC2
+C9B765A86ED55C0590E0432719BCD7BDE7CCC7F6B33BD467063D886276C8879D
+E04897A4623111C14A1EDBBF69E2FEDDFEAEB2A785C6D2F0711DF4B93AAA291E
+7F4E0CF9CC3FF0D31953C594DAD014097DA02CBD5AE8828C7E7B5BDA09188B05
+0D7263F164E1E78CC430ACAD1E8FA71001E9BCEFAE47C79846916A5F819CA366
+5734089BCDD458CA1A9E8E17BFF357A91F9A7A8A6E1DEFB121353AA80F1906A5
+AF7CD2E59EE6776FC0DA6574DA0DE522918CAC4E566F13FB9B64EFE79F3A3BC0
+689E3B0676741C90FF3BF85C7A0FA9716F4ED0E329512B66BFB8AEB56C3DD6B2
+24F8D6E23751A8485F7EB46719E9D22618FEE86D5E01ECCF4C6E74368A8E9B49
+245D80E7484DFBC916FB2447852B36EF3F99A82B6C106F786707D7689DCD7AEC
+A0C51AC1A3F67034C16B74994403FAE7743BF02149BEBEF554814BEF31B79184
+3FAB4D2C887E1BEE81B465D12DCDDAD03DE5ABE9E763C440B2CFD42FD16D96EB
+C21FE788C8C2688F79F148AA7090BE64B0EA710D376222FD1590301BA9A2E715
+D33B8C1D95F2589AB0EE476F7046537E27DBBCDADEA1E7357C9D7FA92C2F93A6
+7BDDF58A44966590821023380C97CDE37EF6D449E35EF32BCA6E69DC8458511E
+8DC8AB63171A6018AC9A334829E5978484C4C6E917A5F1C254E6669F4037C691
+36980250A80673E0F18C9E0FBA1E5CCA3BE30B8E7B7188062B25F8E1E16528A2
+F217C18D6A1955482E5463FBF097ABAF7314E449C6FEE56E2695407A8AA9648C
+61AC2BF3B2D9CB6317A9B16CE931D318C8BC9676CD908505568C197D90C2BB46
+06431C999EB68C8216409E4CABACB2BB34A05B697B9DD1E91471A404B4969519
+E25209EF4EDD420944BED17B18DB3566FCB8059699FE416789191EC2B35086AA
+2E10C139E3C9FA0A535DEE9255A867A26656213E85851DE5F51F9780D3A6E572
+F1F5CE64DA176CA810799DC1C60A8FD2A5ED42E613021A19928EC4572059B2C1
+EE441E79CDF7DD4AF7B6E3D3230419ACAED329388044B107DCB4DE91B71EB838
+904B1F969738BBDA064FFE75C6623639BE9924602DDF0C166B433B9D54ACDA5E
+018680477FB8F10621FF32319E58DB672D744959A33E7314A1B3CDE0C038F7D6
+0C8A195AF191E36B0325334A711CD8E25D9C1D257E46A734779E486567481108
+E0281DE96907D460546578DE83A0A01A9ABF64402B48DEF739F4308E14145753
+719CEF720FE5CF8DAD7845E74D502B69DC18D172C3A27411259B8042F3FF82C3
+B157BE242C351830255CF0EDA96577375A70657BD9A2E9FFC54AF0AE563D73F2
+E510279FEF48D79F5F7745DBB492F1D74DA738E6A4FE4364799B5BEC93B4CAF6
+B06B9B8C8D164F8FA1FBBA693204064F2C1806C39910910E02ECA8D092558CB8
+33338B359D56483B7B99A1D8137204EC1AE70ED3D75881FC3B00BB9349AD934C
+81A9F285312FDDC77FA923B18B1873D288C2AAF2E6D0AF90BF25A982B843789D
+5662D6A2DD58E065026885601ABED4B09CAAA3116DEE6B430B15BE0A121FC1BB
+FDEA5A501F0798CFFFFEAB5101E707F1A00C8E014A3561FD39972EA9AB108EBB
+960AEA7FF60C301AD6CBFCAA7D35CBF6F8462A4D76C4FBA6F3DF6BB762DF7900
+9F69529AB4EAF96C2866444B257160E8822533A7A1240C83EC18C364F577407B
+4CB314678D2511735308A1660AD94B8B818CEA4A3DC00C5A1C978F8BB4E0491C
+49328F6CDF95BF620AE53056364423841D84418B23C2A447B0CCF8D8633FE2E8
+4A4AC1C6C74627EECDC994059F1BAE9E6B10FA80D767B3FE97BFFAD413DCB0A8
+495039744B48266278194D60422D6E7C74D0DB45ACF217797D0C0678EEB60759
+6231438CFEFB346553A7A447B50807EBB6E885B5A49CA9A350EC4A8C76EDFBB3
+A4DA1C9E3EFA193CDF08553302998F20055C84420A4C5252F764CC4B7A4BEF6A
+A09170EC417B296DD9E2301CD8EABE4A087E648E0525A9FFAF26374C47FDC123
+82F18C9884843864F418ACB08041E7896FDD395225532460A8194A8DB4DBD824
+1C68C6665F85059E365EC0972EC6465E2D8867449907DA6692A021F026F437BD
+D02654BC11381BB6557663E0B0B8C4F2FF69E4776F4EABA69311BC1AF8155F7D
+6D3A418BDC912CC7CF1A4BBC8A1376D8B4DEEB6585416959BCA4AA08D4520C33
+EB054DE53140992D0707210593BE62B3659E3E493C4562C2E99CECA143791DAC
+679896BCDA0699E405957E17DDBD243E65CDD7C9C8629F29A2078658746A7779
+0F75BE24E2DDBB672B95F26366BAF036B3C23BE4132D7362E76D4183A469E0F7
+29174711ECAF4FD9A923E72FE58DF2854C5537E3626317D471D1E8A922C9BBA4
+CE9163A4086AC4A231C2BF35FBC39A5BBCFE41843CAC7D81A054509D31572BE1
+596E0B0B563DF2BF0E57DB4943DAEE35CA26C8433FEE4FC61145C77F65DADE75
+62DA18DFABC7F4194906F53884E62E77D8AB3E099776AB93B2B4D0C98FA44C71
+597202A2643942795EE8CE098FE26F1AF8134F1E75FAE18D563B1FF43A511C9E
+EAFB9EFCF61490A1A4FD2CF354927B72C5EDD5D62B2F3F5006D6130562A13BCB
+1B988A994A8D68B051A5A821CCD5D0F8D9D49FE7CD04EECCFD7A554CCDFFD77E
+27AC4AB5BF9FE40F90EBD066C483796CE1A364E95C5E0CF2154834760522F128
+B2DBD1F4F73347D42635B2875A23597C35A0823CC6F71E49598125411BC9B2C2
+72470D36DD967C947AFB031BFCF770FE50551A134DF8C5D1AB1F09819569A57E
+E23D4E87C0B52CD02B0A2E3FAA7D27A94359E82AF047756BB769BC5950A75207
+78ABD49D174F2F69810AFFA9336A52D6B93B004DCA5CDE58475C0210E0BA1D20
+FD4FFD6838EC56A0922472D4C4EE0CC481574BC30618179E733EA40A48847E14
+A75BE7717CC5DDCB5B0718074EAB6FF07CFFE794D335B3A13EB968EA8FC5B08A
+13B38AD1C2C964E4B07E90B9732C458216B028E07DD593A5B767A2B415EFE7DA
+951FC07800F11C7E2EF9BDD152BC6815B7F32117F49FE08BD79BEB949003512A
+327F3F8FAE1767E7842348BA4373649F1A21DB2C56C081BCF9FA4EA86C8DFF00
+FF45C4F1386CF8C2C4120F3F6019CEBB639F2D272D08C1763A470D4BF6330DC8
+43C069A6333113C3A0C93471486EFE9BFC02B760C7CBB2E9156087D09EE8A178
+5EF50B34994094C3F0015EA2ADB6C920F4302FDEF128711994875551C4E883E2
+DDEFFAAE11F2234AFDD96400BB69C1B4E6EFD75734C586A10A54A98E7D790F28
+DEF7C7DF61FB23BF91AA700AE585EBDE74E215DA49F4ED466F46129022722086
+8884D8E026F35C4BEE7E866DF8E0846D5EC3534069B713FAB02D4B4EE3B44E1B
+656F30D629D40AA1337786C1FDA08EA1217AFA4A6E2498B334DAB5461A70DFBB
+5AA5686C89FFA4EE82D81CE2B28334DC5C032487CCE998616F48150BA1281911
+076E626E5BFCC56A0A4CDC559F878F14C2BD7A5148C1D8CC303FF9EC473354D2
+D4FB0F0F2AD0CF182A28074ED6552E179222570DE0E0D44E8FF4DB36C3AD6487
+C4BA53C8548714A69FCF8E3E5202F09469D7447C6519AE902C1D611A720BAFB5
+59E27A6DBA73624F44B4ABE0988BA3450F82E03521CCE8EDE8BE7EE1223B575A
+DF9A52650E85545525E6F121FF2D1531F156EA9D5594239AEA2CD09EE28ACB15
+A445E11FD1C031188DB61881F474D49425C084489A88A47D681EA68E7FC4B1F9
+DBB552063A02A0EB51125E9B2CC646B940D46FF457415F9565892DEAC030F08B
+E4C10DC38D825C7597394C844CB863CE6C843F67F2E1C42C4EF86AC7FB727BF0
+224B5E91BAD99CC6638AB2C64469A81D8B1789981872ED037B3A34BDF3130137
+80FE80FDA65EFBC11A08B98A1AE595F980B577E22D3CB7FED1D4016F5290ADF5
+47D7D9BAFE39F294582F2C084003E9C83FDB9EBC87C8B477CB8BB359EDD9BBC9
+9368D6605E1468A20909831BF602EFCEC0D5EBA99A2223E5A269275C8B221B3A
+F9226654185929F794E1979ED18B4CD36152F973433AC67BE24B9D953254FBBD
+B644CDF3BF0E29A2C72113DC486E46DED2CE8F8DFA8B0F8478D1F18C9AA8E054
+A31C3DBE84ECEDD85DF6AF9467AC2990ECAA3384FBCA1BBE598AA0D6813C859E
+1520B88BF30ADA910A6AC3068A5B8CFD76B7F0F6F4AF4C32450D628B5320C384
+F23A2B5E8756895584155226A30F8B0437E028978491DCD00E79C0ED58DF261E
+79B9DA17E57AEE03EE92102EAB2D63E69A88EE0B1E2087ED0C0CF6475EBDC3BE
+0324D1FC8F7B90D8D807533E5436F2C2583B9629EC390403437FDAC908557894
+03054A6DD6A3586043A9C8BFD0C7EDE1229DBB9F69F7A5D20F55664D061F6517
+0051C6B3CD7338241FB403F2AF77DAB1A8EBE1650156D40863EC1957372BFDEA
+BA8D0BB1193CC5BEB5A68C8274802E14FFA3ADCEBE19070325B1BDB960CF2988
+C0F5A9BFD843C515ADEC8B8AB02B2891EDD7502D9F28F4E58D8F67D1ACAFD0C3
+3531E0C7D1554344CCF90AC8696E83A3F968252981CAC09653956F4343B99D3D
+4F17CB8BBE4506B354439B70F2024871D16668F9DECD8EDB872BE5E6ACC406F1
+1DF4E3ADF60EFED57D1C426292970199BB663405236C6A907B6891C6190E87F2
+78D9142220FF295C7BF44AF61470798FB8CFBEE6973C69DA1CC24ECB058AA753
+DDBFD92FBB15560EA19D5D92F0005B74F06F0EA5901D231996E0866389DCA433
+E62BE48479687084C1D67BC592E592939F806FA8BF5F0D3F644B1FA6F056DE0D
+51D3F212C6818CB6166317058C2A0C07AE2E324CD90D4EC83CF4819B10CC348C
+6DBABA024A5FCDAE6E288F82DA060BCD16437F07DCA43BF1E5A1B402F16C78FC
+075BEE900B4021A1019C4A5ADC33230047FF11FDE8FB775DDA267040A22B4E5D
+6012F7E72B8BC8DD3A81369A08FB81C6C4873C2147D03D4181D6D8032DD2B610
+9C44CAB50C5BD8F489EBF01C72D4198B66EEA4E976462F8874143640B82AE57C
+A51EDEDE75A9A55D31587C14F8DEFFE69F75EA7B95BF725CE9991FB2F07AF568
+5AFEB39447B728B99BE0502BF28DE1D92B15926BE4E3DA2E7BB44A24836A97C6
+EE3A2080E01DC6514180DAF9C055F4C94929D34F193920020505E62804461630
+9F42C652F9D5681C91BE23DCB0C634247E739135F925EF3D5424767D5F5C5879
+C46F2E32C7B3BE9E90FD6ABE693A6016AB77670129B58B8FE719FA97FE320842
+6488CB85B6BCC0012975D22E75A2E086131DE676AB825A386C086FBE1B65DDDD
+A19F06AA4C1D3EC84751C649F4A62CFDC48A7CF88CFEC68B959C211B60DCB045
+6BFF922FD7349B98E1769394E6CEA4F764AC4B6536AAE4E6BE69099A39A6A33C
+97671C3AB4E7A94DCB829FBA97DFE5F71B1728FC81F826699DFDB0ACE9BC60E0
+6EC15D35EC479F3F53EE4D0398BAC138FED504A84A13B78568E3F9C86BAE8B88
+61830A80F8B994D0D66A8FA3FCD6C5099C29FC285ABF096EF9A3BFDBB522157C
+DCE9F0D6AAFB1F8D7B0A3C573D0C170357175DD56EAF37BAAEF4C92FBE17E26C
+7D2BDAACB9B8F33D09651FBE0D49A8BE66B78D075485BCD38DED5056FCE48A12
+D28E9670EC7CF4E9A277D6ABC2F7AB30BFF290B5452582F372FC9DE6CEA9EC0B
+84328269F14FE7F47620B1042B283C54161AFCF84B46E6B1410587295E4F8958
+C1800F120B59639C85D46D46A4C64309931A8C91F138EB52F779189EF75B9157
+D624045F4B8846856ADF0AD735FC6FA41F7B6C002E9D1EBD92468E86C843AFB7
+4D78E3D54D866029DE5DF865EE3F7313AC358EDA70A792E22F2F806EF86A6B57
+64AAD565C57E64B1A6635B7394B4B5729189319FCAC8529ADE30633B9BDEE0D2
+AF1F8944EFDC7C408FD8FC270822CC01E7BA355C856219B3AC5D05CA37EB0EF1
+6766D62383AEDDA1F7CDAD1DF0172E766BB46C5FCCDDD61BB019D283EDEF312A
+B2DBA38C9BB0928FB93F50E8516AB353BE04403D132805B5AAAA17163AB9C847
+F1B54946B0775FD21325C82E4EC7F2186C54B4396BC4B0B913A59E4444D11B39
+8AB56F2FD5788A9BA45DA5499A50BA74D28707F62086907BF8342E0C753A31A8
+DE293B592F51D74DECA52858CCF76C69BAF2224F640069BEF2604983FB478173
+792D68030D7A6E3FE083AFFE9488D872897ABFC88CA8BFE484A75201D73058D4
+72A8A26A50BA1F2B50CBF98D46DFED0BA057619BF370E435A0400147928D7C06
+28DF2A03527E3BE925D6A664E4640E63BD22D54A038D934B3DB5B500E075B8AB
+06DB5279274E65FF870F1E5106E190AB0FD8849EEE2D605FD4F0DED2C3F86831
+4EECBFAAD8B2A895F08DBA692A8176F9080045519CC6C46B52F0F31DF112AD79
+8E46B9899C5527A011AB63FA443ACE90F09434C295A5D9E6753AF2645407488E
+D29E7711546F87265C130B76B4632242E43962A5C886D4DB6316A2F3420FCAEA
+3055AB5A9E1325EA870CE87F34BB2B3110E4919E1AFEE67606B00B03DD6824F0
+20BA42968B81DAE198C88057438E36056D46C550E3E5E03A99BD4B07E66A2179
+BBC5B3FB06D5D72022C53A3F3A1B759472D5A50D7F7A1F4E31D3F7A30EDC1D45
+4B00AEB5DF680145A123CCA3BBD801CA64B2CBEEA99842720F8DCE432909AE78
+5AD3F29AC69D302C62256CC4D47AC92EE11D2A3E1C666CEA24876491BB167548
+9E3A990252DF8254CB5E7141F57B78FD1FEB38BE135815C6FC86EF81B5994711
+E43083C3234C55DAD97CCCE4FF3F55C5A6C22ADD2C549513A465CFA3D8A9AEB6
+331374DC05A4F496BE33F9263172FB6FE1CCD19EE9515C5155ABECA9492DC743
+BE4142D63FB5E17D55C9FE642F07995502AECD9D555603D15B5BE420A65A6E98
+4F341BA13E44DBBC1DC8CF0D561198A2B40FAF35F7ED5FEB4429BF71F5C88637
+CB114F1377FD3227EDF592733EC68F4EFEAB14FE7C26DA7031075E04289FA6DC
+8A79F81E4E18CAE8380CC585E7DA3DCDA3FCB53929AA8D772D53FC6D821EBB14
+EB472017FB56CE9410FEEFF14EA69C188993922DAFEC805F4C8028537A9D6365
+AE1A6BEF37CE8E02B995C41382984802AD3D12AA9FAA36837F9F9F8F60D16B81
+474238F136F442CA9B14620F83E4046E41EB0FD02BD04DA7863DF26624B5489A
+B8BA35B0B3A8D128FA10E01DC9B622C26CC57CA79CCDEEB7E174698EFDCC0CBE
+879AE1434B3EC5AF48E6C2EC5652DEFE0ECD7415FA46BC0C80FCC57CC808B3DE
+CBE4CC7B62AD3B092487F7A23C38A2D9102DEBB1CF4C1EE7FEDE1E8BBCDF7F73
+54CAB1E591F9B3B3159D879A9492394B32F2CC43EE7EBA6E293AF12D7FC4ADF4
+DAF8F2F48A777E927A915DE1FD9125B52D406BACB0BEA149F6F6D79D92D06413
+5D68461A772D531F2E76D1947D2ED5BFFCD758E062B5435BFD180F7E3734D5DD
+ABD86A1C2BA643955A36C482BEBAC608F588C43E6EA7EA2AE01D0346D28F50CD
+BA8F9FD23674AB19A2B879E0DD19029EAC5D74D16B186CF4BE3382E74E361427
+536A00347E536701808C1D31A617D1F9269110B76A0D59C7B84D98C8FE308733
+C9497B807A77D244FEE03ED7FB5EB4D6ABB74A7129F23AF628BC01BEC6C43ED2
+D62F4E2133006FDB94D33CD31F9FFE57C8C9E31DC6D7A81A2C6ABF1D971EE222
+96A4D79F7232190EB796A43ECEB88F1C64A88A10C3AE8E98711EFDF984BF270B
+55C5B9082D54DA7D32B168CE573597DC5A453D76953DBDDDBC1798F8A645AEB3
+78B6B5BAF60C9AFA9D5F818740EDAA977EBEA0F68E531550E607E6FCB04F3E22
+BC9D6440E1E153C8D780213DAB08CF8CFEB03018942AF980642745D711C7DB1D
+BEFD825627798897ED8185D80234B6C087FBB602ADB1263C2A2A0F59AFCA7B09
+EA4ED3BCF936C2DAEA9C8DDAA90130C24AD1A1BA47711CC760FF72EB3F27C165
+CA1FDCF1250C6CA4A788AAEEE08902AB4EB03C6EDF281CA2F5B074C859DE3963
+27F7CFC53CC91C80F779ABB25F7A6601453DF5606B72EC562F615A92C1DCED58
+3911BE7784B6E8B17F8993E4D5693A327F9C289701F39ADCF583BB4EFDE1F835
+1A59BBC2E6B73CF422D877B0B423E4E8FD116F5C66A4BEB706A3D42E7EFBB5E5
+E73CD03D7A91719337CC8E13F9D8DA255185FBE3F4FB6DBE8EA90AF036A09BE3
+5047B59BC18C1C3658ACE003B6535E42043E4D7E6D79E0B48B3D0DCA36C046D1
+D5ACE0B6F91CB78BCBD144F3FAA3D9D711C9D11EC30B6CCDBF43CD490E9AC229
+9ED2CFAC4F53927040CC8FD26004450889A1167FA34247B7C283A46E4C0A8C20
+AB43314A34EF0BC02C5558746D35F2315624FB9D4A8ED13E3D1A8B80B872798E
+CCB9775F985E31E8228B03949B4E35DCF7A41C834E53CE3C163EEECE81A8278C
+FEA3A9E3264627D33738170C12F4EB23EF8F00811723FA4FE56A0EFE8ED5EBE4
+90455B690EAE1E8F1092C1AAC07FC418A6790C2DDA6DF739B9B586B68263EB63
+718EAD2B11037C5D26FF31FB2E56AB82773921B00EF07DECAEE2A8FD71AB232C
+86865012F1FCC80CBDC4B0E881819601CE2FC5AC36875F2FB5C088436BB11159
+813020F0433EDF6D96FD162F5E3241F88BA7025F2B010208DD1DF737FFF1185B
+812864C3049CE325E06610404C8DE9322187DAA7FD90FFDF2DF3C86D94E8E792
+377C1C1F10FDC78E1FDEAF718A2857C4922FA300C8D3FAC136BA2957C675FBDD
+21E3A9E29C797142BA6D30FABB0D5E97AABB49D113A55C4838B253AB8D7443E7
+15596B3BDF01C88C17135A74AF78551CEB6B0041BD17ECAF89321E6948E1C531
+B227A1F071FC3558501BFFC842A4F8B80C14D9213E0633485A66F899BCB473D7
+3C72329610575B6279C781714761468C785E426DC9393564979B1D6A6D55AE9B
+4954010208883EC964F35E8363129682AAFA2D40E1ED08A4A1DF27F3DB5474E2
+92B917B45D9473AC94EE40662DF06AC9D004541B6F88DF5AA4A36756620CBE83
+1254ED1C3C9CA39B09E0D4148DA552B00FC60FF68E7159F556998EB8A66C8EC3
+3B7842ACEE888BCBD1FA183BAB95B06B245ACEA49F8CC51A2EB01053E99E9A87
+A5198C2FC26E270961FFF61A093A084594E6C0298CF96B251C5F8395ACDA26FC
+461E6DB774F6220F8FA04C68519E19CF69EFA73E9A1BDFFE833B228DC19571BA
+34B7AC21EB2BF8B1876BD11E128F002AC9AD6A9785CBBFE2D5FBAC307BE7CE5B
+DDA7C12820028FBDBEF1343638CE166E43B95E6518A83828AA3C3628779FB2E4
+CE32DED584715FD18C95D38FA85772DC8650EFC42F980A1ADC012ACD93B7E1E5
+FA6453179ADC6F17C94FEA1F4CC2EF6A2A975C687ED81DEB7111F0897742B373
+30720766409C534C5E0A42D7221337FF3C4C59BBD239518F3976DC55FDBB8C1C
+8DB9CB4B05B1D9AFBAF0FA1D82B1564AD7FC92B6CB3582F7DA309403EB78916B
+BFDC6F918E26A39755E5AD6394D985C92F7927FB1287FAFF2F60248236F918DC
+2E8557C6805B01090A037E8D5C529E2D70976A9CBF3785F4BAFAF9923DB40756
+7B6CE8EE83559893E3930790E5917EC3421FEB042C0CBF6CE74F16C44FA08025
+82EDA0833C0486CDA66ACB450094BB65F54C83829B47DAAAC9E4CF115FC275C8
+6BE583008180F2E2C9B003712ECE32333199BBF9772A471EADE59355FF264DD7
+ADFD42FECCD00892FB545DFE555AAA4B273B82BD2740CB8C9ACD144DEEA94188
+D1AFEDFA1FC63557F9E527C00AE7D14762FEC2814487CB60E406F8D4A47365B1
+F7B0E0A56CEF011CC11345674611EBFB5A7C587C34F786498FEE4F0F999AF42F
+D955CF2ECC5B64BB1C100310DE5B6C7D106A80FA4ACE0184A6E18FAC544EEDCF
+307334E1C2A0CB6E488B21DA3BDDC5B593D5ABD6006D1E2BB56336EA88D56DAA
+62DAFDDC379B06EF80E9F3661C6B7AA6787ADD06155F3DBCABAB6BA3A46C9047
+5D295774447BC007D5423B9840E2ABACB5B811B30ABFF547A8A6E2C18A92DEF5
+D30890D49388E80E6EC7626FE3236AABBF64B21E5525FFB7C802511129EBFAD3
+D1E19814500A465DA92054F93FF77864698288510AB599237D0DBE1EECF81C46
+F706515DF10A1D0FB06939473BC72429A42CE6E15BA2C97720756D80DDDC171E
+7E8202D385C2E5B4A5A011933CE920E98A09527DDBF49FB4DAF2E736B1E42F57
+354C91CAACB68BEE8FDD10F4DECF25ABA4EFFC4588DFDB9E98640737C015EA04
+A33D5AAAF9AC4A7D288BC9D4A8AAB9B852516E215DF7614B10BEF003EE1D0572
+E4654DBA4D71959D403B936339D41C381FC1A206BFA6505DF3082D9FF767EF67
+437E8C2A14A8B6F0FB98C80DCC42A30C57C8AC3FE83570A1B4AB404374B85F45
+A1056E389A7148CAF714CF6DC26A04E3DE8E2E7FD26F6CDE3E836AE65E593A9D
+3FA7A24A32E3E99A152009C8713FF8960FC93A2E49B8F442B81A90F98B99E140
+5F0E0253DE8ACE69F1248040510DEAEE069307FBD02B821D1DAEADE6C41111E8
+37A80AB702B8D79977DD73429695C13DF81ED3B562FF4C168AE03ECD24909A41
+22C579987CBB22700D1D34BB16E5D0B4BEDB4660D34EF5CF0A4FE507198EE14D
+9FAF7C97CF769EA9159E1D8210B063141913DD402BAFD515CD746A7CBC061A74
+CD6D6DF78AA722FF543C5379A1AF5102B75C06F73E075BD8531353892E1733D5
+8143315C0C780BBB21D6954119C0AB1D4C89EA67C0AFDD4607AF07D509F481A9
+9045776F08003CB429316307E66E1F9490E8547FE0336BDD8B070290558E0DCE
+DB08FCF371A8A9FE905E9C3BA4CBD4F12BB2F512838D395BBCAB1488C58122C0
+CD6D3634C0F6E193E2F2E8C632BB9185B20D94503E02244938D4400F0DD8FB81
+3AB0CBCF32E462A223F9680A14AC8876917ADEDCC9B181D584AA307CFF3B66B6
+F59FC840A9E8D1BE101AA1DE41934C22A1017A8AF69D257433C2D2C5A0474F9D
+362A669B4044B3990BF83E8906C5B7E2B45D688CF12CC1FF38F2EA47743676CB
+55FCD3C6261C6F5AF002869128882E39E089A6FA108195A8B86CB07913FFFA6F
+6D8F8D5C9E897D63C174825286953B9DCB09B8475D0675E09C1D26286107E89C
+C75F92D14002B1289A5E11F059F28FA27DF23FF395EEDFD5F22374FF67F0B60E
+81D249898A228A6A89141B23918E977BA79C5F5E6CE84FD35F51B136D81428E4
+E4D205612F6DEEC1CE6AE571B30A33DE004A8F096656A3BFAF8BAE8A2C73AA53
+D7984D6777540082F3674304D2C3F17775BDF86A27563CC2BF95F190DB3E28E9
+FBD0716C0F1B0D56A96E2E870882F03A3E160621FB469355859954858C9CC2AB
+06EA8F87EA163B9ABC176D704D3C17A37508864381659070B071B80C79D6D60C
+7858A32F5DE87B1F818E78048CE81E229FD7BD91286ECD773147F94E7A184450
+D1060F0FBC5A8DB06BB4009B3F5F50EFEECEF8FE970E3FBFEB5ADEDE9EAC6A49
+AECCEB5378A9CE274BC7F25D03CF477C2054D313FD988A4D913D20ED3981CE47
+8674501E487FEFE5DD91CB0E5ED24BE1D2D45C88DBE1378B11F6B7076FE56BF4
+8E8925E65FBF23330B9C4A943CD96EEC06A6073AED304CDF520CD2AC1CFFAC7A
+6B8D8FFB7327834C9DADF578F250A51BE64D27A2B65A16DD0204635560B47075
+3A054F7159EE483CA06345D3D55EFACD47AD32A9D7D7404ED0CB742A3AB8C47C
+2C5CC71EA3E1405D6E114DD53D85C2350D46A8E4BDFD1667C65A8152D9F3331D
+6235F40AE36EDB507325E21496725F3351C239207C0C4BBAEE2DC7D2797B8818
+BEBAFCA4FEDBBBBBF3FDB633A0C21A8BBA856D4A3119394FB00AD092E314558B
+99CD5B138D4A42BB7B621DFCC2A2E2AD262479E878D8F26195A643BA0D13F9C9
+FCF3B6BE5774DE6F4564FB82BA3B2B9BA29A5F406F1A135D46DB10C80CA11E1C
+39C9A74A18D8EEE86C85556F8B9203E00DE0B1A164134E48FCE7F37AAB98A79B
+EAD809EA81192ADD3D3C6B35E521AC99E190262E5454C7170B081CB8AE338D09
+D489BB694D228CE9C05DA95297BF106A3B71A99A5F199F122971F5C4B0B9C53A
+4344FD111B92AF456697E0B85142B71FA56802C392C886A408558A297EC3C717
+FB803CA1002361034D40420699FFE3C149800137EBA3AD99AAAD74B471038675
+8B073F692D278E0A088D3F51360C2C79A83FCDABE9963A4D636631310E7C6D35
+EF02828CD45CEBF9892C2761D934E07AF32BE74852C13FE63BD3DFF3619CEFA1
+25F5FAC01306FD99A573F0F5F29116967FFA22C9236EE8EB052488C4CC204855
+EEDB80B30838AEF66DD960389684231FAAB83750575E4C9BAE860D9B0F838927
+791AE22921BAF254FE561771B7A9164362D6BD462A82763F6D19737ADA1C2B92
+BD72443D7521795F9D3702F83B04BCF992667CA255A3AA539CB71F25F2D0ED57
+9E0B180D1C199211FBC17EE282E7CA9E078593E6340BA651AB949482A0760790
+E4C3F1446653CFF964B9A3142FF4FBE8C75CFBAEFFEEE1810D38033CBDA2FE9F
+B42BBD97740EF0C118C7954FBE81FDDDC74608D036A3BBB75EEED4E1A4A56381
+0F57C993C4651E4753A27684D170EBC495D09202AC0CDC5F10267EF26EF4E7D0
+908F4524C91AD27F43737253BF0617559F2EB99EB26643D8C28B61F8968CEE7A
+A79A818887ED9BC3AECE4A35AB15752A368D09594F93B7A741282DB5C6E42144
+EAD79AADE23733A43500563C3AD34E0421D1E3B4642EC1D70F0054E3DB6CC218
+FF930B11B1CCC3E4C90BC523D4635161C89CD9FF8F2C4F6E4127ABF479914610
+4D95589775902AE3993E1CE3D4868A1055BFF961CCB244AE25C76C4CE556B8AF
+98129765EA10B35FFF3D24DE1CA68BA55E133084CD2562832630E302C3823EB2
+5D7293D0C760EC1788BA6BC9ADB7AF6DA83C951E0A23AD98EFAD64AD387F7764
+21320EAA8DD04EFC4C2BC011185DAC3DC1FEF1461F3F9ED515E2240433D855E2
+0229E1D5269092D0FF790539D2946A608E82E1FCA5E3A1254B27AA134C300FFE
+C7C724824AE8B8436577129608078274BB69FB6A026D0CA48B97314F596EB375
+390574158057D3E1C3EA4AC61BEC73F81C706A6C7A9B42EEACD6A4B5C4E69FD2
+C68AB11CF02CE3D9B7148BAEC69F92FD7DAF6C9D772BE60AD4579BCE18396E4B
+60EED65E6E2E62B283F135675C188F58C831B3A7ADCACACD39871EF8905B3264
+567AEEE25FB31D64C6596D60597315F1AD8F74E5577E6C966F8F65B001850D1F
+39F0234F0478F6DB136F17F20262CC072B25202BCC8A67EECB03A2834136EE5E
+8FDF55397F3572922DF82D25376DA73083419420003E99A020198ED0ECA44A72
+DCFF31392F59E14720BA027A5A5E81B3C32BE7DBEE039CEA50AFD5CF9CB9080B
+3952949A3165C5AE1EF9D8C76E0C901DF5013469D55C8AFE1554A74D6C565533
+FD00D77FAA0311910C9C191ECBE1A0FE30A4FCDC3909D4F6322DE2DE90865099
+ABAA1A087DE9B4642DB649ECA28D40631EBA0B3902EA6D70F9260EA9DACBCE35
+8EFFA26B2E8BF4567406788443950D8A71339F595C83E28111FC90181AF60EC8
+9A7EDDE1989A2678B8C570F5D0BC178C4018626B9AC851604F03C98469EFDFCB
+BC34589B59973E918756A2C1BB7D1811BEAA17D193DEA92EB273D50AE5C0FC30
+661B330B083311E5D971D70DE46E2239532FAC9A6D8FD913E6DD03F42ED6148C
+4F04E6D136D41C24BD9B973109A9B63233E51176EE64D247DE1C5CBB43F568BC
+DBD5A6AEDFB68E5A0C8DC465E9949A96665AB78F41132F96F3680B5A9A79DC44
+828FBDA04368F277C40F629961EAA9F3B253276EE252478A9F409C2FB6447C65
+37AB9FC9A216970D7BF6912FAFC92BA0C000A58950291FB3E47F0DFD493EC7CC
+A99555CACEB7EC87F4250AB92E7136500138087A19053E9152B6F007B8D3DE8C
+96224FF8D464BD3289C08AD1E05B9D063375F38FD42CE97ADAC4E5B83B8A88D2
+B2634B95A0DC0AE6A407E62D153BFC434B42680FD0F62F5FCF0818182F182D1D
+6B9EBD47149F8506CF38BA61D8AE460A8B660F40DEFBC9243154E5683EA8D574
+8D48276FE5128F972D96E42D89E374F7D8C72E70F84F028263507BC96F6B2B92
+EF4B992CA46361BA3EDB888A6E5C57688198EF10A616F7DCCA55B4E1645FFBEA
+C2201D5503101C400B147CA23A805AA95FF059120C677C32ADC486DCA6E775EC
+23BB704624D3755E09505C395CC3AB83D68F10E2D6E1497BC179F3CA82A3DFC2
+38275D10D3253264BA9C32DA47C0088660037C7A789C1DAF75D0476BA9ED5B62
+CD30BA0E268DF3537F8298BDDCA16B1C970C2863B21CD839FF6B713438447A4C
+C58C1F0ECE39E126AAC2353E31B6FB808253501CF26AA3AC48433D4CE5A946BF
+10347C814A195929213655345791FAEB7986B1DD4F2B0C9E7116B11A4F1157CB
+933B48B488B7DFE700423AD4FAA7E26F003B87B6255BB607A3A639830D68D663
+A3350CDD992B528E3D2176DAF79AC03F6455B1BD626ED15299042B46F03BB46B
+992109329C6F67F1CD92A620FB4D806558D6CFDD75DE4F7D6C558CD5325302BF
+ABBF40001F90CC940511F63F32F112EB958944E37A603642C0CDFC7941D9EC65
+F1F5B2805EC17A6662FABEAC3F1A7CE8A4958D64FCD57759F5CA294236B5834B
+0071972DBCFAE0D89A1BA76FA1EEF2C8ACB12E45C8D8939B3EF1DA3970ECD2A3
+30AE415757A89E44CED997FFF9F6378FDB532ADAFB25872A690137609D91405F
+4FDA7B432D432325F1467A7C85363A9E2825F86D5B9F9523E53FC5B58D82CB28
+90D43D172B2CBABDA71E5B83928A6271468C197108584BE45647AF5C9BD930E4
+18E321AE20B3D28980B1CA53F8B2696043BCC4C925F218B0AFF8E8C2BC1B85A9
+134BD28FC51E5F4E803761720601C5D9D87921116C342D832BB14EFA08032E5D
+7C0C4F14F118883DBB1CA0313B6658E3BB5A7ABBA4970CAB64E66515031BEEA7
+F0311CD7DF8CCADCB38103DBB1D60CE59FEF567B2755D0A65100C8F8EA622025
+4AFEC5D179796C4F87808A76B3F420A228544CC12427AE7A5E2FB6CD76D4668D
+BD5A22FF8161EF3FB20EE9FE64EFC4D1E466DEF81D20A395B020BDB7358E80D0
+6CCBBB8725B9AB973B060770E4CB902F429D75295D1E5ADA0BDC01D0DA7A4ED2
+A21346CC735F3E6662B87BCDED41C39EB2174C5ABD9C89A4A6554B3523E08BAD
+F208FFE1095E6641C548DC0B7116851695AE8813E691347526DA61EC59DB43E1
+03BD503968825F7EA207E22EA04656780C15E1E9D0A00CF8CEEC4D3FD48A4E93
+7E82A2D0F952F5ED616618739ADDA48480DA4665526260E4269F135C89C2F28C
+28B435A1A40C924B79934D6CC536A58D2F102CB46E4C3F6F5390008A7C7B5E28
+4044E385A5D6FBE641B6FB074C4E15DB9D25152E503EB7DB52F45913FBD962C4
+550310BC3592CF1C56A7E19A73261219812CA9A818856901E9F0FC46FA53FD67
+20A7AF35375DC845C8A9BC82F46C061F46233CE3F963C6AC49CCE0936A1813CC
+F7904CBE756A07106AC3D9B58C28EB405FE50A12710C7FA7B4F6900E163125DC
+43672E2C565C6959C412F7CC333F49E0FF5B1AE666E0770255C43E1779A67D7A
+BD794057140D8D1478B7B3C43C84C2C2E56DCA12A1A536F80B16BF9C5244FFB6
+906F2729E0D6C3A6AE9A837CF39F81668CE7B299F4EC9825892A961935E4C81D
+7A9FE5D9431283C53770E41DB77A70500A9B21D63B2F073D75D8E11579FF7C63
+3D1BD1D11EA3C49A594D1D83A733ADB8D887AABCB81C32E3913FC4B2DD1DFF11
+10C193CD5D5D5FDC8080F9B99C9B29A86ACFD94EAC9E052790D6A46E5A5E946F
+6AB9541056CC23323C09CBA556F1B0F28BA2C30E039B3552DDBAC17B9311BF1F
+648D3527E8650B3FC89CF81256E9A4A9054D9F1A9839BF7E0B875D25EAC8AFA8
+2B5663DAD7CC7DED3206BF5957291DF837535DB23BA63F9F7ACA7141E1490A68
+327E35FB7888C160C2D47BC4A7CD84194FF52646DF43AC83A51489481CBA4D20
+1E5094E7AC3EE66A5828BF1D87A530D7786577F164AC3D5C0D624FC6CF1DDFFF
+C2
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMSL10
+%!PS-AdobeFont-1.1: CMSL10 1.0
+%%CreationDate: 1991 Aug 20 16:40:20
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.0) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMSL10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle -9.46 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMSL10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+readonly def
+/FontBBox{-62 -250 1123 750}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE
+3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B
+532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470
+B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B
+986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE
+D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958
+9429B9D40924DC059325D9D4CC0344F3F997A99E6CC0676735EBCD685AAC9142
+08DAFEC78BB41AFC2F1C219910BDF41D6279284EF600B69776CA15BC8A34347C
+30783C52AFA60FBE3E353E2AE354CF87B558776A22C776C7A0B5AB5CE1F941EF
+C2D9CAC37294BF407A671F10E4743BF842143F4F7DFEE643BA3BBD8BB9E3F24A
+BCCF7F0ADF8BA500620C81033EAE8C4EF2C1DEF13AC575F1B3BBB66F093D3B78
+5412B82B67FFA087AF57182B2230F9F2137180CA58A7D9B2C822FF04BE6CD01D
+43B2CA7058C7B953F6D9B5D6E91ECBAA5CDE1159B0E59C83DBAD96D6C8C8BAB1
+374EF652D10C0F3EE7104472C98DD3572AAF2D45A70BF7061447E21EE3C3BF23
+DF39C2D1B35B42CD5297BEBE6BC94F7C9DC6E61EC67E4F677256FED9064BD3E4
+B51A71B1D27CA4E5AA9E1D8080E6DAB5310711EEF87C40859FA935B19524AE83
+63B163FA8397BDFF443227FEDF7DB27DC35D89FB1C5E435DA0619A5C88AFC73B
+89A2DF5E767C5B536BC7167A840A0C32BD57A14DE69A7D0D819AC36FF32F908A
+5070F32983BB007437E3500799DF5E0AD3710A4C0000F0098D5BE99F2EB9C1C2
+C444FD9552D0DCA098A94B3BF176F511CEE13DB7EFFAED7C47B5ADCF8D4700F5
+7A5FD1B49560969BF5C44F3749370663A04776F749DDD7B50674D93254426C4B
+EFE264BEE7810EC93784B7C01A7F29EFD92547E13A2C7851A2E709FBD5B87850
+4A44F08F56A542DBE072D2FBC58D9E6468E1AB858DC35240E30D31C7AC13D6C5
+7D2BB634BEE96FA0E10F842B11A789F72A333DD6DDCB1BC23227EBC406E50B40
+30AF0C48E6359AB0C46898CDAF1118E46BFF8B00F54EACBC2AC262AB898C42B9
+2E080C10DE923C1F7BD11CA700DA95F7E94C4C77EB24EFB7D5DD39CF43896343
+AD32237117AD4B4C24EF2B9AAB4228720C9F9EDA61ECC327D71641E9657DB045
+3E35C6ED9AFD4B88FBBC287F2B08E20CD064866D01062364E81E3594D85A3216
+396597A1DFC0BE35873C5BF3B12F115AE64354DE66EACD29A904A98FB23A530A
+64D6DBD4198DF302D6EC7460A65E40609374E2031E0A3E8A3CB33C9823F1CEDA
+6857069DCB4384BD963FE143AB8C46C2A6953B5EE8CA955E084517BDEB8A6EAE
+7004A47347A65802F42FB1C3E2BCDFEED75859F600C521207B1F12360D8B5B5E
+BCDDD9A8B43BE2886777EAB5A7006AB74FE08677A20579E5E0B6B949759F8346
+347F3AF2C105AF9A10341270B338AB4FDC2288B79D98A54F8457205DF24ED632
+B28F3773A7D9B85113CB50A9C472C537EC2F2AEC0243B6211664D78DE60EB3C9
+717285D76DD931E6BFC44864BFC7F99BFDB8A2954BF0C5712F21B490CD7E416F
+12EBFE13341161A9053FF78435759B60B0F54888463C4B456CBAC7490988317F
+17CCF703B1298BFF7B8F1002A86171BD2B7E9D8C4E20D426C132E7A9A1020653
+B82A9B932ADB1C912AB90997600AF5D56DBCE887D79EB994466A78D9040C2034
+1E537DA15822B32E17DA808628519B5D964B961125D6CE8158FD72D84EC1021C
+68FB5F28CCC9FC14CA321D290B9A2F8A9196B06F787DC618E6C1957AE2DD8C3F
+C2D2BE2A46B8A2CB9BA13255AA74ECFAAB942328B176D6E13C3810CF28B976BA
+58E89F16B00B2BE618A07955CC9C46A95F5A07FB240D95452CE799C8709D45A1
+85994D7BAB6792B58694594B881C240F3C36129EFBFA4AC5B5074E390AB2E39F
+CE9E366EA4E95A5DFF8CA2E144E2F0050F512414FBDA7A7EA24D2804D22FAA04
+C2261EE07DD605953453B94243250098753EC7FAF186A2BB5FD481DE92D3A6B1
+E03DCF5C2E2EB80A30D0569ED52550B5ACB2BBF67A86D4F4E65D868B2178AC94
+14C344582F4ADB60E79ED161C0B7DB7CC6FF8C391FC1B2A290B33DEAB127C200
+C309335A5601E10DA4BE03730AF8297EF872B08C54110804CE0FAD959F416B9D
+5E13E390C820F540C109F6D0F71AF41B0587CA7450810019F8CAEC40CFC3C617
+5D0163AAAF368C1DDC966CAE0BC65A31083D01CA513CAA2A5D3FDD301A557CAD
+148344C2463CD950F033DF4686BC452D6206760EDB2EB00026F5318440AC8795
+D1F9C0595F392BC030B70806C8FEE3DE6C140547CA3CAE9B4B3F1663CFDB5519
+6F2790055E57B004E48FDCEC080F8C8417FCB849E34D5C85CDE82D435089956A
+C0F3E924EB2C4328CBFDA7D115BDBC58716D98B4F49A6F2E841AD8B31F2148D1
+34A68D8E23ED7AF5D891A520ADE49714ACD727EE708BCB6668939DCE322AF08E
+53F071980E0077FC9BA5A10B3BF911664F61327233022B59E72F38B2A64E90AA
+C858FEFC4476C42C6398128D10F889CB7E0B96E4D13EFE60CD99998388CCB554
+C7561FCCE0BC98152D9E4FB1D7AB69A5BBB87CE684CB2795F90A682210E75F9A
+539CADFF715672E0122236E42A8F54DD833D4F99E672B390CB63849D911943E4
+CB0C6C9693751380E7ED446DADB9C7CD98E042FEA6E76E473AB981D8A5CED403
+9A06577BF4960204938151DACE2CB21BA653A580DC8E57500B172839CBDE3751
+8A48345DD78508B4D5B35083973E026272994D3D58C6BC0F505BFCF708388ECA
+514F0DB510FF93CF4673EF0A19A89B0E08F3235BABE22638A843CD1B92DC72F6
+7EF613DCA9053AE8177BF3650C44CCCE8F1B7CCE6EE269F54F8857B5576BA1D7
+8403538A00B1675276C38CD38CBC7B73906FAA9A34DE35A9F03CE84A0E60B499
+CFBA23F6C2EB6580B07EF12D68446359FF50E039E0AC2186499E9B589B6DD483
+0D432890F26241863A182314369ABE41338B2883A7CCA07439FE96465A5DE153
+490D3DDFEC94DFE203CA50520AB3553F6FF5630404C2A2BCA0E65935210CFDDD
+433842A96E7646942824D43D0F9F5DDA9195850737EDE2D65B769292D5427023
+AEB225160606F8D821F08AB9B33E8C30D492E1C57A3259B1CFC1C56C5747EFE4
+792D365BD95A08758383C496F6D2729EDD5297E8C1571C2711F65FD6D6BA0126
+BCC6FCADF50C3075B9339D9194E79A4377D728EFD1E597635425407FD3BF22E1
+062866AC4580ED0DCE3329BD884F5E022385FB0D020CAD3ACBB9B0F696C4C911
+8C26C714194A606A95441101F427247208E296212B4FDF1E68CD054122C64CD6
+C0CD1EE077F2630FC30DA75EA8C3DEB388418C004557EBE97A136308B2E8F079
+2A225D5684449EC17A1A288265CDC0A0FAE05DF0F03AC4C61B13C2AF9C5AEB97
+4E63BB904FC564A28601A9F79E43155F3560A67B2B49EBDB1399962A2C0F55ED
+73FC547D024FE86F65FE2AB8EE5B65377F9458077B0C6D31BE033B258B87E1DE
+2C9646601F49B17A69341E8064F6DF881046488C2FA69AA0F9BD635057256127
+C4DC77D9D71C895D3040F9E6EF7653BE1F904978749D5F98F531C5564FE02F4D
+000DB6DF12C17EB6B9C13726B0DD1D8A23F5CA8B984A350DE453F808963140E4
+3248089231E94E9B298DC62B46610176ECF3B8A1C77064CA3E90480C27FB8B01
+5E06A2CC70485242DE5CAD12DBE8037433E39E978DCA6D59923C557FDEBCBAFA
+48B435C528845F0B7BEED2323CB3622C19816F2AAD6BC7027E36BE571A1C8FF9
+F2090A806CCA9B4A869E5E15EB363C608EDFD82C88A11E6644978790A0AD0647
+A786BDC3B6F0531B1D5F01AD551C3C759EFAF72E146CC7BB125ACD1DD6197DC5
+2B3AAA053519F55E433569CEECBA8009C20B4AAFDE97B8EA362C8639ADB0F771
+0D7AFD709E4E16C1CCAC746A2307505A462F77B1B977F4EF3BC32CD87968D463
+C7B02975D3269F1E3AB3CB1565CBE061F928AB2943B43408891B9D3C6FF864B8
+FD69D33E79951101FACE7C635F8B2BD3F45C27F4E2F119C969F552EC2C5D047D
+EC3D0C212AA56F51240DB8861DF7398C3897B8DD8F1B2400FB49197AED7803AA
+FC07426EF806A7CB2DD05B8978996754E72BD2A3078E578191221EC40C71F050
+79257CA1E7B0EAACB2C0DEEF23C4B2BCA93AF1BB58D94BCA90BC12A50FF9FC32
+253C51DC821ED1FA42318788342A8C1812EB45E1A1AA66D9CCFE0D7A107638CD
+EFB007C6A6BE3D58B81AA688D787F7D0553677EFE62A3E59C2874A88D5719E8F
+9F1E12B507D39FF42589C1475DC5F0974B423DB8DBCBA2C04075518EF5CD747D
+C582F0DEFE4F674617DE189EF2030FB38194C08D3FF6D0CC1969494D86A74342
+337F5A3EAB685175FCF927B27E00F69A3F0B5B65E6FCB9C310ABBD731CA8D647
+F87D8B2BAC0D46E4CB24290D064B536CC0FEE46BE2E0982DC832F17A8668A78D
+313F9943C5CE466123BC3B80122B69278A3B61FD4C5ACEFFA8B62EB6A1DA2AEC
+7A7FB0D4B1A5D3B59235430FA156F45CA682AD86F3FF33D94C0867AD1E1D7AD8
+7439A4E3ABE919C6E3DE041175E0E3A1F2A878CF7144ADD7091DC52E5BE98830
+0AB8869740D57C6013C92CF23FE175EBD5C26330CA8B83F1B3EA50228085651E
+64F36D1E8B1FEC84FE96CD2BC8AF45198C9CD8388301B1BAE9926BD8A014CEAC
+3F8D5AA5C6DD2232A3F2FEB58E86F2835FB055ABA8567A3E53D0D7DD404E0D99
+7F2D19678CF28BBC35AFDD80DA0F1F47060CBCEA4EC5358FA8B000C570169AA7
+6718FF6DD3EA7622AB8725FD764C2EC14E2DCDA0548EB94981931C0A2FBFE083
+37D342A73ADF7BD3282E25390EA45D5AE7052C058AD6780ED90AA5007669AD9D
+839B78DBC708D312C5E109E7756AE6D7D6BB2191FE1B6EC56B0721E6A53C8CB1
+6519FB1F37A8F38EC33E4A5766672E4785475A0F8431CEE6D66FDFA4680BCB28
+4EFAAC29A37BC21D9B884F508738D5F0225ABCDF34CEBD4D173321E328F877E8
+590DA7057B8EC485BC92A14DFAA31A63A6244D1AF09F29F0E36C6F9CFF260EED
+10CC0D2730237B4C7D32BFDD509B6E3502A463284271A3991982887CF56DD662
+0654E725CE1642E0816092D6EA59CB60244DE99E733C2C8E990EF76B70B20B00
+734092F47103AE3ADD001D19F588546D8F9E8405290CA23BB3D3FA81F034EE89
+EEC731F922E6F28BBF12798A0A4D6856DC7D1987829310C32CB81B5F85B92FA4
+3DBA34BD1950E4E4ADD08B54F12F923A36195790A7D91447E91C75DB1D17F351
+D2FE11A9158534ADF9D06E2CA4BC2F11E9914AE70550D52C5667DE9DCDDEEF24
+E57C9F372DE435F3FFBB3BD498BD0B56B1B53534CE9F74BDF113E06268AA1050
+CC6D925F17CE2F7AF499C5DA843EFE205E640079F47F5B5BA0F8FA27FB30DBBC
+3D3F95DE3D72DA6E726F7D599AB903EA90506732D051B5541C5952D522F354EB
+F8B4E8C34660F9A53F9299DABF9C0CB5EE6F0685E522042814F58A0C5B54E0CE
+58BB142FF89520E7DCD0321598AEEBB393008EFC4774E2B3BAA16C714BA68DE0
+C8814BDE1B37E87B1F7D4E8177A23C793F8D3F6CBC6833848CCC0885D01F20C2
+479E8F80CD07715EDB2BA7139837DB3E090F2FF71A66016E6805C6CACB18BA97
+035C6F33D8CB3CEB57D55B07AB10FBD469B14933299737F2535C97643662868E
+41B46920C640A039A4DCE141371BCA56E66A2A6C0FF74A4CF52A851291B7B674
+8B7B676307320B1DE482A28741FE51E8FCCCB79DF636DDD2CCD73F2B46C29C2B
+6B32C6C58AD847A41486323E5B75AB58BCF81FAB2E7D794191D6C66F1DD1F742
+6B0D0356D9460AE3287B98D3613E576238C10B6D18D4FC4FF25ED3A7A85EEDD7
+5FACEAB91FB2F0E6ABB6499AE02C3B1E6D2032BDF5E1ACC575620FD8199058DD
+499B758C1B5C0B69F930F3A4C73E2E363168FD7E03352DBAA3FAEB32B29C34EB
+7DB8B049FE0C20AE7B36DA2F783F8AF72CFBDFC698CEC9362FB188DE13CF08B4
+830993A117A1F06996B000787DDFBEDA484266BF6956FB0B27CF5613CF11DF1C
+2BB3677E8CD75742BE2DF91F646817E1EC1F60EE24AC8B116CA297F57CF6317D
+0F098301800B7664C0C19D12BC6C85688F105D3C91F18C6166EB9E586980FD40
+1928B4190E3DFCFB858DCFB0B8A536D14B9AF13BA62BD71969E9141ADEEDAB35
+1DA0931BF97D7749C4F93577D4DFFE52B373D4E88D85BE4F9E87B858AB32C26F
+D4417FCA56EA2EBD9C96D3596D09781E09AFFFB1B4441293EA965FE8F78487A0
+5B327A789E1104D30C62248A62660C3F5710E0DE61F6F5DF848507F1CB7DCCDA
+5F4D645939ABBAE1472F2704FEBF7AE27D7075946A02E322D43DB7A48F75A467
+5E081127E8CC6C1F4E674A6A8883E67BF4CD67DC016F0734DB7D2D1CA01FCEE6
+DD0B05A18A0FE8D678524A936B4AC20E512606DC99F412B589DE60841A0B67D0
+82F5F8202C1C561A60CD6779FB9DB36D5C210973BC6460EF7A01271CDB1F1D63
+FADD31E847C3B1EB0B9D4803A59CF6101D2178B0C68660E5078DCE5079FCCEEE
+1DBE1E9FB0ACC7C973CD013E06A8D0D99B73E863987676E852F08756EE0DC548
+D2ACE7C12532CF8A53253722C0AC57FAA8E9B95916E30B46A8481C6607CC8979
+012E32098D7BF25586677CF9349456D708D37D676AB9E72877A4AA616389EACC
+D4568F515BFDA5F56938455FD44F42AED19E9933930F0BE06B999D82C9A1A37E
+BBB23B6F155C8DF5CD9374D76DE34F099B42DD6DE794BF68684DB697EA5ACDED
+49880D90DBEC3E5E2F5EC08F1EA04B29174D918F6DA252FDF531D7873BF74871
+224BCB8A5AD6D87583AEEB673FB02EADFE76CFB7D08ADD021FC30DDE27E77D7F
+50F3B5D09196AB64CE919D4E991D84D1D583763D5ED14EF6B106399908DBAED0
+D3900D1E15205C0F4B5AFF9104926FEAF219FEB0690552827DC496C10556441F
+60FB15A6D64B52B2F84C6E49DFDF59816D67553AD81ED5573B000FDD6519864D
+C384B3D60EEF2B1BB5C1141764AD6807DBF37BE031D670AF8632BE22A7076AA9
+99555DE31320B458C792EBD69279F58EC7317B1A52D0E51E950D76FB2C254C11
+CF91B8EB98EA650ACCE188585E642D17A211DA2574E509EB4E87EBFE313CBFDE
+51F501C45B182D75EBFEA3EC9B95691E097E46D792BC095C6B0BD266B097BAB7
+9B8ED5797C17FDDB538AA00DB25482823B875CCD6E5EE55A76FCECAFFE8631B5
+3E4C3E9EC1E5408A2A2010FF96502D1CB940350524C797A89A5FF8E6AB47E4D2
+80BBE24B89EC689BFB00B9C5B469620DBB2F0281B757FF3AD2E84EFD0CA3D456
+A481978D788B40C8EF363A41B2C85E0AE198216E29A17D67D0FB19919879EA31
+57B62FA6123AC99A36840C6432895DC4528BE0D2FB5FE4F24F5DE3DFC5CE5E57
+CA4BE5EC998712BE30C680B8DD1F730CED756221598A0A8E5C448800491D8907
+A80C58E0D78D4A53C7B651177453802785A39C887AD73E87908D1E6AF244C67A
+9A5029E17CA9F1BAFCC5802E842C33B39275F046C809F2AC427279361B3FCA39
+154E1175EFDB43DCD748DC7ABC240C8AED3F4FD78FF4C7AA684AADCEDC564AED
+B35CF787921E74B51F4BAF2A8EC4BB2C3A78D2CD697BBAF16A14236BF7607F81
+6093A211924ECEBC1AA68511F7D9963DEC9689E801CA25DB41B89782A6471A62
+92965E950E21D5E41CE5496D95553FE6B9BDD94424914A3DA9F878A28BCF77B3
+BDA77E647D03250DFF74A2D17CD59BCC2763171F0EFA759C453A435F0AFC814E
+D64E3EDD354A334150402AC48A6F84693B2C10E91C67537B45A5308502E96460
+871481EB917739EB412DC4262012D9ADED07CA03BABCACDD04A6C3A87F4938CD
+6EE57009BB556DBCAA1E208D1B2C03F01E47EC0826C99C8A8DFB89212193E8A0
+2B2865539F8B7888664DE8CD3E5A193E6320EE7E111EF5A3EB73DF7ED921E4E7
+A26B1B1D18D92D78858086F7133DF3ECC8A80E499C576DAFFA25DA530769829D
+FC01632F7E18C5F481DB0006621F7DD4320ACEF939AEF57A41A11E6BF8A183DC
+6B2380A390E5F3568AAA53ED30292C6B28EC7EC45C17F471229E37FB8C1E5582
+B480FA1B647B69280035A0823C512F4AA0286201B2C9B7CA85D5FA65648F1479
+C86882D06BAFC16E0BE7EF0F4E16FBC4ADED7F49A2DCC9E151E26F1502748B2C
+0BC4FECC8B11398034491060133041AF08BF8EF5B1103852F3834F6DD659494D
+4AFD896D3E85560664B0F1F031ADACC315BC6140CF38668BBDEC82C202890144
+64BB345B4866F14CABC63D744F3E158AEEB004AC1A550502C2AD5F9595170EC0
+BE4A0A8D1232E0DEDA7F829B0D1A599BAD2007F9111EC24F1E08022168C2C34A
+B1DBC6A844531D7A8D21731C042A7B380A1FB1D6B82E6EA341B123F8CC078324
+95A5049CC0C46392EB9116A03FE0F1B6168D272D96D8281A1527CA80A16A7449
+F31C1948E9D6A0E6550B686D985786CB6AC7B58DB428755875CFAE0572D2FD6F
+7AA794CEC2AF0B7099AFC1DA5B3ABB479A7530B8EB9BCE9688BCE0276BA736BA
+E88737ACD9E781828D687114ED67DCAFD4E7404C7C0E924A9141CC27692BEBE9
+5E8660B935A6F18F321E0AFA5B606F67A4D8CDDE5B424E504D52B2CB8E831A5D
+F77DCCA96FC7D75E24F2D44D897FBBC3E35C98EFC52875E149E2C583AF6C10CA
+BEDDD89A099F97D70AD5CA26C0CCF9E65352819C2FA1174C157E69D48AB817FC
+007ED04651DDEB2FF2D8D7D405B401DAEBCE6151353441860A41731CE520F75F
+6FA578EAFE5631925738B325F8AF2B0E15A5B84E9E1E203119ADF574989F3B33
+84404AF0FF3EF287A226E8C9877DAAFB358E5F1A5F5420767C0B6836FFE901F7
+CD1DF68CA5778B4649759E1F3F9FB5C5748E295ACD163EBF1EFB64785625ECB7
+A5060407B009B0CBEF3FF5935CB10233BD332B73F9C69AF4ADF799CFA08EF25C
+A6CCCA840FAEBBC99C8639A75667BF652CF3FC25542FA6D873AEDC7AE369BB1E
+C15BEB51ACB928C61F97E45559FDC572003885B999B4B91F66459BA96082C763
+A9F7A5C7C7F27B9CFAE1E80ADA4570300158A71016DA3600579434AF7F35AE65
+8B267F947E13216E437A98485CCBC940389CFDB05BA3E663DACF32F21978FDB5
+18528E1CB7AE189E007FA0778D62B9D05592E25559747E578C17156BB507D6DF
+4B4198BED9F33ABD6E93F7D084DB0824F0C351F8D820BD9530CBC821CBDB276A
+8C58D133DB076D9BB5689DCA2257FBC741C5F59AECB0BAFF81E0B899291B6F72
+5CAF3CE6A729BABE19AD5E6C31A790ACE92E952E82638B6AE9C0F61FF3A30003
+22F75DD843E2317CBA51FEC548525A4C8EDE18D2FEA0F6D8FC00B33E44938D2E
+88663593AC4D1652680D51F1DACC46413C43902F77790B1C2E266293EBFB9C78
+833A274EDBF9BC80D19212D2635532B935766D0006697A7EC775AA3657152D72
+53540266F89330E3E19671E73E4BBB5F9A716EB13CD23FEC5B5358C7E004F101
+6100FEBFBE124B765BE98D24BF2E89AAD4A27C75A3549CD3907BD582E577B1C9
+1543C1AA7625E5AC9AFFCA8BEB637E5EA8C2BEAA30C8A7741D954422171D5086
+07E87A41204D0CCBD3A22E2D5184764921F19ED5981C52B539B06EDFF7A3EC02
+DF85F0132F038BE6CA49DB6A4F5A17CD5FA0AEC05478BE9605A3F7BA1159A76F
+03A38668E6F2C72AA7E4DDE730641216CF7B9A61BFEA6EF937A54F2A2962A320
+9498FD339342ECD80A0FB71DE820AE65B80A5B7A8E9196D2530B8DEB0A1FB8C7
+15EAAD601F6836A6C8C0605BBB6A336A523A6CAF13B064D04F48F002B579266A
+A46A47426ADB627668386804EB7AA726E1D65249F6440447BEC02306368C6B9B
+0C736C4E5BD2362B7C9F0F7540B5DEBF391141BAE24EE7995303C1967B3DA371
+E0E052DB1D5259725163265BDFEAD1798D71912B4C7AE63BA1CEF08FB8A15E3A
+25D67D9E3A70A040AFC254086D02FCDA5BCC1EF37450BA967EA9AA5C952AB4F2
+64F3D7487617B261CB8DDA5AD34429E3474A5C12D7DABD9F7053B22935909AE7
+D1D554D0C24436476ED68B1D209DD7AA80A6A547E045178D1763D596A5CA7AC6
+4E38DFD247A13D54EE7F2FF5A3442EDDF7F4894CA301A05ADD6E9C5020076497
+F2BF7F15BC210DFCE1A8DB7DB5ECA33EC5A7D635C089620177BD3E1F981D9CBA
+B1299C0CFB41F53253A367F7B05C110C3702C570EE29503EFCAB28EAE54FC81C
+922A0A80EC12E1A5D7C191603CCEB1FC7F41B06F2D91DADB13716D2D1F6BBB2F
+927AB0F59DEA31F198D5422989AF7AE03D5F4AEF146323F8977F79540DC4200A
+89615E702B72127B7FAFEA8152B53EA8ED9BE3BE7EE935B61ABD0B9C3DFE96E5
+B1A47626E4B62D96A9AEA785524FE73F68FA218DD58918D55E8338000DF0F5AC
+6ECC8E6ED15AF45B45E74AED4F06C132E8076E21C79F6D313494BA23EAC84742
+2F778B9948CAD5BA1D589A3EA21516EC56A5E40D4CC0A5919180C2736D6570CC
+FC03087BB9333C11310C8E5D814CB9AE8EC2D2973437F8B80C8CF48930E228B1
+4B35BFF4A7423DFD51D881829038D15AA5E3AC6AB976D3549CCBBD59034F1E7B
+A539B629EB8C2FD450677510A7056C1D6184C20AE04B8BE7525526C9B19BC64B
+1B3F6BFFB675B7D218D58C8D87F4EB1A28082A923D404CC58859AE55F0F8F433
+3063E52630170B2CB806BC95469581FB149AC66F00C26466ED3E1BA6459309DF
+AE6050F36FEF2453D0CDB3DDAED0FD1E5C7B21A9469E62E9CC09
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMBX10
+%!PS-AdobeFont-1.1: CMBX10 1.00B
+%%CreationDate: 1992 Feb 19 19:54:06
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.00B) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMBX10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Bold) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMBX10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 12 /fi put
+dup 45 /hyphen put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 73 /I put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 120 /x put
+dup 121 /y put
+readonly def
+/FontBBox{-301 -250 1164 946}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5F00F963068B8B731A88D7740B0DDAED1B3F82
+7DB9DFB4372D3935C286E39EE7AC9FB6A9B5CE4D2FAE1BC0E55AE02BFC464378
+77B9F65C23E3BAB41EFAE344DDC9AB1B3CCBC0618290D83DC756F9D5BEFECB18
+2DB0E39997F264D408BD076F65A50E7E94C9C88D849AB2E92005CFA316ACCD91
+FF524AAD7262B10351C50EBAD08FB4CD55D2E369F6E836C82C591606E1E5C73F
+DE3FA3CAD272C67C6CBF43B66FE4B8677DAFEEA19288428D07FEB1F4001BAA68
+7AAD6DDBE432714E799CFA49D8A1A128F32E8B280524BC8041F1E64ECE4053C4
+9F0AEC699A75B827002E9F95826DB3F643338F858011008E338A899020962176
+CF66A62E3AEF046D91C88C87DEB03CE6CCDF4FB651990F0E86D17409F121773D
+6877DF0085DFB269A3C07AA6660419BD0F0EF3C53DA2318BA1860AB34E28BAC6
+E82DDB1C43E5203AC9DF9277098F2E42C0F7BD03C6D90B629DE97730245B8E8E
+8903B9225098079C55A37E4E59AE2A9E36B6349FA2C09BB1F5F4433E4EEFC75E
+3F9830EB085E7E6FBE2666AC5A398C2DF228062ACF9FCA5656390A15837C4A99
+EC3740D873CFEF2E248B44CA134693A782594DD0692B4DBF1F16C4CDECA692C4
+0E44FDBEF704101118BC53575BF22731E7F7717934AD715AC33B5D3679B784C9
+4046E6CD3C0AD80ED1F65626B14E33CFDA6EB2825DC444FA6209615BC08173FF
+1805BDFCCA4B11F50D6BD483FD8639F9E8D0245B463D65A0F12C26C8A8EE2910
+757696C3F13144D8EA5649816AAD61A949C3A723ABB585990593F20A35CD6B7E
+0FA0AD8551CEE41F61924DC36A464A10A1B14C33FAFB04862E30C66C1BC55665
+6D07D93B8C0D596E109EE2B1AAB479F7FAA35279ADB468A624BE26D527BFF5ED
+E067598E1B8B78188FA4BCFB0B51692D07B0BEBB930C6F0997B437E2C51B876B
+61A563A2673932C2045833FAA35DB22ADE12102335D5DC734AE3AC5EEE6658D7
+92EB62131E1DFBA441F53EFF9021D9D4C491F26BE8F54C61165CAD778CE8695C
+EEAF70E3B20C64D4C2B34A084B5770BAB2A974E898F62BFE90F132A37E2DCA4F
+43E13DB13C94DFA8ECE2B7374827AE168634FA007F8981ADA046CED3448BF453
+FCD9A4F194FA648F9FC0971734BB69CB73439CB0DD021D44A7C11BF295E81733
+4DFBA460FF3D654F9FB337E99E6D66FBA87A817EB9CA1536C84833870E3626DA
+55D48DE850D3E6F6B29DA0E7C9D681283586F208DB8D58042E3A7CE55BE84822
+C98237911453E479EAB65AFEBA3F61A763B40E74535BE56C9D8D06DDF9441741
+5C9D9D917439368736619717FAB4F06E2C329AE0BA411F3FD522D9C33AD8369B
+D7DCC9DF993778482F35F965973DE876FA19E109AA198A00658AB3F0D8E3DDD1
+08A573F2D525202AFC57E05D141E6C0BB811E1FE280EEA002B7A45BB363AD06C
+318D320D2C81AA5DCC842CEF66E7DF7670588CB39C9F42EE7763A3A17372432A
+173BDEF7ECCEA297CCDD76A835C36DCE9DB8F8CB66CC71B4920CF5BF055A5260
+5B41A5373BA6E4F63C85671D979EA5EC30D22163E6D206168A3827F465279870
+CA80E6632872F721BBCC622EE4214BF723551C846765495FA9921E11FE1A950A
+53150C3F5D8595958A47E0B16064CC3AFD65DA294FFD111153F4F233BC5468AE
+69585C16CFBFCA32C4B96C161F47B56661DF84FCD8ADD3EC086CFB6BB5179BC3
+A5469A1CFBC8620BC711F42D0D3139BCE4E38698D9C574450DB43B5A19FA6D54
+0368BA9F7A8DBF96DCD0B8968CD194264E6DD10A958846C278B8C2BAFE7AAF8B
+44C84C955F1A89A13E62A054BC76CABBBF6296DE00A79CD7C8C61C70F127618E
+9975B59A880685E126F57AD80F8F4D376E1B476BDFDAC868FB6AFAD9D694B561
+001623C4D9F55366D053B52F2B09EC08B81901AE0986C5350312E626006038AD
+AC15FE313FCEE1A2E61F8992AC00CA7BB7F997707EA377D37EA6FF35BFBC2866
+A572B31491F9B80445685DBA5E62F166E80589F768FC95BBC79158C23B2F1BD1
+25816F1486A64F76D99A638AC0DC101FDF390811B3C118C2D972B2E7587F6F24
+7F1DB2DD922D237A7D18FF08FD665355CFBBEE799D3BFF11CD94CFFDBA3E725E
+DCF4CDE4307E3B199D91893A365D04F43A5305BDD2538E28A0788E061F3A621A
+B4A04E5063B47F0109C1693A284FA43E8F1EA9B68145FF51C005D3FA40713BA8
+1879BFC3CAA881B9D885A0C1AA8BB9A8C848963020A5B15F862E7DCC78F25D7C
+56437215999EB78142C128C6CB1E6E75EBCBB1E4614E8516FEB1E68400C61326
+D9F9E8A41216901F77D9466455E2A0B45FF50B27B55A1E1DD4F243C92BA6B175
+8F7695CFA1E91CDD8651AEBA3D258FFABA6280BF2420A98FA7CECD552D152CFD
+A8CCC94C032087A28D68332769DD2CB4ECECB15717C245BA305CB616CC72644D
+C78326E77FA602364A7B1630CA0BD0282FA781E14282982C1AD13479B6178D28
+1CAA541FD3F4316F4FF81C53496DCDF5F86E0D7C870FFCD85B36C936B1E08D78
+CEF3823546BE4329B97EFA4E2880AF3361C0DD67F77C8BA6F1CE3822B7FBE567
+064ED0477949BDA06483F8DD04F891473C8FBF73A61F7C06B20FB8B5F0BF4B77
+1429190979A4BDB29D77E94D5FB486A93B8B61DBC84AE06B4E06CBDA3A942043
+9F9926F541DDE4E9B734A985F9054493508C5F7EF9ADE372C520840F15F705D2
+51826A537FD158C4105443E38116307A1D4608E9C6FEC3353F57E65E150EAC0D
+B923BA82331D83E41C97ECAD6F8F32242DFB52EAFE2209B9F41DE483C8549B97
+407186E3A04011C8301B6C9A6D36D8170F40523FEBA5E498B8E5B7BB28581B5A
+08892C2894316068537336338E46F5113462AEA9DA7102ADD13EFD2EBFBC27EF
+00B38C25E4E23843C50C888B22BE1C76AC3F85CE148B7EA0F47D72E56726D13C
+ADE5A5D539A8379887352298B7ED202D909C8BBFAA0BBE7CD378B80488333B88
+E38B1C3C8DD17F32583A642A1D0A4408B0C244185C1376364E723D83803813BF
+106524811B9116A47F0A3205513EB80A4F798B330C9C4560F98FC3A2FA181680
+C83D6BA02AEB9E57310A60C39D31D5BC8AE28BB3171F90B69C11688521BA0845
+3F7D6E4CDB496E3F8B46D080156669BE81DE017A70B3B7D5EFD202F26514335E
+E06DF49F24576733B1BC191480D8C4E613537A80FBB7C408E7562D31833E3405
+2C16297EFEA28E55E929640DDC8D9C12D15A89A03C8637336BDD0D712AD5A2EE
+34012D38FD1AC70D13C3833B0A055B545F9EE98A463A2B3B424CC138AF6CA929
+A7BD80C3A804D5F80153DCA086B862A7D621B47F109EB93D67A73934B066B546
+BF15F27517D10CB8C83F7B319F423C16B42AA435231B9C4A05053D7109715804
+660B7052FAC3EF49E66AA763DCF07FD1AEFB5ADBC9913D3329AF36A7C5359038
+963383D68357C48B254DC2508706B1D5B71B66E2589214A336ACB11EA0E4070E
+3F993DACD86186718E488D4734F024DB314643A9488841654924DF275A1A2221
+2FCDFDB677FC3FB49409A644CEB01B260A4210613C0AB3FA3BBA7CFD4CF2867B
+B261875B9C592124D8A5609FCE7B376A39F6AC86E94F40587F69BE0E8B4C2E64
+DDBFADD699BCAA66A856556CDE4620A3C104EE29F9523D0ECBE6552A1B8211CF
+66D12AFAA3E9611858D51B46039B5EF0F3E9A020A6370B34E80F83195A643F15
+86934B5BA8B60ECCD0D3C9496F8D32E70ABE513FCBB85A77D992E73AF8B955DD
+5AE1FDC1CD972E81DF6816DBBDB583FC1410D2486F7479F1A466182482EFFE44
+DAC31E1F059370329DE19FE4629F33433576C1E3E6B49F122F2F7333C36AC744
+BA663E209AB384C9AC13B5AF8E9D0D7182D5F4D1EA874AE24DBA41DDB6586535
+8CA487EE4084602F3F2A7A46A1DEF17DE9B98728FB8113FD1BC2A62D3EAF7F83
+EEB13A260689B6BC369064D027601C48AF68CF0B507BD5AA8426833B11D5F086
+E0759BF00A3044F0719679D27D8D8AFA8FC303917255FBE6C1317702DAAB2C88
+4669AE63FDC111F7FDF28CDBADD14E9D82CB39340F567FFDFA4716CB99CED1C5
+871E005ED9EF2A8C3BD948CAD403F180EC8649FA7C4258DB0E1CA5F1ACA24DBD
+B59A2D1D7D920103457822D0F03F7D4CA5FA2D944B13FAFE51C031FC9416E5E3
+4987815ABCD52F279B7E1A86F659576B57860004E6E22A6FF097760138E683C0
+638CA1E808E4B88CE859772171D8F864F99FA82FBB5909E75603C5010D49C62F
+256EF48E28DB392A15716DCDEE0993D3C8B9D7A8DEE99AF3401FA9A39521767B
+F04344EBC10A08F880FE13DB7E11AFE3372B8691EA9807B11BAE3C4B7536B7CC
+B58A3DED042A85AE55ADA24E74A0A50BC5747F9C8E816A132CBB3987FAEBF451
+22FE85DD817E8E6B9DA980F189103C5E972614AE92FD7506CC61589B2284BC84
+A4486A73B619585F82FDE4410A3841729C2A26E7E6FD5052FEEAEFF792EC1B58
+0131564B3C5FF80F3FDB1132BC1D83FD8D0B4961AA68000BFB9A0989036BB0E2
+CDDB585566EADC55623BDEA1F218DFD343324776DD201CDC9AEE023DF5B98195
+AD23DE4BB8EC522DDC094D15A76FD38B85964AAAD1E2DF9513B87281F7106032
+D833B6E2019EA1E9D05C7AB6CB34DA376FD9BA187E8BDA5DF7EE06134DA2F577
+115F6E891601CAE2BFDB23FEB902E2B1A43F7A834632B6A7784EF9E9A659DE56
+5E7E66BD19DC11ED276BC0E117C8968E955629700B639BAE108F342BF38220BC
+A4C110641D1F70F6843206711275F5C33A6100CD20825B2ECE39EBA78631E349
+FAAB77A671146B5A712B40F644B86BB1BF3EE8F75E49ABBC757485C1A53BD9B9
+34BCFF603FFF6AE40A641E9626B0F9259F79B06BA573D6A42DCFA21A7D69BF63
+E1BCCFE3816EB1247C9F6DFC07A59656D89D69DB5DAB731BC84B77EFE8860EE2
+AD317C5F30763FF2C1B9C00C0FD480282FC591C84D7E5AB2A795B1D2B3E50E5D
+6061F96ADC97AA2DA0B04E96F8E3961CCE37109474963F05E9C15FDF55214DD5
+210DD9C43391D12018AE5480429C9D0738CCB2B0178A8824968536C99CB0BE77
+B649AB272EDCF07F46DE28AC2DB08DEABD47C1EADB1B2193EB614BC26FF58583
+B4543394A1C8DCB80606EE803B273D8E313179922EA334B26E58EDA4C2BDFF7D
+3A7D83E0EE66A4FC9C6BC9863F8F9752D66CD473F28194B9F26D624F30FF8DBC
+77A700D39436E16839628F46B0F3637AA4E8BF1B6F5B95CFECD5626B13634939
+C46CE51287BCD099E31DADA771D251961E311640C0623956B2AADBD1F18A5F74
+8DAFFBD0C0AD49F4EF2880A60AE0DF30AD1425B79DB0CDCF9472D2EA009E9829
+56EA40DF5941215E176B1AF92C6374AF78D9E6622CB915537EB9F5DD807EFE7C
+9749B43CD46272AE2101C1172A5210A4F71421E75C874046540050485E27FC7E
+C4A5DF6E3679343F161F3BDEDE5BF274D8B052224E987F4A135D2D8FE7F84EE1
+E0BF07ACF7C40DC3A9C50CEDFB0EB5EDE8FE341E696ADC8710EFA61526629305
+AC390632DE1B80CBE8B55B2A9600D8B94CBB43F4E0728C08B250A8F4FE484720
+E6A260E226D420DE06A87617A3264792743639A0FE4A2ED4D9627E78B0222991
+A583A5A87AEA5D695EBEF083D770C5771D7304E17ED5FDA30485E82FC8C41B86
+4D68C82CC51D87AF64B277E0DF3E97BD5887C7E1D913185D2FA7F29FF0BEC2BE
+14A3E6D029DEA2D9DB4A08B5B3ED8157FEDA81F552EF0918ADCDE7580C48FD58
+B0FC972EE053225A5B2264685C7A14AFF0706B13EA016721DAE4F8525B8C1E80
+A3213A33114A3007B7EA5CD2B1AF43487F191D22A5C106D3BA83A22673131EE2
+5B370CC9430E2FCA3B5E3D181FF1FE29DF3A9E6823F243708D19260EC2BF31CB
+BCBF8684B4E663F3B93AE10A636CC9E2F075C29F2AC4951E85DEE75B87FE2438
+C389B91443C821D4183C0C35E916FF970B51856FB04B61FF8A265206898EA5AB
+CF60214736A9A0A9C320F462E7B6F7CB43C084589B88DF4217C69434107D8DFB
+A9F3D9C248D26EC0F1225F842581F27265516AFCD19B9FDB23A18ACBEDA6AE5B
+0C8445E30DA6F2611E3173B7E7A6C2BE8BCEE2FC8D688AE82CA35AA85B47C48D
+A64FDC522636F50ABFC0B2EA41EA35D67B308CBF6C2A86B0CCB58A025DEF703B
+FD186ED17A94B64DE3F9830621D11F0D94F518030A232D7C5927625B2B61F414
+ECEC88EC56CE35BD4AC7F7D4257BA661D2856B8043F236CE60FBAC9186E0B245
+9CA6DAA942CB5E4D5A4A59A48AEDE5EB78FE118F766FA9A16ECBB6CDEB641421
+7267F61338AEC49F83A9DEA6DD1F7FBC53ECF8DF0C6C2EB871518A94CD832E53
+1DA38A4390638D9115136C9D7E3FF7494DD7C2033D39D21FAC65512164664997
+785058E339CBD84ADC911F1FF4633667B7C172748F83235C241EF9083A29B907
+AC96C96B45CB517099E62B7E1DFC89390DBF51D02F1BF2A1AFD3AE38E3026990
+5E9F5A6FA9746C9E61DB1A6EB4F484C4EFCEC8F915F46E196ADBA0D2FDB82E3B
+1A97DA40A76874B349BA4D480C360FEC74B1CC187C76128624D1C063D077BB8D
+F3E50D3CB072C7ACA0F3346BFB1D112EBED706BC035F8C8A6A23474BC914E551
+1CA4FA8B354772352F7A0EEBDBCE9CBD523CC03E2C5C03084FD372DC9F7113A8
+8ACEBCDA2378AD0570714AD3879C7A05F120D18DC6C0AC7C5950117B9C8D24A1
+D59CBFEAAC8E439E52FE8438B59A7164CAF45C78E8396FE323FF38EA05B2107C
+F20D2000F220EDF53987710F0C0E2DF4230391E545C2D21CC810A8E902323A2B
+BA82A938A9221298D214BA068ACA55C690B7B7A508BD6595860E880F7AA9F030
+27E4243410CAFFD55BA49F5CA06A8FF416F194D3E3AB7192ACF871C7478DF987
+16540ABBB52520CBAEEB922BF441D940E813995D4ED3D8DD707A631707D5F553
+D73223CDE27A4699C2B377C319C1A0896AA544018FE978F5E65B24B278A108B9
+8F3D7FAEFB97C51F9AC0CC60BD9CC620B315C91027B83F0153BA8F7CF627934D
+6D44536CE65F562ABF7A46DD66401FA9158F3B603ED6EE02C14B1919613FEC58
+8243E4215173307F4EAE1FDAB515F26419DE06FF2DF62D0E0E60563BCA2A7634
+4B58344AFFA0F104229A6BBAAB5CC149573A19C5903CBC58009807EB095ED97F
+BFC664A073337252DFCF946620B1679778D6EEA5C1015B0F73E4DBC798F90AE1
+5CC47F90690314CDAAF1FA54C47C9DA655DAD56FE577468C6199C346CE0D5C14
+F3190325FEE8CD9F9545625F5F00EBA1B449F55FDD4E53FAE7C5286468677ED6
+2F324DB5A9C804C8A2BEA08625C37E2341E5C5A49C06C15F23BBBD08D56FA07D
+2E6FDF1CCB9143BDD8EF3C48079B16324FA502C29DB5120878BDAD0A783CFF92
+19AF72D3844B77A18BF1D2BCE1C41134761176794957AF3B8634D9C5A269671F
+5676B9D71F99E56EF7F84374F15099EB73515268827EAE0B114A10FDA6171656
+249A963A32C88761299004EC6848BD76B6D8D68379EB302D2528ABBEB85CA4DB
+DCB6B0C376D86530F4FE8E17B93952C50D2136CDFB1E217748CEBF8AA6B46BAB
+73034165C62F02628CA60EACBEE01864323CD45EAC63832BDACEE0C39BF6952C
+A07095AD3D82C80E2875ED7B998F8D9F5D26D7416AA70E53760C04D2F07CF734
+E9AC0CBE98C1642B93075D96E35AF27717A52EEB4898F148BCD6F792194681E5
+F0A396D7E2FC5676FA380A34EFC2085A7D0A5DDBA1476D0823BB77CEF027B833
+A144BC9D0DDD83A6986D4153664226DEEA70796247B400AB0C53148D61BC69C6
+BA4C4A288ABD172909EDEDB5CE6494B4F86A42572D0BCBCF857A64A13503EC6E
+4B495640064B9C4299C0B6AE174DEEB07DB173AB3CD0A00F03E9545386A3AE24
+717387668FD6EDFB94402E3512A7A6F14ED8F079ABD4E161D42B40BE5027E3E4
+22D8EFD20D83D85AEDA43557FC14973ABDA50ED56948FAC97B44BF6EBBB6DAB2
+E05C768D80E843837DAAFE5F4781812CE3364155672C77AB66301A94E2A9E6DB
+85EF7C07FA61CB474C2CFC6A2F7D90962B4C0D9B95F391420EA0938BFA21461F
+B979C547DD7144D2C73A0DB184D4E1152F82A559F09EBF4620BC1B9313E03FEC
+0CA4C8D1EBDE10514F3ED772C73E76E67E3B20805A93BBC4E9646827276C758F
+B57CEE6AF20227134072637C357683DE58A7830FA2227FA344860C2E4B332268
+22E6346071A229CA44AF26E180BA8AF72645D356C8AC2DD443F8C9E4775316D4
+F832981E22EBCC3D707DF08F12114D104341F83E27734D81A56005E5C0AA55F9
+DBF4FB0D4B17BDBBDDB80B3EAA35925C70B846BC4C49D0ACFDDAAB55280E838E
+A962BB1FB63870089E1670EA0F1E6F810830E100D00759E16688AF88C5E832A7
+01EBEAB36927754AD34FBCF10F6B787B6CB1F90EE1C119A62E88B81BA82E71B2
+97ED389F742FEF4B76CE6A17D0516BCFBEFE6F7185A54397B3538E190CC19E2E
+4CCB233AD9126D64977FF2E89C12CBA5EB2ABF6E91289728CEB3CF67950765BD
+B6CB85DDBC55A6F452561F0AF5350DFEFAC063CE5F25C6F00C7D2CEF0B880324
+A82CBFF49C6796AA0C943440218E59C2A98E43C2D2764CAD05C0C5C4EA10F598
+F97288CCEE303179D86191444516A79AE6C4FD1E9E60615E3B547CAB7D471F32
+0CD1AF2B3F69C8C047FE1A01845D1F1A6EFED268601F87F8A92211BAB650913A
+0A2D98053C511FA63A8B3813E2E2B3FEDC870C5E6206101C4DD70AD1CA223A32
+FB276691EDF2421D12A4B330C4BC655A1218AAF015A384B8057A71B8696FBC73
+CFA6A9CCEC4AD7B0789E290F483E96E741325E6062C5F0B37C50F75A81D00344
+966F1FFDB35329F1653AC58EEE4C4B9E97F89EE4A3DAC15D67B6FA4C814A0995
+7460E20953FBD68438F0FCC139724701242D7C45AD30C72141A695453D003D72
+AFC26291C1F4BF991BEA7404DD85C825B840301B9215060870B1E5177D0AF621
+83FE4365ADF6FF293B7F9627ABA242F0A3E4A608570E46682A0CCF1284961F63
+B3E68FAD31F3452B5ACE03F95505B3BC194C783DE0F8BF66CAB795BAC0544191
+4D98F68ED7E13FA2A535722B667F6DA5E91E74A01D815F8F3CCFB5B4820E0797
+3553604F9341EC1B735D9F96457879D61A216A449D7B8A94C928154358253459
+AF775289AD8E86DA52D05A2C58387ADC92B18E1F0D1C04CFBEE4877F49953FF2
+42A7654DC8812CB057B305A68B6C22C8BAAE86855EC1ADFF0B3E00D60C853807
+20B98B49E7B0A9E1583E685716F6C2CC58162127FC8558AB128B53554A679763
+512DC6999BE36C0110423659F580491D0071B4AC2374D5D305AB506B24E63E44
+BBD84371A903BF4CC762A0E0D3142BAF794A332B629C0C8F87366F0130FB6E7B
+84BF4D812759F2AC831D1E3703177215908039D66CF07D17258BA2B34EBC5D68
+E86A5F0252A7FD1EDACB59639A56C710049D5612818EBEE157A773D8AF209CD4
+4A6816A6BA050D5C23B85C53E6C50CD2ACE0B218C8F87A54671E271EA0A8477F
+4A1DD5D223C0C644580373A57CD67EF1CCF7FADAFCD53843526AA357F666B835
+4BB78097E85D4D9211DD8F506380056F03D9C9DD9EF63EE9AE3A5FF0F74C654A
+EDB34C3E9894E6248A583032501A0C4B3816262300859EDDEFC8B4B095130B91
+A0E583759F16CB9E5B38C42CE172DE2DE760A9E994233F006CD772964A621DDD
+686F4DE3DAA62A937ADCE746FADF3BEF3FC2F90C3661FCCCFAD07CD4C22A2F8C
+4DF29BEC9C4ED7FB3006301DE829E18EC81C8B7F27EE3AEBE4292548C844523D
+A6F07705F4F16891D5C310B62BC698014846F9887925163C732666B6595A19CF
+4344B5391DC011EDA337BB0D00891E6CAA8A6DC61C87C467181950BDCF13A7E7
+BECB71FBD2BFCD3D93135D5A508D172C3F63394A741E1F6764735A61B90353F7
+B67797C681A1AB28131E8E29CD12906A9EE1E2844451FE9DD9B0228AB93C7310
+F2FC310DDABB8418B1C29DB475E42233826FD9D0800196D6A825F380165E27EB
+EE33F99FCEC55AB289E5D5BC4B02DE34008BA722EF503608673CAEEFC884E36B
+2D2BF1B6410DE582CE243523ACDBBBDF75A886CA62C634F99A8216AAC0B762BC
+4312371C42DF685CD54923B02A5C7610CFBC2F1AA39F0FB7EEE423B787308DE5
+634071E08F7659C70A6EBB94826EFF8C817AD6A01B13E91F0F15F43100B0DB6D
+052DB9CED475535E482A58E3528B50D66BF785454A17DA4E4280AAF58F6441FF
+0D18F744E745FCD33024713DA26FD532E640E9BAB1195BCA469E9FF2476E9008
+AEF4A4A68B5114A7C2A29448DB7A9E93AD6B06429D760AAD16B48FD9D5395480
+36315FE778F795CD7B4F4F5081F8636FE81681E643BBE83740B8393E22293B6D
+008C845E6B3B5F518B34337644792AC0169B793093D308641F4A4DD3DE51AABE
+95E16160C170D0DCA01374D0EF9C0C1138AB40F2DF6E4E7E5C45C8707182F8DD
+DD59586336662C831FD0228595D89E5818A85E6D2C461A252BC1A2DC5895D28F
+C2CF0BCE8DE71A094B7BFB56A0640AF9274CDF166B0AA5F9E32C5F595ED7CECE
+10F6DE434D4CE74211A93C88625E508546DD3715A18800E4829D27A0F1067F0A
+31BF17B596F13E728FBCC9FC0EA5D01AA51B5CD8B76258FC9A283D7E7B8CF14C
+80D2EAE16E5F6BFE3F773B6609BA7473B9431C7DF9560AD9FC6E4D64DCE17C7E
+9AA26089E18C5AD0FCB8F1838E58124B0028B2C2E4D5CDE965D02195C16E968C
+51714CCF9206576B6D07128DE08529C4D94A1E2986E9060CCBF3AD61C605035B
+F78A0F954F3E1E5227526C47631375202CE7B71F014053C68652EC5DD89001E2
+780310E4BDBE74B38CDABB12B604CA278AF003A951F7361A607A3AF0E1CD8C8D
+065668CB80022EB608FFD13A49FFF3DDE556B4F8BB7D8B379120AAB86D71AD8E
+64CFFB848D698536EF379DF427309125FDCAF1F521A767B8722DDC88A64F50AF
+EA8043686A2BF63A8B447B6B588ED2985C773661881ABC98E09DE56F7F1FA305
+78055AB3C1C99FB40A4FAA548BD9CA0B95C29D74E6A32F3058EBD42AC47B427B
+98D24AEEBDC0F957EB5887100659B402AB542EB5EC0A4CD278ACAC36BD87798C
+C41B89E8888E23552B06434635D39D6E4011F9E155D648029FBB2D9F8837774D
+BB8A7D722A8EBAF520E0CCB55EF124E5E189BD7332E0EA5A90B10AB63FE405A1
+6A40F4B356482ABADD9EFE8E7D2876F5BEE9405EAA684BEFCD179271C29AF089
+097C485E4D7911EDA8997D29A67B9C225D592EE5B3B79C3F8931FD7B1A6E3960
+328E1E2718E7F999714A6439F2DD59B5FA553106F3CA3F82D7247F61020C7440
+F88FE379239A75D25FE3B3F20EAADEE28864FE249EE86664C792D92FB6E0EB6A
+9D3F154EE8B06501A347761BEAE8929E122790A718E2389AF824728904A8D449
+8DC150E294B5C9F4607019120F7255944A9A8D269ADB25FA6CF19FC52B50FE7C
+B86962C94561EC3386D0D54E476AE255B82A242DF5676D26242C59391D0796E8
+63039DC728F0787DAD489F3DD3F7DE89561892A5E8A38A3B28B7E942CD331E9C
+DA010D80EE13169C73F055F2941462B954C1602E2BA63DAD5578DA5ED29F68C5
+50A869EBA6FCE2683FBF6A22EC68D25B306A27B79AAF8E889E82E2986A8088DA
+7934ACB4168DF49CB75BDA561940C8DD8A7800E4D0A7C1DA6A23C48AA319FFC9
+3AD59846534F647DA0263EAB436564B6A501473795D2E5B5BD1E071292F958F0
+909A4247E8714F06A959A5FD8407A4B5D701CAAA3D7AA7931E091EADA1821DB9
+A795A21744000A01933981BC2C3382CC6C2878BE0F3C91DAD353C9182ECD3DE0
+C8A7B8921F87CEF6A6124BEA3D7F77A4AE68731C0AA996A9BFD86D7E78BC99F7
+E6B1BA1CB38EB0F4F36CE7537C3476E85123D3DCFE3B925BD5564705E204B101
+FD0DBF5377E44978B52DBA6BCA2780DC42620ADB6EFCB026C148EFDE93DAE351
+9388DCF162AD385FD4F9F3A671FB07570878A52DE86C00255E93B45D928449A0
+36A0E59C8881CC43A72ABF81819AE18FBBACECB668E0F062591EE485CEEEE60D
+F4F218CB633F7A0260B4884CF2EECF06E5705A197D2990DA5D9A7456129FB40F
+C0C6B3B6B2FC22D4264BB48337A98C375DFCBF80080DF4AA0753293E91C96FA5
+12A0B8136C7C4C80FB032C68EA75660EBD1FFB27491B7A6D984054D35FECA9D1
+5FCCE108B2F3C4C23202CBF5B85BEE7F0F420FCD74CC5D558A016874EEE3B5D7
+8E046B303D46468BEAB588ED948712DE467C5ED1F42DF22C9B402C596D24B72D
+2F609E7CACDD293B5BF0C9553D22C47EA88339AFD06EB3AE466EC2333C1C85A1
+00CA808A4264FFC89A485AAD982CE70C5EB9070BE28B380BC239FEE14C455994
+726DD99D74920AFA174CE979BF410E72A22D151FD7BAC732B7BDD1A4142BDB99
+70B521BAFCA51DED5829A9A36F7FAE6E41BFA981FF2F209C9F3DDD617890BA28
+E2CDAB7E51D49C22F338ECAE92B418855FC59577F8F199F5E372AF73701CD030
+273B84196E718BA54284A26D724ABF7E698A94A47CE3917467540AEC57B31E4D
+3B8691B200EAEE8444AD5BA8C24A602B7EFAFDE2EF05BE950222229FE68CF9D2
+7B5F40456B0C5A884385AE655B9AA57095B4A0B0199E7C787CCE1E0C1CAB4E18
+506587C792DC259D0EA306972DB6170F008FC9582D4930BEC21D5DEED3670071
+85EB62A3BA27A30C9245F0380F3FD20A085DD77661C3408378172F830AE09837
+8380D1C07DA549314DFA349E9566259888581E212CCABA00BBAFF7FEABD4F848
+6672980B30A1968293CC7E8A6D7DE4A5CFC7BA3708A76122A3D2552F69B6E79C
+0D6C120A098404EC2B2B67E80DE56BE7BAC2A05FA3EE6B68596E98E3A997303A
+D0A072D846360D0321F3F856A8C7007F489B82BE253435DE87C8163ECD0489E7
+585ECEC657A0E040A9C1FF28C94BE2B2471AE2C5966778FAA120DB1DE340E3BB
+9164EB236F63D8663566C306F263A79D03FA3C26F0A3A6DA8D0AA119EF05A515
+CECB66F7D06EE72C00E2AE1363D5DA802AE6FDD5DC07F994B332332FC17A7AB7
+258A0328BEC8F828CD3833F6066DADB4B62C42FE93F07E35D1C8483D12D52954
+42795EB0130CF2A6A2600FEDED32D288DFFEB25FBA5EB70E4B78601A0A653162
+5F6A3D4DB999E0AE48E8CAB9E332048EDE4ED293CC62B7867F3159C28D6D73B1
+3A951C22096D1A77A68E37C2F6CDF58FBA5CE7D6B4E5E3FA78AC2B0845F7CE15
+A27B284DEEAB751B1088C9E190F4B90D3D9E068AFE56EB07ED0C8E332A49E8B4
+65570124F18665724A3E52A204BDB06D68B452A4D63F4B0CA4DFA3CED2FEEA1A
+D86ABA5D4B3EC7943FA2DDB74F93D3D4A1CF559D2EB3CBA0B986E939137EE099
+42CB3160219BB791799DDB079A10836EC5AC37E12137FC33266A7A6273987E57
+C97EC1F6207AE4517CA2D4E08CA90A5DD27015C65D22DADC6D06DEBC6BA5989E
+F64BB70FC214E1536882F72ECCF238CB5BE51A261CE55661ABA44D00DBDAE487
+ABFE21C5178A131B5CB3
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMR10
+%!PS-AdobeFont-1.1: CMR10 1.00B
+%%CreationDate: 1992 Feb 19 19:54:52
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.00B) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMR10) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMR10 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 11 /ff put
+dup 12 /fi put
+dup 13 /fl put
+dup 14 /ffi put
+dup 33 /exclam put
+dup 34 /quotedblright put
+dup 35 /numbersign put
+dup 36 /dollar put
+dup 37 /percent put
+dup 38 /ampersand put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 42 /asterisk put
+dup 43 /plus put
+dup 44 /comma put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 59 /semicolon put
+dup 60 /exclamdown put
+dup 61 /equal put
+dup 62 /questiondown put
+dup 63 /question put
+dup 64 /at put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 74 /J put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 81 /Q put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+dup 91 /bracketleft put
+dup 92 /quotedblleft put
+dup 93 /bracketright put
+dup 96 /quoteleft put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 106 /j put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 113 /q put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+dup 123 /endash put
+readonly def
+/FontBBox{-251 -250 1009 969}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4
+87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F
+D1F017CE45884D76EF2CB9BC5821FD25365DDEA6E45F332B5F68A44AD8A530F0
+92A36FAC8D27F9087AFEEA2096F839A2BC4B937F24E080EF7C0F9374A18D565C
+295A05210DB96A23175AC59A9BD0147A310EF49C551A417E0A22703F94FF7B75
+409A5D417DA6730A69E310FA6A4229FC7E4F620B0FC4C63C50E99E179EB51E4C
+4BC45217722F1E8E40F1E1428E792EAFE05C5A50D38C52114DFCD24D54027CBF
+2512DD116F0463DE4052A7AD53B641A27E81E481947884CE35661B49153FA19E
+0A2A860C7B61558671303DE6AE06A80E4E450E17067676E6BBB42A9A24ACBC3E
+B0CA7B7A3BFEA84FED39CCFB6D545BB2BCC49E5E16976407AB9D94556CD4F008
+24EF579B6800B6DC3AAF840B3FC6822872368E3B4274DD06CA36AF8F6346C11B
+43C772CC242F3B212C4BD7018D71A1A74C9A94ED0093A5FB6557F4E0751047AF
+D72098ECA301B8AE68110F983796E581F106144951DF5B750432A230FDA3B575
+5A38B5E7972AABC12306A01A99FCF8189D71B8DBF49550BAEA9CF1B97CBFC7CC
+96498ECC938B1A1710B670657DE923A659DB8757147B140A48067328E7E3F9C3
+7D1888B284904301450CE0BC15EEEA00E48CCD6388F3FC3BEFD8D9C400015B65
+0F2F536D035626B1FF0A69D732C7A1836D635C30C06BED4327737029E5BA5830
+B9E88A4024C3326AD2F34F47B54739B48825AD6699F7D117EA4C4AEC4440BF6D
+AA0099DEFD326235965C63647921828BF269ECC87A2B1C8CAD6C78B6E561B007
+97BE2BC7CA32B4534075F6491BE959D1F635463E71679E527F4F456F774B2AF8
+FEF3D8C63B2F8B99FE0F73BA44B3CF15A613471EA3C7A1CD783D3EB41F4ACEE5
+20759B6A4C4466E2D80EF7C7866BAD06E5DF0434D2C607FC82C9EBD4D8902EE4
+0A7617C3AEACCB7CCE00319D0677AA6DB7E0250B51908F966977BD8C8D07FDBD
+F4D058444E7D7D91788DEA997CBE0545902E67194B7BA3CD0BF454FCA60B9A20
+3E6BB526D2D5B5321EE18DD2A0B15E53BCB8E3E01067B30ED2DD2CB9B06D3122
+A737435305D42DE9C6B614926BFD44DF10D14402EBEDFF0B144B1C9BD22D7379
+5262FEEAFE31C8A721C2D46AA00C10681BA9970D09F1EA4FA77428025D4059BA
+2988AC2E3D7246BAAAFB89745F0E38580546045527C8779A254DB08DCC6FB9B9
+0E172209FBE3857AF495A7F2B34BC895A39A30F903DC6E3202D29AC110D868F4
+7184CB78407B8B9D42F6375F67FD4B828592E4A977B9E71854D143CD1A9EDCD1
+767CC2929E071FBA4C3D17500E28A23F697B5D5CC68D5F56EAD14BD504E07182
+3FDC12F5404E74EC1C02AF00C1A6A17F958770ED4A024F5B3644DEFB61F2578E
+56013D0B4E7CA3AD255E23DD63369A921D427EEE0E098E8148B16E8A5613A8F8
+A5F1099E15AD16EC554B644DF306F0CF3571055A81F1B464529DB49E919F88E7
+581066BEC4765E31BBE28C245BBF0B74610DBA30C63A71A4F3B60593A6B41C6C
+636C980828CFE9A3362FBC02F1967F0F770A4790F90DEF9D56E0A76B0703FC58
+2841E6E8D984FB476D4FEB960FFB6B386EC6CBB9EB83704B0AF63F38C77090A8
+DAA165E6C6BC86601B14F8E9F504A9D578AF05128D8C1BCEA9D21057958D5DCF
+653026524A2D101334AA3DF02A3CFA410836E6001561C00FB34AB04FF97302F0
+7CCD024F8C61577E82FF229A45F7FE22ACEDD95AE8052044A41EDF46B8F84346
+7275F5423171DF88188EE93BCFE0A84AE5C999E9C774A32B7A2826CEA8A8560B
+2F61A42F967BCBE2081DCA5547D9EC53467ACF8A6AADFC54CEDB7305DD661ECC
+3FE33D8C93D2425ED57BA83F360A384F6B94023EF8938DC136ED1F66CDB618EA
+F40377CDEE0F17653E011F5CDE11C81A3FA5F7168681C02167B275AC0F73EF89
+521A152823FCFC811C71E5D05D99094EB69E5724B34217D101BAA302B5BFDDF1
+4DE66F7887BFD458C2A97A835C72E7A6EC2500577B0B057BA1B4773094EA1954
+589FE5B1D1B4520FFBEFB6ECD015B606A244E605E78D39EDC316D97D99862CCE
+898341583D28F141A02877B76050B07694737E9F107F153E5A5C7393CD479A09
+114F07D12DE0185B971BD526301914EBAE20A38DC804C2319EFF3C8C4186630D
+C91141528F408EEB02C718A0A3E0D39D1C9853F71113AC07DD209828B4873031
+3E7A4E45D95025D9C558CC0C313BA3333EFCEB2D95B7BDA88C062E5243DFBD99
+744C678DF4AE3478C68B4F7BF5C52DFD8A81DA0BD2C95229BA43D15986717CB8
+A925638049C2A15A6913B9819B3642F68A07C4FDB2552C97D29211FAE2F16E40
+076342D4C5A72E0D5185CE8EFB7A8D87D7F345E776512E8B41609794052B9A08
+87EE0DECF203189379B9DEFB8DEC9585DEF2B44C7F64B4DEE827C74B975BD1F0
+82D7E511A5A0FEBD52702F7E68157B509F303378B191BAFFB4229495AE65C558
+D72D9AC8286E61633B29CF90917E4A01030D6B82CBF263751BCA8AB219284B04
+80A8F4B34D0592EEAB82D64F9A5EB6A08A6CC5A7F3D3EE2B61710DB386AEA658
+7A059E9633123EFEC39FADEA37C4205112063F7BD3D2F8319A30DA796E55BA23
+00DE2B3C15511F87044ABDD9DDA9247B5E785A01A05B39F1A395E36AEA4D3D4E
+ACACCB99E99DDB1AD1329069714FF050311B274E495FFE43D33DB3BE958098AC
+61150EBC4F9DB7BFC8F6C81047DF0BABBBE67970D14524C82334B693724A0818
+0007E4E848CE4AC8F07E72F02D74CC5C06DE0A67A63156F9567DEB913E874E56
+B993FF1EF6774A9C582D8DABECD1EE1D1731457305A989E9BCCE8CCA4872B3C7
+7635D840A0FC8FD9A40CB7B2FAAAFAE3274A2BD0CF7F681E877830103D2DD3DB
+761F3D925AED45E0427BCCF205201BF0DFC16C0109A4389F37F25AC6E4E70C85
+1BF6A47B91F62079EAD1D983BDD249D0EF82B21F89FE58CCF2612BA50EA48901
+6757149BA3C3FE22E61F80F62CCB355082A71F1C85E8819E71E8997CAD75ABB6
+070F0CEE40E3A9CDBCDE24D59F2DDEA887568EBE585EA8D40BB4D0677097E73C
+1C76DE3BD95B2BD843B1522540C5CDBBE4E1E6FA4A77F93E724F4942757B50C4
+40E316CA4DAD1D9D36823BDAA73E3BEC72B03F6DB2E99C89D2C3F840C15CBBAA
+0EC7330D23A3EC2780813F0C1F56C891FC040B958C7861DCA654743DB8FFCE0C
+EF4EDF238CD820A3EC97CA497B2C2504E43B9F29707D7F92114E8053CE90C494
+4C3E681028257FAE5E2C60C3E1A33E40A7C5920A8E6FBCD4686135296590D866
+1359BCA5B650EF33AB7582BC61158A573F93C4ACD4BE3D0E36EF1A7683B85438
+1FFA47955F8C1EBB80BEBC9427F239EFB50BA42D8C72AC0F77A511AF3832F819
+FC3576C4A28B6154B8B14B9B88A84B2E9DD9AECEC59A9CD717151FAA26CACA64
+FF6B2A5F561F77E9DBD2285695F0B1DD8D1D174EC5ED48DA7324EE88698105B1
+E28FB0EDB30067AAAB1AE5EF6527DD1A83DA04B50E5E2B7F2A63F0E8F924B2B3
+734ED216DFF4E41E2C074741FEBDBB01A103B5A68961A12C571A0A35CEDB11E7
+DB6C9046AA97B45F756EF5B32CD3E1446C9616BB8A7F57308679AD7E5368648C
+37F5CB0CB4C95D49C8DF2D30A8C17D8870BE3C4D9A077BAC5EDF794050C793D8
+D26A5DBAB2025FBE4841308D5FFCD592C37514D1EA9F7286EE8789D41BD9E38A
+905038AD5FA8405AA7568F9B34F43DD17FD575EAB5067147CAD8E9C0A454B292
+74635B10585CE8D8F891A07360DEED0DAFE9836B006C3ED2B6E10674CC17CD8C
+9A862C5C51EFEFB1AA02F313DB95969B90714C62F32BBE3062E2D805989EDA55
+0684402A5FFD3B330B194B1EE4490D05044859619A7A6A7AFEB4909B63CBE907
+34CA9F2B19D27DC59F737344E1298EF87FD4210D08FF55E143319DDDF5E94582
+1FD4C58EFB00CB9C840ACF598F300B9F6BBC4C83A89E7CBDE9F37C0EBC924777
+9337FD42AE2B208FC6CA3E0D9FF9AA07BF7BB68ED07EE307267BE7547020AF1B
+B3D65F802A95A69A2CC366B51AD5771EC679B23253F21CDF12E8584ABEA58D92
+38F3B4710D434F5F967A9868BCAB5C4B57F5E1650356F9509050F03FAD247F06
+607D717C4C183CE793BA995DCC37C836BC994465C1785517466DED4A2CCA2AB3
+32F2D92C7DA918D720341298C650B4ECC780A457CF6CFB2120313BEE25A34AD9
+3B2C2B587AA791104E38D27C117C3B4255791862E6750FEC3C32A5B965D72FB6
+E333DBAA452661F88B7CFBF442A9CF467D01B1AEFE817317BE81CE3479E17E71
+6C24D0A6C08978B3DB9EA09567FFD14118259E858E88648222DFEB2A655E0A0A
+98F08F3D13539005E85DDFD0B1CA60E48C0DC80FE0AF9550344B07548E9B3039
+E9ACAE903B7A3AB6FE24324319DD792FC5140A2A368D233140DA5690D5A8DE57
+A42AB04F6E9D167CC3D0348FA7CB3EB537AEF89B99C7C93F398C9360A0B1E2CB
+CC7E403B1E439CE040F958BAA50E36980FB3EA7F789FDA23F4292E566BCBB731
+38BCA4A234E2A205D815FE2A450DB6586D56E8C1AC62A50DCA49CB76E122D050
+E1A3413CE5BA8BF96F34990DCA2668FCA06BA66D9031AD98650EFF39D881929A
+28D99CFCA94FDB163F970F29F3A2617F83F4894EB997EA7AFB67A6293A08E00F
+37D5A50FC0C360BC4B7F9C876A6351F9D4B3279C1083D6DC79F5A63EA48CD5F7
+02FB3C581F446AA9F19603AC165BAEE2EAA7B2574268947479540B5801FFB122
+AEA27CE208AE86BFE14B8D139C16ADFD5D7ECED40EB0E258B38E509A8A1E07F6
+EFEED540300ED1EF27AEA5A9B1B0FCF027F626B7258F4485B8A17399188CEDB4
+8CCD037D55F8EE4BA5D2E876DF7083409DCD95F644F43778567B61F3A41894B5
+485A87B1381E9E98C713E2BDE4594977B85C7A4F58D542C634F9F76B9403E23A
+87D1091723B30E53CBB97A1406EBB78A7E06DA949505FA40F0D5CD0675EC4B6B
+207B7210210E7145ED707377A9A1534FF7ABD8395083EC23928A03E3016F636D
+1697B161377879568A752DDBE939BECABDE106790248103F1C6D75D474584F85
+33DD684D3E4927EAE6DA1C2020EB78B226A43708351B8844E4A491E82D018AA5
+AB46821A444373FF2CF81F996193D0C6AC98E2302BD0D7909BE77D97F1A6CC58
+959CDBFE69014EA8F95224F2D2EC70DFCF8A38EDFA77581CABF0921B863A6544
+24740A40AC91E315E97FAAB8D490AD44AE6805A9C7471AE945A40886A2DA1F03
+7B94629ACBFD5C307ECACB6DE6FDD477F439CDBAC935A94679F037F1FD6DEDA4
+F4EABA6C9837CD7679DCF343E823FE70D065D0379ED0EA0C51DF0700B7F97775
+4EEDBD920782FF119223FAA23689358F35C8A68566DA0D9097C6D0FBF163EE2F
+656EEE4291F0DF40C5F4910DBBF3A9A33A0B349A2FF1D01811857F9335FF04B6
+EDDCEDA0172528348FED69047FFA80E2EEDB6A612082134CED2E167A061EB226
+CAB50190F731B40DAB9650D4BC581BFEE93A2CEB9E9BBF5860760405127A1E3E
+7FBEC40343D0D2E8EB80083B354C095C483A8405B7BC144FCC23E8F25E745A4E
+8C527635AC995A1065A7FCFD805C6CA7CF611C06845EEE14D07B81E3B404E727
+20CCC5BD3657D1575949FF993A71F5F8C5236135963F13D8C09B1F3B08CAB6B3
+58460385AE220AE727B0CB9C05020EB678240921E0735D7A28E6C17CE22AE05E
+6C9DE888DC5D3E24C60BB94289910B3723F60A74A8B48ADD5E03B6886044DE90
+69236204BB7411A3D9119333D328F3A7BC446AE7C2C4C529D5E3D501EB99C900
+D040D670DA581CF03FE6243093192F5E91A13B79BEF60D605A2EF3BB93B569A6
+9C533A1AAE2CC70151A0BB5992A5B8269472E626D299F66D3DC25952AD9CC205
+25572F56F774E156EB78B0406C4DE584660E1AC7E629DADC0BC41E725BACEE76
+FE217A7B0190A4CB69E9F32F4F7A184BF53EED2B1659DAC33A2EE695A88D9F07
+D076E3ABCEA448A576DB7B0C5549A5A2D63710141F4E539DECF167EFAD871552
+7BC24AE52DF04152173D6E4CA827DEEDEFB7E9C3E72B5934C5DF97BC1EB23749
+F776539AD43E9200A04341EC0594EAB62A0C7050DCA43945E58C4890350F3ECE
+5BA67C3D716D5360A5C1FCB6EAE1EC00D59B46402B16B14B821EEAB4758701D4
+4CECA59735D67B099AD9CC4BFF50B846CFE14E35E4D3D1F5A3ED2641ED940775
+0067986ABE6AA117DA321122636AF7FA88AF53A473BDC12A4844F46F43D94ED9
+CBB72CF2CCB37469C2E63661BCA5A298D5E9C6BD3D41853FB4867DF938DF0391
+2F7ADC04FD1B0D6B0D5478581D4A2E51BDA015A4FAA53378696FB50A3297DD3D
+20C365B963BBEAC22789E0073AA921F0640F63DE0833764999F02B66E800991A
+438223368F1AD8FADC75E2C5130F76148FBB0ABCE3B1270C6F1CAB55259B5290
+A10A1CD5419F9254ACE5834A4B8A71B8068EC21E6C4AFE9E790C74EDF7411289
+3AEF976BB7A42A7CC1AABE4634CC1700272E6B272BC6CA5F1549F3172537FED6
+C4047BBA4FE5776BEB53E8AA82BB17AB4796C1F91264A7B7E95EC14C0F74710F
+9E9CFD51DB71C3CFA152D6BAD9E60B38D688C7CC5B587F37BC2301C2938DE2E7
+88E1607E5B0CE6AFD63989315A9AE3BACA1E0C0E0F6CBAFF02685282033A7532
+3E5B0AFB7AF6F4E3FB5801D175D02551F9746503A2E50AE9AA8AB56DE79BDE79
+74B4550F3890818AE801957A3B6A822614EB8D12FCA584EA8C41B814D30856A5
+97C3ABB9F665D1B72B8D19C4D2BEA46AE1332F8BD2A6FD2C2A1183E48F62C4DF
+4175B4CD65A9B145D400D1CAD7E00D0D154182126764BFD3A267F85BC623A575
+92FFC5A063A9205A02C89CA4B40C4D489F17D383FAF081A3C0B2C94E21BAED8B
+1D06A4495F917C37F8B04070E9A90F60AFE3A8F0073086F00C5A707A96D4E1D2
+BE5A637EC1C614997446262573426452FA5872FF661B519E24A34E3C58D4A07E
+BBB6C294D4DED3EE01A853EF8E153D905B0598241F97301CA600C09B7D116901
+77EA1F6C40CBF7CAD5991EAF92890305BC710270FBD575B626A59EBEBE2A9A21
+D02700440C57557225CEAD5FC1EBA1763746A061A7F4DFF5558F6CF9160F7CD8
+7C84BE7407ED508BEB2338DE3C5207A7804FF21C4E0FEED254C0DE812FC8DFF3
+4B5B890B24BE5AC7C00DC1C193C88A6B33A442E184B4F5EFF79F4CACB8A56DC4
+05098C620D63A0135F8FE2959A396398A421FC16F8AFF99F702C1B10F92ECFC2
+2D86DB2489887879926E2AD34DB4F7A9CC460E12812C24FAB08ED0F2C3DF3FCF
+AB41034C07225F20ADA5B5AD6AF5349319D3F937DD64B2E0A0887B880BE636CD
+F814C498584F19BBB3FC146035E4EB4A3B7EB436E7713D968B24840EE00C019E
+D08263764CF0839260BE71F875E5408AF4A8AB1603F7F694C2DB705F6E13E1C9
+4CCB224D0E2B610FDC729EE8E33366D0AFB0A014C3AAC6B915C2268C27A65624
+261E38226363108AB1C12BA960649782D0A02F87404350EB7F58C6C54463C1B1
+334F936DDA18C96B577D4409F18E63A79F708A816096A6FA1071B1FBBA3DD470
+C00F032534140440012988D81DBFFEDD0F6B02827CF76A92F638A685BB1686E5
+D0624C445A765E6527B4D2FA2B8BBF035D9B0BEAA0CA35D937FA9B4A79224387
+CD974CC0A052A5C78C4CA12379413303DBFD11DC6B78507875E6643D36679EC8
+3CBB213B5116E5A262300890D85018D550C69365D717BD3AD5579C906F8BA35F
+1C07EE6B17F394FDEEDFF5340A86E28FDA9ABD8803D832117A74BA868326A1D3
+4004DE8942437EC0123075F2C6B97B306AA3C806FBCE7CAFC83C2CBC77E25C3A
+082DFAD7D69D36ACE654CD17916062449BDA3C3AF3806416B16C718128326DDB
+062CC9FFDE6FEC2D0451C4994F5C681A18D7E5310917B2994756AC8FD055F7D6
+92FBD23FF685754DC09F36AD98201040626C381FBC63217DDDF511ADE6D13101
+0043EFEBFB8C49652EF4FED438B5322D83C6B998BB46BD5B5F31BA2DADD76B78
+ECB3D44A2AD40518C22914CF53AC408E8015F2E828F6F4908FE0C85DFE30B8AF
+7A1E91B6AC7E25BE17F971DEE8271DF880E440EC95E45A6C909AB0DD6259AFAE
+35B3AF9B04936FCE351DA6D244D34EF22D0B8156A583845423E93A3E5C827287
+EEB8E89E19E4FA0D6406506B73285484A75082DF8E0219FB5543B57AAF63C47A
+0C5616682F22DEE96A8CBC70BEB556DF3E719CE0E70FEAB87448B0FBF45EA6E0
+2006416E39CAAC51A4568736D8F0270144CEAA8CFF832AD16907E09E49444BC2
+80306B769125A50595838E76514A7FB0F1392AFE209D8817FDBCA2DBC8CBF8C8
+5948F7E471B6B94D7FAFC382B02824888D3C5860D1AF18F729678899932A1AB6
+A6A7A3FAC08BFFEC6FFA3CD9543D36AECD2AED91B0D8674EBD6A9728FE8BAB6B
+4D3E8E175D0941775B3F96144DEA873B48F3F6B7B6A30D2FAB960AB555AA441E
+69DA76ACF6894AEFF47BE6BCC094E42D735EC1B9D65474C31F0468FDD3CEAAF4
+333F60053CFEEAABF43569FD1C216FFD77EDD13C344A0024CBDBFAB9CEDEC95C
+115192A65A818C166A5C4441FBC0A1379D0F3FE58922EE49BB91857A03BCA8F4
+0067F324EFA67755AC0943EA80D0EED33A817BCE9D5676F9963844F6A2DDA48E
+C9B3D9B1E9F8CA3FF805CEE70807B028510D0AC5B13259280021D06260FAB24A
+0143CFCEE0C3FDDD6D817C717DF925DF5022C37A19FF63F77D464F699F585E93
+CF29D5AC1F2CD04E992E5E714C1EEA2FD56400E45A42813E4BBF87BF0849834C
+F54A730E4B399FF3BB4E14D9CBAAACD79CF06AF35C128CEFCA1C43C8A5ADC1BC
+3AB187E52F70A2562F7A705C58396C3B9198C78AFB0BCAD890956F7D463C70FC
+0DD0AD6AF96D778AEE93A3A79A514A16C0324421D5DD3F7BD1002252E0F24DDA
+3EDB1856E47B979C235BCFE8D6B2FF68864FBAF0CCBC3BCA811760643E0B2E73
+551BA0BCDC4037F497911B8A5CCEA5AC79B2C8229F317B690108ED2C52E7429C
+01DFA8C97FD5FF794EA69BCE240C02A9640CB5194CA6AE598C605AA92086AC82
+C983661FE88DB62A3B732F78F43B93E9C22A09B29FCD79E41053D4E27CE6F3EA
+FF365338B03B87AA0D48063D02B8E4C88075FB2354A05EC177E3FC76FE4E4DB7
+7337F0AA30608A6775C928A39A515C20A285D0C4541A2A6F06E6844A6CA428B1
+68D522A3EA084A2EFD17E3FE423F2F55C9F19E842D2E30CB79026C2D2DA9CAEB
+8C4DE6394771D9C2D071F1B17047FC66A2ADA0FDEFECD6FAD63EA5F2196CCBEA
+A4DB2C62A0948DD2A8A0D30E7F6808FCB912704E647E1FCB8E54D27039F67009
+4E995339D198156D3F6522EC70AEB3F22ABD6699C36386B98E0992A57FD9BED5
+D9EBCD492CE373E46A35A906C17AD2C4C490A9F74039075C8AFD8EB52C9631F4
+0CAFAAF50E8C6B4C565D859F6DEB844846D560318367C21967D6100DBE5D3A1B
+DD12DF6B8A3633BBD59EE865445D2F1E8814D8D64C3BC913183B59DF20361B66
+6F3DC614B9AC2C2CA4C30E1A01C1C2A2054FB4BE7D58C6BFFEFAA4E13087C434
+ADC6D8F1185F68B2003E7EA12A991128037E54D2A88EEA2E794D89BF531E107C
+54278EE82F49454FC13638CD0B83C142BA3E0F5462CF92FDF0FA223EBF69D12F
+3D99BA804FC467F40945B1B0AC23DF88BE1BDE21E296A82870F6322630C06823
+27629EA02637E6E3E10F16747B3EB3E479AB8A347FD46D581608D453684278A4
+AA58BC490F673269CBE7356CA4F9E523CDC3F5D98EA1B95CB686BCD17366B609
+72BB6B2167EAA0D66E36EF6A1170EA56A8485A659E55C8D50108F6455F1C4227
+6CB5DED36763E54089C6C04BE71D5B762254EA4374C136F98900F25B239652FA
+71A14A43F046EC8171C490A5755F90DE4ED09F8AE5EA1A6A98EC026B612BCC35
+6879F1942C6B45DF7A50F4E49B8C8013164CA04DAC46F1D799071BA6402EDCD8
+F55BC6B064A2264A37D4BFE59754703B2C13BC4C2586A61EE4A9F9915F00FC13
+05072451125EB001CE97BE3933239DF6501A664B45FFB5E63467CDA463A5AA14
+504AFA4C8D4A976B459D8B41046615E06DD43760FFB72488397A34C4648C8B4F
+C56454126529C50AB1D3B328136D31F79EFA1EA011C8C6FD6AC27FF2D4218B34
+3F99304558FE4B1C81BBF4807AA89ACF653EB74E9A2C85D8DEAE86F1A7B3B5F4
+077D09031A32E48C069539410F68EEE2A7ACE7B200CA099BE59009268219DB52
+27A2D68DE15C91ADBB30775AD1701708749754BC4F0BADF52540EFEBCEEA9FC0
+E00ED70078142201E897E93EEB6B8C033B2B21617162BB54060D3A14BA41D481
+9B2BCBFA81A176BF324C8425310DE6C313113A9DA8A950C6439996C957ECD22A
+BEC6631437954D043A5F0F83508A7EB24EBE9058841DC13E42E5A817928965A1
+0566C3B7A4593733E519AB17F3995C6702E3378822FA575A537E720BF26BD14E
+D08755D999FA4AF6D0BBC2A54CBC279C8E75514733DF7F2C19B84F043A4C9A03
+979FEF3A622C92ADC58FE94C3C6C6ED45472D1E48290173613F991036368E036
+1F8A871A66BE125074CAC7887A69AD92D96F157BE10A6604CE0647E5D2F6E4B0
+8E3CB6AD0E830C18B4C239094238357D1D371F643F50E81CAF234EC88E0CD6C7
+BF0B0626895B812E489153B01F94C0D86769A239879CEDBCF2402894B6E79566
+1AA9B48033407926F18C7399C641C3B0C898AC99AE6595E865726374CCE03954
+92D48AD6A336888DC372676F0E1BB9821F638924976163976175D2A687324741
+912DF146F8C7F6EA428814DF6F235728386BD3558CD588BB1699B43C1DD6B4E5
+CC4E75E69FE0158E8666CD4E86BE2E79148680287615041E559DF70923831A27
+63D40F0F873B3DCFCE27E0BA3F396EF61417E77DE37C0D11902FD961CF5174EE
+8EB1DBC17A1B0FED2BB385C9475096D7EF37BE12B0D75F6C1883229F3A62A679
+828645A2E71DC2818B037613531463FFB0F84EBC614F6A9C3BDD29807805E580
+0200984E41C66B9C99A62EED7E91DF58C72EEA135B03B08292FF4532728086CB
+5ADD2170758529CCFD0E652138B55D545DBFB5C1DD4FFEFFA87DB31F24DCECDC
+203A0B9D242B8F0ABFA7484545FA7BC22CC5F30C28629086ABD681555FD8C060
+00F4B5444B0C79EA2F1EBA2CBF0C45689B6D4B09A1292DE9F6E92A9C52A4F601
+924EBAEDC0F478330826DC36A3E3AC35DE0B82145E378108A75D4DB79B78A713
+4A54643465AB3D1127B69467DF7AAB30EA92ECF0B5C475FD5922EE8310F8913B
+7B1AD24A93EE946C8E6DAF09C3697934E94DD0074D8DB4582D26F9807786CD8C
+D8CF959020822AA23D57077A73126BC5716FCFBFC6271C9F1BBEE9730198EDDC
+41BF84898B24CD5A42D6D060C281B1810B323C5AC6032870041F007EFF54BD07
+63F24FED3250E1F67F98E4B73678A5BEFAB99103F09E59E5E80D4BC9A2977FE4
+3AE53E66D4185F52A001E6CFE374CB6A934187664F782F63E3C3359C66017383
+99693E9A5AF425BE05A681BF7073A3108C77C2A31A9ABFCB24384010E36CDAB1
+86219786B68AB2A6A7065167EF57C5EB79D790824A459A137E7CAE466F1EFF55
+8BA7CF2E9382C1BDBBEDB381E7BFF677DF252886AF2BF19B2E2D8C44E0C35957
+A0491E4723DA85E67BC6182EA0803EDF4BAFE302BFD52D84BB888A70232F7D64
+3CA598EF660B77E88A6A8A4A4D63AAEBB88E400D20581F2DB42ED3B2B184DF15
+6DC8E586726B5074EE71F347494C84B2365830A932A4F05F3EF70FAD933EE655
+12834498F3A58AC270D74CBAEF756CB8A499D3EA9B99C37DBD8D84970B188530
+82AFCAE63D692E6A72777CB1BB9523C75F9EBD4DC7F6E5D6F39862BB1D7AE93E
+5BBD3E135E919421C3DE94A2EF81914B6EC5224906F83EF47292301C59C3836C
+3F359945C40C61D9FC0AEA5A88A9A93DE5CB8DD195725FE145E79B7DF33B1FAA
+F14A457C39D12AA5881FE5607251BADC4CA3A1FD901BEB971C765D568803D1D9
+832D5444A1D8332E125B7D865D5B28CD78C7043D8A86AB4DCFA769A183FB4B05
+749DFD67A669B7DBF6A6283CA516B94704D74F64C3FBEEAC15CD1A2D939CCF23
+3A7837791AA06E6167291EC2DB0C34846D7D158EF594C6499288ECB69EDFD50B
+4AA7F1E37993781A3933174BDB9F8EA0D41BDF7896BECC4BD9E6FE17738AE1F5
+FC0B9D80D6247E861AA03A36B3BC648FC8610203AB27DB18B48BD494A5798406
+BD74B5D1631C2844DE39ABECFC6518C45A89E117D7C498348FAB6C512DE91210
+1C07826D1D6131AFC8B138B595641D80C8753C45ABA3EA94D2B175F382508B1D
+B85D1133FAB93F41187C9399ECA60142A1356B1E5CFD821108C347CEA7ADBF08
+0B124290E9D736E2043039D49D7D297ECF51BB2D2A9BF589761AB8C1E7249722
+BB558C01661AFF993684BEEBD24DA09D0184440581B53FF4BF3C0129422E8F94
+F214FD0FE66F14DE284435437600C6B9CBB80CF7CBD3CECB34757BAC210DA30A
+2DE252E3DE81792D101F032EFD210853B4D37CCAF643D71C4733C81202D5212E
+4E75DE6E19A3F1905A22B668DEED9A8BCABC2365A1B2C6DA539FFC709B85038F
+99A65DE1C6782F0C757D402F59F11968695061FD1EB1293BD54FC33E1C2CA4BB
+AEA897043AA9FE619649D835D131E18DF17A9D1ED6163BBA1A9DD12B9BB42A74
+F67DEBE8DAED8AEA55A7F022159138F97FF379566A42354358FD09DC88FA9EAA
+5CF2ED8B4D13C1339C07D398E96D0287FFCECA5C5C32218BB43BFE08196D3D1E
+23973D34833CD9BACE28436A5FFD4816542473B7CEAAE489D7FC0F5012BCE6F8
+4D28102E67187E50603942FE7514770BB9157E67F1459F77B2D8FBAAE9A4C987
+295D1DACC6AD96A0818C9E875FEB5354BC2A1D28E2A1F45C8628D8D5B0C58651
+5083D10F070C42724CB17BD93D598ACE9762EB5060E2687FF9EFB1F58A95A5CA
+1AF7B72010131F0618EF48E9BFD21C17B297812190CC427B569313B025C39843
+57E25E37934EA128680771B49E7A3F1978B3A6238EA54D83CFB84EC2A296791E
+3990AC7AA99A9A5EC4A560E59F27DE1680C81E5930C136A83E8E7B4ACE6AAAB5
+57DFB10D605F501081A8808BBE3F6E297A90F5E09A3CDF26FC387399EF4D5C70
+E7A3E9AD46B0305E86DA98263A7F44357D4E950A63D7BEEB9D2E3DF3D066A6B7
+9E940CC10E8007B2CEA1C11521D2095EED15F3152F92B10E0B4E9AB74138F241
+4303245DED32F590E1FA35275F2A0A26FC74F9A04F1CE9280B9A5F136644B77E
+9F4A7CD818309F8FF436B07EECB4E6D4168501F32B348446AB6D693C81FBA667
+80FCA9390E36759B14F7A406E66F7BFE7E91BCD495A53097E55EEAD39F8A89DC
+FB4CFB345F075FA37C763528DCC7D80FAD8F674B107E60FA76597DE95BAEB3C9
+A3BA95633F1A44F20A2679BAC5D867A8ADE1270B3A87CF973424372BAF552056
+C9C37ED61E8A791D32997F15AA52A1F259FD02267DD7F43A218224DA371093A2
+2945C99A06AE36A43107BEA63FE56A9A2FC0EFDB46DF08C2752AF493035A5595
+EA90BD9847126368DF8E22FE380E50A893FB21914E78BAED3AE5F9F03F7027DC
+D10B91264F4459B8D0136A8C4139C416C64E304128104B6EBB0F3978C69FBF5B
+E090B5C295B98578A79FAD2AF4233821A08C375DF4C4429C93623C43907B99D4
+527E67CE7A73786E4D2F817A612AAC7B4D9E3F4A79BF382F15008DE76A9A8DF3
+47C60F100B09D971EC4690B1A04173A1CB66A2269BE80708FC29D82C552151CC
+385F1F179889059D5D70D252C99D0F84D12FDC13FFDFADC11A731262BC8E2AAC
+FD8FA176352F9D114322CAAC7278113C9B48C869D5EACE4215CD50A125EFAC99
+88312CF4E12FC1DA63029140E8EB1BFE1D79A7A338BA2188B599A1C224A0FBA1
+3CF40EFC11D7D3333FF371DED67318D2F6DC8B5F34A5728233AC9BB2EF214D67
+B3F2D0FDAA10F2C932F7AAC4EF557E31909175A3F61B0804CA0C762C53F20A83
+53A8A6FFC37E002EFC441614A8E540921635FE855CBF1338431AC8F66FB1E17E
+6770C99ACCE479A366F00211F8915AEF2940F44E43FBDAB05FE2D64565BD2584
+59F65129BD9695C4787C6CEF7FBA70E2E0FE4FB7051F65AA824782F9887E5F96
+DF2527C15E39CD1D5BDDD48765BC0C528037F69F8C5F168810DFC2D974AA0E62
+20104E3F291DB79BFE816FAAC5765BA298797EA491EF82AF07769675D60F4E4D
+F088426BF9CF41B0DF5D840BEA5ACFB5382015DD26ABB0851AC610B12553BBD1
+788032FDFAF98C64AF5E2FD0B08FDB9582CDBCCFDA38F256930349697AF7566D
+F980076F5E072279EF92BE37DB65AC1D702B0E85C856482A8BA9B44CC43BF3EB
+BB7504F1F2696B597A0FB8085E3F6E3BF178837363F750679CF2CCF7B01027F8
+747E1DA4597C8F93CE8F07D304FA72C64972CF08CD8B8F3331285EB0ECEDF8B0
+64B53AD633C6D90340797802DFB81D424DB73D68BADB7811765D83C2C57E3BAB
+F543E327CB8B0356D4A84CA1BF0AAAD57FB9EA0E5C70090A04745C916A3EA2E9
+2AEFBFC64AECCA2DDA387A3A8AE1D27C6B031A28E8FB3F871576BBBBF7217CB5
+4ECD354B391D4661B278B1DAD9B3AA0F39883F31537E158075D73A5C4D37FAD0
+4181846C724986DA122D84914611B7C50DC964E21B40ECBCDE2FBCCA5A30E11C
+5AF792173E502843DB785CD34583FF25251C712087589EA26D73257EB7B9D484
+72FCB8988317B1F886C5EB9791F4688F087DC8D2D0B82B5EC38CC026C45C406F
+F0BDC2C47011AAAFC765C2E520BF3C90C85E0D4AD3D59E75585FA2AD70B3C527
+2383D7582779217F435224718C04EC8467BA8C9319F99F3F033B148B24CA80C8
+C2A35C0B3BB874DE6AA03D3DBED072A45DBC5C8A746F83ABB578F872D535EC21
+D16BE93537193CD36DFCAA9BC9FA95033EECDB3853532452385A71D1E92D12A3
+9AE044E7142F0911125B2C2C881678886AA4E924B5718172A3161C790E2E6F04
+9A28709CB38269D8D460A8415E68F64D6BD3C9ED9D9744DB7AE04B9F19B8DB63
+EF85CEF8DA88F8442E2AC150FDD3A15BCF9740CAE7FFA1DE92E2571CF2C0E0F6
+90F13F5ECB3CB88FE13D4B8963B51ABFB9040A25ACC10B08166441D7275106C7
+D5F58C5A80F4F5472181D985237B431B8DED88BFBE1215B6DB506B7838A26C4E
+C129AADF9C36C4177C76930CF6008104E0B5E3A387A13CBBBB8109AEA38FC35B
+E7DF40B4734AAF9A7CB819D94DFE944E994DD21EE7E9BC4014BA7F0A1FD7C098
+6F7A699E77867DA25507D723B6CF9174782B58AB59D89BAE119F145D61F83687
+2C2A1653B501E71415A0978D2FF39468686E2481CE4F06B981FC398F93555A87
+E93A098C9FF28BDCBAF0637CD63BEE7FA448538FACC04B11C068A16E687BAF4B
+5D722363F7E1EF39B8DDCE5C947DC2A69DF4A4FCF40C397FB446A37E74502E49
+571846E8951AED1102A7B67B7038EA1C7ED210A077D83222E988C0E5D2B88BF2
+C71DF6C9F4400104F2E8DEA364D3A45CA1C1E6651C3972E89E5CF31881322FFE
+AED481E2602E19D31A735C14F3C7A8D585C46ABF0C5C64BDD64EDD35D0ACF67A
+5C91C26E2D53C47EEE126FCCAC1F7E9A67A0A02DBAC2C3EDFC15F55DD73EE385
+A7A32431AE18BD4F2C612FD5F5AF4380A259C0C38D22FEEE403A7B9CCC4EF62A
+6CCFE803F270AA5FB5C4DF8419CCBF6AC611A721688ED51B82C1E5647F2B988E
+2B84B5343C26D8495A23908A6EAB2D2376DB03F96D493A892B6548E0369988CA
+A2ABCECD47663BFE45F4F3F910952056A5314843DBF4A8862ECF20B9C6427E86
+E90CF8132B2A03E1A0109C2C1973B5830B9AADC952F41D92EC44FA3E79C77155
+AD89D10EA1E3B30126889BA190C86ADD788045D0F933226A4AC2FF91A9406F6F
+976F337400FF3921D372AD11C929109E7F2D7C2A494888CD85BD790C8119681D
+83B11275991898106C693C0EDF1C19B8731A84A94470D2BF52F0123E5BB89E56
+39D5CCA023BF0625DA16DE7DB7611108CEA00E3CD4B8C03F31787EE00A94B542
+A88B4369139836FAFCFDA51CDD5ACCD351C567663F1140357C1414E3301174F9
+0FAAF917EC9C19DDA2F41C671B3175F49DA30593FA6C93A067560053822D9A9D
+0A440C3DE6C4422E0EB2F7E86082F7734BA83D02C30EDA9A22354D1DCBC8D186
+6A43BF3DDC5209DD661A87CEDF97BA43262C6D418DAFFD943846120FC5E1A06A
+5C7D847154E41CDBE66B0538189C130DC4094D7F1709F15460AA982DC438F380
+766D6937A65D1E01B70FC903E2D906FC31448FEBDB937051BD538019D849F81D
+9C28FD74ADCA7996C9F319EA011A00AD195FFB5149F1B0B550ACB239D6D161A9
+E45FC9F9018F471885D62869831C55EBC118920B864BE49244DAE14794EACD02
+A096A5D16B4800B0A1AF3EAD075EA2476743425FE2214BDE468A20749C6FA35C
+9CAC2363798D17891339B28F8BB6D0BE628DB425FAE39D65D3C034D041BBF7CF
+4EF74A6AB6F656144930C034E57F02C528E054F65828BDE71083109F43FAF0FF
+E520EB4BF5D92932BDE44D54797E58DFAFCBF5C819474A7B9282D087F819AFA7
+F13B47F2CDD0BDDA2D8ABE8D6A0886407EB8550B96844FEE859BB61C799975C7
+056361974EBA586DB2D3DDC859CFA0FF493C5C8DA81B2673AE6C94CAEECE4B0B
+498E9F060E9948D0CB5C47040265075BBF6B40382EC26C5822DF3632F1F24973
+DE14BBECF72DD8535F05BF15276DBCD457432FDA386EA8131FE695CF61F11B37
+1C917751B54637348823C481D4C2B0DD4C98671BF1EB42919C6E11554D86490B
+8E2823073B9F1DB5B04EE262840352032E1B9E4B688FCFB1144E43BFE455AE25
+F914AD37E6A694900C5CEA010A04631BA180B9D126989E46566101B868EF178B
+6BDE396797925C90780A1840369DD3F7AFA7C6A2D46FFC8024B12C356D5FEEA7
+9270B37CD936AF7AA2F041836B00D3DA2F190F4E8C97FB7E9903446F8847BE6D
+32A1772991AB24ADD997BB3B97452F21A25591459AA9F15A0B5395DE1D23B038
+07D3B35338E4BA1214570B83D730F9FE2F0C0695A331B8E391D1FD879FA2174D
+3F83FCAE5E1441C51B7CC7AE625CE6F6EE29604FAFF1DD5C1FFA48599AA073E4
+E54E56028BD64FDACB47C715566D193332542E7A45F27F87F9BD0E7CFEC8EDD0
+C604549AA0831EE8CA7C68A8A4A6549B1E7C0BF2B6EEA70AFE13024C41557568
+D11E69C2F8D7962F5FFB6367016D93125A92DA39E25F30D5E4B85F66D34B0528
+DCD0D71BB767B7EC0A58272DBB90D0D0D0F661B783F724929CAAD9843E044752
+C5D1F2F6DBA6CBC67410623EC23D7C7EF15B18484315CEA679FC1526B576F54E
+D1DFDD0E8ED5F2B1449A05501D0110DB989F62F815A30E84BCB0042A0FA14855
+77D07A326FA8F2B85E67E20935F9DF0068B107572BA80DCFFD90F922B79A85C9
+821363FF5AD881CF7C0212B2E6238B49813FEDCE319FC0FE40A42797235DFCA2
+0F1B939645B97D26A23CC5D1ED56CA253AA1E5C8E88E93C74F410835E3D5C2C9
+731649584619ECCBF3A50F95DD7EF36A8C1B5F63222863F0D8223CB787B88027
+54835558B8E4CD6FA1BD7E4024B6C7267C1266AE9E7D7CACD4448342BEDE1EA2
+717FD60DE846878BA67710AF4508F33E2D8D1827B7AD0A8C94531079BF2550BB
+87B73A3848857F32B5D7AF2CC07DF0590D6090B7D820D701E669ACA06BA8F194
+02672D01ECD7E2BD4E29FE18176D8317BF9523D2900B7CCACE98E9B46DEDE394
+0CB3B65538418147C93E77FADEB94B66FD048E47A0F1C3BC92A51633F83E68EE
+D239C0F2F5EB9EC68A048EB809B5B9F2DFE41F815CD33623CC2F6AA0C06C9F53
+ADF903E40B50945A7A288A016839EBA12CA78156F617ECF3BFC8AC106A0B1CD9
+9E2474C0DE1B88B5B18117CC68187DF5EF78C5B1AAE36D39946EEE1D931E704A
+9D0A315054F5362FDE90A0C04F159F93715B4082554A6FBBC03AC4C2BB6E3A33
+8563FB20B664A350BE0CED555FF8DCF2AEF4FADEE74A09522BC31CF7E4FFA014
+DCA45475437866FAD01AAC47DA6951197066B69E6E850D4076C0F8B3F04355B0
+E26711458BA45DA22AB577B6D71C8697816ACCDCA0C59E1BD92FA8C730D09863
+ACFA216600EEE43FC54E9BBBCB873C64D0C9FE41DDCC573AEDA8A699F780950E
+A63B8EA80A78E89724BC77DE5F7ED67FA860EE16D7E847FCFC198CFACF6FD4F5
+7A25146DD526769E6A4080E908C16F7CEB0EBEC4778A6A888414FD67BC2593FA
+6D0111E37BE74CA96748A43A7345622CEDA9D1DD5482E8119DBA73E73A35FA0D
+ADA16A14CDDB54D76DE1D407BB39C00AB23EA1CECAC9C4DBD64DB5AEC80AC9D7
+FAB6A1A3C4CA84F630A8D3A143A3490818A7BF0C8F16F6220BBEC2B8CCD528A3
+4A5F899039BB3E21B9554E3BD873E2C1DAE37F0700B43CD1939CE5D16773520E
+7A915895E74BB21222996FB5623FC6F077F44AAB49FD6E8B6AE3C8A9A93DA0C3
+445FCFA9EC73F98378C5B4EF3E67978B7FED5FED1EDA85BBD4D0108D3E059E63
+28E11EC677315B68DD63C517853C1A65967BF1B859A9203DBC2F03C4AF6A20AA
+E17C7103917CDB42303D88E4A1997B34201FCC208C941249624D039D069C2977
+B28AB8D215B245CC115024E3FD2ACB74184C8548DCE81F4D65D4CE268E360C03
+FB719F335050EFE6B13EAB0B9580437C6067F0251660588FB519409390F94326
+97C1C7A485E28C199DFB746BFD1CECE61C6F66D20946A54D9F05CC7F14BC7BE5
+9F0C229CD87F1A35D1AB547EBE307B0A5CB61F8E7661DFE503FF2EB3344EF7B1
+FED24165DAC30B5B6F39D1D1FA414A19E7FFEFCDF93808EDD4493AFDCA0BE31D
+03EC07BBF75FFF1654E5D3AA64DAA505454A499E398C2F53DCB93BF548451764
+3E4D7004D97DEA315CB51588F654CDF6FEABADA788D6DCABAC86E3DC9BB7E42B
+FBC1381C47277801E353B58400F9B9AA4DE2E1BF4E6433688C8569182F0F4568
+6D5E7931C695A5CC181A815B3D3252AFE7F25EAFCD8B07FB7B127731A25D951F
+51506723A896F8DA4027296D11DD4123FE93BCC81914409D2E6381F1F2840852
+4214BDD7C2671B85AB24BF24F895E67A91DF23E21C5663797F049467329F3DB0
+A74763B8C6458A5C9FF1157F9DD08C37351A6F074E1E5A05F9827AC15FFF4A68
+93E1D010E02D82B63C1661BBF9113D415052C4C5070E6542E5E07223745355F7
+3DD76EDECF1C5328A29473B07BDEB0D4223C5D3DAA6BF3E639C2FF860AADA0EF
+05A9BBEAABD8389112937B0F282A0D6C50A7CFFB0D214523EB8618583DF0EFBB
+D98086ABDF5EC23F57F1101E86AFFD2CE314B4240380C6FFBE4530E6576180C2
+3A3695E4D70DAC730C2057578AA0CF3E8E464500C0F2C7ADFADCB41E1DB62D83
+86DAD27D800C797B01D3A701C62A3A1D0E1C18D76CEE1AC9F581CC1C697A6E50
+62053E7EB21754BA9D9763654CD7FC08B53A12408A4CD4B99F4061C41FD06922
+ADCD8518DFA056B825A24965B576EF1DE31E3A4E2E54AEFBAFC8BDF5E833AE8C
+929405416A91A45AF0977E396ACE32C969C87FC93DEA7888A35B7C9E8ECCC350
+C9388F9953925A208E63514E9BCBDB99BD47D146DE4EEF08810C81DD6DC06EBB
+DC1F0035A6DA0D99F32696E8B4A226435376E26C0ADC8846D28C8B875BD03663
+73592B3FB5D5A0C927140F27B6CFC0FE2A8DBDC77CBEE70C0E2005EBBAFB8BD0
+5B24447CEC27AD4225DB0DC1CBBBE69AE423F9622A4A8BBD9466962FB54B64AE
+726060F18B3EC8D945009E8FB6C2ECA462758A78BE369F00AA4FB8534468F700
+A9376FB42130ED96EF9DA17B7B9589474D1427D0D8FF5152F6306527B12D4329
+3CF929105E04AF564DE552C4F06B466F16A8724945CDA9E098AB31A032CB2D05
+BBC3CD225A51D818A9695D6E32DA429E702632B32FECC25722652F67165695E6
+D9819D5B200EB3626FAE8FF7376DED2B1720CABD8AE2BC1A0A39B7BA427BCEFA
+936F934DC88685CAAC7DE19929C9F99984CA938BE0044FB341AED41B19F97F41
+2C31E2C4DB232FF90BC0D15F1991DB60E7E944D90F7FF591136E1F260D3764C8
+8BA791589D455192A19ECEB8A9E80FB5506A479EE444322C4E8E8FF0DD9BCB8F
+749C69C488E816625DF57EF673DB1A85BFB19D960461EA8E6718A1325D878D37
+FC7BC693F15D8A85AAF4C42216490BEA3D1638BE006CA2EC9D4DDEBE3C641754
+A78F6EB4B71D7517351A91A711CEE1FFC4FD57B0EF71E2959EAF82AB5494234D
+FAAB49B1EC4DA7A2F3657458CC1CF6229901C2AF5339E2E36F92197762A8E446
+5F8F9D24A57B80850DE4264FA9F23C947C35801C2B557CFF02B15637D5B9B059
+9994ACD938E826E4DAAF9581A63EE82995E793ADE573CB2B9628BD7B899A1C1F
+D437749137278A36B921206B70495E0DF379B7B7315FC02058EAC7F9128A3B4A
+30E20BCFEEE17A99CFC9795F193E4356AEF6DB94A7CAC8880FAC9227A0BF78D8
+B7BC18F6DAC8E5CBA63996CFD5E4F78461AFECE7EF62C585B5E5DD40789AEAD2
+597E24874B3BA77799D67DF746E70FC9DA4CCD9BF40F9897092352B3A12682E9
+4A5A92795C8B52E212FBE7323349E867ED8FE78B8B42325C6AD4BEC036BC891F
+0AFDCBDA2A75DB64EDD020A39A4AF0387B68D64BFED1C5FC11C58919C6FA0C96
+F617CA7860D5C10188376F31F1E323A95AB36138D4C8AEABFFF46CB6A3618ED2
+88C3BEC6184BDC2522388424FCAC44EC1DCF68E6B0A19B01A223BD7193EED9C3
+F5B838BE944E6C4CFEE7742EEFCCCF9F60EF632849E3306B990B2CA74B8F6AF3
+465A0BF22E1E59798302338B06682323B19C4E44FEFE84C0A210031F132E015E
+E74264B3B0DA6E09E116572E707C45FE7010C8D291BE49657248E416B4F244F6
+E557295AC3633C4B84B5638EDA1B2767D0FD770654C2667EBE9494B1DC28825E
+C12B1244900CF0F45EDD038BD90A98497250F897F1221A1733DBD4540D1B374F
+827C8C10FA84F5A1F6A4C921426BCD3EAFB1B8C654131F15B4BA3E8D489F00EA
+9BCECF58E9D15BFC1B16E4A08F0D5459D26559144278DD721DAC117E4C0F6EE3
+19930DF91DEDD9664287F11ADAD823DBAB597729C554DA905BC72A6686481108
+7FA7B78D41FFEDE9830955C6309749DE1ABD705BD346019D4ABC4C340C9A2A9D
+CA7D20D6CEB59E8B7836043C49D33C86469D27CA62851DBB00E6B8F4E28714C4
+B5F277CC2CFF502F0E47352F296EE242318D73197E754E4620A9B7DBD075C93E
+5225C68C47BAC50FCB58A6D33E1B55A39D131DBDD4E014C126DD320293BA9748
+4712E66FBBA2BA24BC8F4B1A285AA123F7B8146F4684CD922EBD333A7B493CE4
+F9C7BDE8FEC45429EC26DF8569130F0898C3D43F7CA90C210B103117911B27C1
+A14E0068595867748609ED646B5E08485E7467C36A528C738C1B7CFA362CA720
+C088CB808926A1D895DDFA944468AB702AA7F91D8A4BFA372E6D7640A8E24273
+75C1C8466DA13AC7BC57CC6ADAEC27CDCCB29BFA5473CED983B9E2EC94132E18
+6D77798D59EDAA1BA98A0618A1066374D655D55066BCF81FAB2E4511E1928ED7
+C77FB148D57D8EA24EE0720AB527AA3A76285B696FD2FF3546901E849A5B3802
+F21F7205C80F9A4A102DFE192C5C5A5403C6A8AE106C10746A550F7CDFC992DB
+E3A64BE4A2726AF22D403EAD6AC921F48D6535E9E850BEC1E5B0AC79AF04502A
+1FBD5043391104C6DD0B09CAA3654A7A21A52D6164FA2E7A4FDBE9CB328C3A53
+05406F4A2F45A1FD4B2CF998E94B7DAF2E3CB584A8AD83CB32844979EA560E0F
+6EB5215F705141320F1BAF1504E210D3690FBC58830BACA500624F7A7ED3EEA2
+789738814E197DAAF6DA815029368B28818561F044171ADDCB73B6DE459C3E9B
+64196B66F8A12A1BE100124EF86CAB8B7A10822DF4951766AF568D826E0B91E5
+E640EB8D3D8B188912C510D456231E46972B177019A807DA6AE89E76400E82B4
+EF3EC27BCD8F879A5A7A04BB4D5E290514EF7ED3A976A5B2D5B4F9359B283DE1
+1D7BFB356B3F3F02BB45FA93F0B442330A9AA29F8680260D1071BC27829EA312
+0ED69BFF2730E0F550F35CF2CF16AEC7D8CFDECE336F95789FA1C76B4C6BECB4
+D6400166ECB6FA2A44C587F15DD55F55A1F7FFD8F07CA99EDD2052218828B191
+D52CFD56538ECE62E946AF57C39CDAED30DE6FE58491181ED84E700092A061BC
+821B6A5C32A0F436DA74826E0790EBC7D55F14223DDA0234680D41A5BAC55EBD
+8D657911A3C10F9537AC9D3388EBBD5856F043A544AF4E60CA7243DA6D38BB28
+4646E77BF92BFA763150C7E4543E844B01097CEA61AF0CA802CD8055BEDD63C0
+6D91EE700452A400496DCAB0632DBC58C5285E8722F9BEB4860842B48B1D9FAE
+B266B6381548CA943B5EEF047A6805D99AF761A42AA6850CC458E1C147E3ACC4
+E41653EE36F6BF8C938DF808E8DF9220690A1E36BF5C7924DE8944C261955F25
+A7976C3FF10C79A10D8EACBEE51C00E961588131E35B08BD2B07962EF33769D8
+8A7FA9BA8EA90C38B846963030FB463511992396C25B4F83D6E6842BB7408064
+B979DF1E0A1C20719C8F9430C1F46B36DAD548471A37B4328DDA480F3274900C
+E33879F1C6AE71A76437DA0F6712297CE10B14552768C06315EB48500514BC14
+AD86EF94E5AE2390B6D9ABC097BF1A9CB666988EC3797A3464930867433F7F95
+D26D8DED9791F0C49EE8AEB9017CCBA02B4B68D639B58C864EAD6067B3D1FD22
+E989551D11DB9BF2A8D833391D25109F007D9E3F7ECDE5F21C64AAE0B0D4C4CC
+C511D9E7251286551308E976F1C69422457B9F6544A768188EC36C7964D158C5
+09ED5CF20C62955EEBFB0C4A851943CB1BEDEFC216A5F11051C9074C8971A13C
+59EF979D9C6C90E545E7569F16A202E0488548C6AAD14AA2D3F5C15E5807F39A
+00752DDE0B2537CEF6F67A921342CD30B85CD65841BA2B92156F2ABA110F9193
+1D8F5C3E7BC15D1F2A1B45FC37DA6EB07B9D77EC0C8F507F49599A3CFFA76C0F
+4EE4037576BE710FD8D22424899D80D389FF23B8760FFDCB88B5BBB17345D278
+42286B59AFC25036261678551AF7CB98432D66CB6C49E3ABE73B47B0568839B0
+9820B34D98B0B2312CE07F438A94F7DC4C5D50066AF6FC3399BB9D58AF4E4F7B
+8271B178FB44B6C9A286FF4925C920DBC35D5AF5E24B60C5637C4D1343312EE2
+FA5625B6AD5ED764EA7D670761365EFDB46FB8153E23072885C3225ED394EFAE
+6B319D543ABA7005821D8B857D06235F83FED9697FDB48074BE3E797D96811F0
+10BC6392B1B9D4A896B3993C0A77E94B57CBBE264C12463687BCEAE30C575B1E
+16DE09B2D92E58155BC5AF9339C62F48DC0C66831B7F519B236A7F1AD6E2EF6C
+7216A0304F415B8C95E46AC28A0C2EED00A5E22B193338BA67F78735D8C26F7A
+994D25DD5FBD72BD3B1DCA1E2B0F7151439313824FA3811C01FEDE345439CC7D
+604ED31A684426939CB3F2B9DB05D509A7B0EAAB0583662991FC3ADB4C50A515
+3B881A40DB960A9D6226C4B8BE7DE1CE38363BBF3537A68E269787913EF43FE0
+AEFBCFA0C199AD0337F48564CCA04DBB0442A4C8BC13B0072BE782817F59C8D7
+4A052705029F8986F888C498825819171C12E4CD2A33BEF7FAFC3447FB5CE42B
+B3BC34F3F2B61E0E43048E32522CE84FBFD8B7E36F9C83320D5C8692AED52588
+A2359603E13A2F2E43B310D433B83713F94D77557C9C8EFBA9B5E5419B75BE5C
+25E87490EFF8A2C54734079826AC3CC2B77B982F3D11141FEA98B417603EFE94
+240F453DD6E62737EFCD0A104ED9009B009C4A62A2188A7FAAA0778F36E3CC25
+D3E6D192B338E69B6C6A63ECB42EB981B08D2B65646EBF09DBCE03940135D76A
+E22D04BA3C8293534A9BEC2969B54A12B346AD976FACA36C07376C9A8F2A198E
+BF0BE85F63EE43845F761274E0D9CB7531C451516EF085BDF6A02833E38B8B87
+D141D8C9F39F6F032880A6E39022707C2D318613A800E1F5A312B300115EF120
+744D58CFF4C7BD46757945D541C1349225F2C0BB4ED39A2457B7D8E3DBE1C5D1
+D150794D5EB2081B8F4C13F73ED220A7FCF5E2DAB5CD77926FB66CE3063A21DB
+1B76BDC2C8B2AA374B9F362404AA707E3E4751848540E83B712DEA3423FE49B6
+0AE4D96AAFCB9D6198918EF460E585BBC2A37B3318643CECF4D3F865E14692D9
+74267716BA6CC117B13CF185717F6FA0C8602041CE79E696CCA1FECA4AA4CD31
+A06916B369B7FAEA1F66AE081DF3D44236F012C557C8076772576CB116783153
+C2DEAB8CD542F0B08C75E00AC57C816B372E20C2660374BF09AC498FB3AC9A3E
+1BE52953FA41686599DC7213845478725D54DA531A0375CEC8BA1827C27DBAFD
+6555A364CD1AEDA1A5DB57
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: CMR12
+%!PS-AdobeFont-1.1: CMR12 1.0
+%%CreationDate: 1991 Aug 20 16:38:05
+% Copyright (C) 1997 American Mathematical Society. All Rights Reserved.
+11 dict begin
+/FontInfo 7 dict dup begin
+/version (1.0) readonly def
+/Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def
+/FullName (CMR12) readonly def
+/FamilyName (Computer Modern) readonly def
+/Weight (Medium) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+end readonly def
+/FontName /CMR12 def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 46 /period put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 77 /M put
+dup 86 /V put
+dup 97 /a put
+dup 101 /e put
+dup 105 /i put
+dup 110 /n put
+dup 111 /o put
+dup 114 /r put
+dup 115 /s put
+dup 121 /y put
+readonly def
+/FontBBox{-34 -251 988 750}readonly def
+currentdict end
+currentfile eexec
+D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891
+016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171
+9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F
+D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758
+469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8
+2BDBF16FBC7512FAA308A093FE5CF4E9D2405B169CD5365D6ECED5D768D66D6C
+68618B8C482B341F8CA38E9BB9BAFCFAAD9C2F3FD033B62690986ED43D9C9361
+3645B82392D5CAE11A7CB49D7E2E82DCD485CBA04C77322EB2E6A79D73DC194E
+59C120A2DABB9BF72E2CF256DD6EB54EECBA588101ABD933B57CE8A3A0D16B28
+51D7494F73096DF53BDC66BBF896B587DF9643317D5F610CD9088F9849126F23
+DDE030F7B277DD99055C8B119CAE9C99158AC4E150CDFC2C66ED92EBB4CC092A
+AA078CE16247A1335AD332DAA950D20395A7384C33FF72EAA31A5B89766E635F
+45C4C068AD7EE867398F0381B07CB94D29FF097D59FF9961D195A948E3D87C31
+821E9295A56D21875B41988F7A16A1587050C3C71B4E4355BB37F255D6B237CE
+96F25467F70FA19E0F85785FF49068949CCC79F2F8AE57D5F79BB9C5CF5EED5D
+9857B9967D9B96CDCF73D5D65FF75AFABB66734018BAE264597220C89FD17379
+26764A9302D078B4EB0E29178C878FD61007EEA2DDB119AE88C57ECFEF4B71E4
+140A34951DDC3568A84CC92371A789021A103A1A347050FDA6ECF7903F67D213
+1D0C7C474A9053866E9C88E65E6932BA87A73686EAB0019389F84D159809C498
+1E7A30ED942EB211B00DBFF5BCC720F4E276C3339B31B6EABBB078430E6A09BB
+377D3061A20B1EB98796B8607EECBC699445EAA866C38E02DF59F5EDD378303A
+0733B90E7835C0AAF32BA04F1566D8161EA89CD4D14DDB953F8B910BFC8A7F03
+5020F55EF8FC2640ADADA156F6CF8F2EB6610F7EE8874A26CBE7CD154469B9F4
+ED76886B3FB679FFDEB59BB6C55AF7087BA48B75EE2FB374B19BCC421A963E15
+FE05ECAAF9EECDF4B2715010A320102E6F8CCAA342FA11532671CEBFCF38BC60
+5BF06A0E01053B7F105ED5140FA4FA37A4F45ABFB58DD41780629C7FA7594F8E
+9488B074D45BA0E761190A94DBFF4CF204D5812EB1DFBC0C456D6A044C558945
+8DF6D6AF8A51131AB5913EF2544E475F489FE776FA45E7C0EB62096CF4517450
+8A57DD2B80EF97DBD17036EB9B73FCB82DC4F671BCFEF06A6F86189A2012F53C
+E518466A9385D08942279391EF5C2B3567F2E53B2148AAA0625BDB358ECD2C9B
+730A59F8DF70FD3E09378E24AEE772A69C96E09C0D0703350A75F3843DEDD822
+B364988376CE8027EF12F0453575AE9AE46296E13925BACECA8B8808DA388222
+BA35B431F56BC3C349B8CA6D4AB83664A991FED51478BFE25B0399B54EF27B18
+65E2E39E57DFC5F57371FB4643D7EC0AD41840CA7C682EE7A1B4FE3E06E40238
+B07A2E7A7FB3F35502F1CCA283F9420F2FAB9EC0A8C8982BF4AFE69A3D2690B3
+CF5DB716B3CB9936C49A12944973F14C2D9A368E4067BDBF91E413A3321B3BFA
+B84463D3C680604A4C4E4B49D0F9F9B59D5B68ECD3891FEEDE9B29B9C432212D
+82505A8D423BA734A53DEB930A392BA6011C6EA6EBA7ABAA6AAC003721FB34A6
+1544EEE16F6AD73E6C5743EFF09975C186A9C769A4732F78AA09218AE576FB14
+70E1697B813AC1B09FFAB762678BA9320043C256766AF1BACD3702CED1228B94
+57E353589810F99AF74109EFDA0740CB0475DE7870AA7218120462B23441BB1A
+60ACAF3B8B171E7509854D1C05C8FBF62979D2B52030B4C91F9D038EF26F2C11
+346D0E9955B491C3168E030B9CCE2964883B824F0DCF27EECA6C6E0478CF6B36
+AF2D33C9265A5F8D76FCC46AA30E6093E3822CE70C1ED22CDB8A8F910F5BCF45
+2C9D2D41B342B43DB5FE5EFCFEB5D378F78684296CAED9A39FC3834929073B6E
+A934014457B89A61253E0924D3C6BB4FE4ADFBD0C9B3C61D08E3DB2B26785A1D
+3B5E0E23258AE12276B63E9D79B2EAB305B8108A0987216C0EBF033A839BF611
+CB208A9B3B26699B201DD3662676B77C66EAFD20FAEB3021619FC123433D1CAE
+53B0EDF00827F374A95DA1E89A01226DB951EC0F09366357A5A86C4DA2AD2A5A
+0CCCB8304C4CDB9CDBA1068E98B2CCD4671E960ED12921F7B41100ABD48768C1
+BD5863591593D6ED9E604857B67D08C0CBE36A2E3D2EF5A9451345693A2F2FC1
+617F954916295D06A6A0805CA62EF2DAB67BC449674B238CCFAB92D628617FDB
+9B3BA7FEE1FF29E7BB9CD5FEAB8F27E592B511CCFF9FDF4271CEF44F73CAA97A
+30DDA0FE944A6C4B23D82797C4D2B53BE303031FC99A32D20F03D840E42BD088
+143E95C4E0CDA56BF86846A476E84C1ACC34A64C3A1EBC0A2B53380DEAB37DAB
+692D21B1C485FD1D08080F8F3909C512F013BC14572FF66CF1ED026E2E81B3D9
+091D0C7196E99F937B4C2FB4719E8ACE48810BFAC898677969B176250A019DA8
+27BE209FCC3A0CD35219C47CC18E771C0A8E49B03CF3DD19F4118287DBC7C4A2
+2B23D2250E0C97C4C6EF38AF4960BB4E8963DBC38A11ACE3B46E1A3A36799FAE
+3D53A874A1323CFBFF769064B7698CD5289E648D1B3968A48452362C9806DEA7
+D51B4C18267A88BE072D1C05B697417503C36206260DAFC1E4B989FDEA80FE19
+196EBF09046E43DD0138B1DFF846C34C7F14A126675BE530B671D23F3D5B4EF9
+9DE0484411942D59073707193132040B3786C02AF197A9520EF649BC55EAAFE1
+3F974A85D1FCA84BFE5B214F555C7F5F939977945559616160776D4369DBEE13
+0486617F2E364E8846175E02FE51D16728C08342DC1D8BC09C69A769E7165954
+A609FFD0174EA5236FE01BA8EF1BA4F43020C81683F9D83C7460A6B73650D81F
+840A5085455A0CBBD4C148F065433693096FA50A32823F9E9CFE73921FE7A89B
+4465255C2DE2722F176A410C0ABEC6619B7E5E2877B5F71DD65E1D83FD3AEBF1
+174CDEF7792366D9D8F965D7B894514552C8689AD98C3D47A5BDF0B62BE36A5E
+EC4FED48090B02FADADE831409D8A12BF26C59DCED4FAB2D855B0AADE1E1E92D
+7C12F644051C522C64DDC7D78663241BCD0077D29498143804A43C8D239B8240
+D27B1DC8264A08A7FD490BDB994C5F76175297570508141E3CA66C464E803F35
+3E203A80B56E0EF34C6CF7DF41E926F0B1C65C963E2EEFF7223D0F23C6637662
+8AD35E5E3DC3916E386945DE7F9459DEB136996E1DCD2C52EACD7EA23FEBD7FB
+B2EE5067521FB56F7AB6A3DD411866A469FE6BAED525316A9E397096CCD9AD60
+227ED9887B9E199242512AE8A30ADB1647CA80A3DAF4F37367EE3A2D6E10B10F
+20B04AADE3FB78AC92BDEFED7C7FEC071596FF33D00B9DF125BFD3E1A23F3E28
+06B1FB28E40FD8B9F7F56326F61D6F0ACC6B5BB5075FE00BF27D077531C87910
+7AC03290749574181B95B7968C79076CB25308FEC5F1D2E2D5EEE5EA026F841A
+E1D347FA7149FAB5C64EF67A2A17C885D51C665DE67793C9E0E025A9AEC6C958
+EFBDD6E9C13CDF596CC58E28E284F6FE9700505C5B0F5D85501EB8C8668AF610
+5FF15864D7DA8F3A06CBEA58045321141099EF4FB952F9EF8848AF3A722646A8
+74336EF9927DC3451C787C2760E768DF4AD19EF9FCC27057C4602193DA5CBAF6
+404BE06ED2FF9DE5FDE00A9F2488A4FC0CAB5CE4A5C7767BAC50F2C84ADB20A6
+D0DB2AC57A490F7D0290664FC560202C2DBB5911BE6018945FC455FCA992F301
+C93F454A189878A215CEB421930E0CA6BC0C48CD297980CBAF9283B8D973078C
+D40886E0C31CB1F44C36BFAC44CEA466011B72BC301552153893ABB2D2CB11B8
+AA14FB14B20E897D2A04D4B0643558B9247B8C9304286C4C26E8375258639E55
+8B004CD7B7CCE046DC730087543B0237A363C7A6B9A6D3CAB81310E2557CC57A
+D43F163D5D81ADB9EB797C88E685E0E11C88400E3B0106DB9B8637B361A4FE44
+B911AAE93675C201493B5F2B24FA53A5D40E2CB99727AEE3740A620531C377CC
+C9BF247FA8551E1B7AB95BA669C7EB321FE9950998496ECD49EB4131E352D217
+826587C051273B13878588F410EBB4C02820B8ECBA8FB7C860998B57FABE9C1F
+816B32CE914F150EBCDF989A257F79F76F3603C9F891C2349909C87BF56EC7E7
+E7017616EDCEBE98B60C0F678D3B0F1DC838FF0A543E6A094F82A15EAA55987C
+2A261E4CA71933EC92CBBCBB0E3F560659B6C3E402EBAF480B509892EC9242B6
+BFB23B9F70902A2AB6CCFED2E8FCA63DBC53244116C7612A94F198F36BA097C2
+7B63D740677C4B229AEF0256E6860F15FB800E60B522F9E70B0455D9C1871F22
+BDB77851B3885608E4FB1A8F830159DA098DE17C0EC61E54822DC61E21CD6C3B
+288884430EE3017B35E742553AD08A264B38A42F3EFA5A709AB46563FF56CBF8
+73909325C6AF397E9524997CFBFA89376D9997D8EA7009A7D4433A73FFC98D13
+DBEDB05B41908A6D74CE3E28F5ECA3D8
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+TeXDict begin 40258431 52099146 1000 600 600 (fitsio.dvi)
+@start /Fa 193[71 62[{}1 90.9091 /CMMI10 rf /Fb 133[50
+59 59 81 59 62 44 44 46 1[62 56 62 93 31 59 1[31 62 56
+34 51 62 50 62 54 9[116 85 86 78 62 84 1[77 84 88 106
+67 88 1[42 88 88 70 74 86 81 80 85 6[31 1[56 56 56 56
+56 56 56 56 1[56 31 37 32[62 12[{}58 99.6264 /CMBX12
+rf /Fc 149[25 2[45 45 86[45 15[{}4 90.9091 /CMSY10 rf
+/Fd 133[60 71 71 97 71 75 52 53 55 1[75 67 75 112 37
+71 1[37 75 67 41 61 75 60 75 65 9[139 102 103 94 75 100
+1[92 101 105 128 81 105 1[50 105 106 85 88 103 97 96
+102 6[37 67 67 67 67 67 67 67 67 67 67 67 37 45 3[52
+52 27[75 78 11[{}63 119.552 /CMBX12 rf /Fe 129[48 48
+48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
+48 48 48 48 48 48 48 48 48 48 1[48 48 48 48 48 48 48
+48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
+48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
+48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
+48 48 33[{}93 90.9091 /CMTT10 rf /Ff 139[75 1[79 1[108
+7[108 2[88 3[94 29[140 9[97 97 97 97 97 97 97 97 97 97
+48[{}17 172.188 /CMBX12 rf /Fg 165[56 68 68 93 68 68
+66 51 67 1[62 71 68 83 57 71 1[33 68 71 59 62 69 66 64
+68 6[25 45 45 45 45 45 45 45 45 45 45 45 25 30 45[{}38
+90.9091 /CMSL10 rf /Fh 134[55 55 1[55 58 41 41 43 1[58
+52 58 87 29 2[29 58 52 32 48 58 46 58 51 11[80 73 58
+78 1[71 79 82 4[40 1[82 66 69 80 76 74 79 7[52 52 52
+52 52 52 52 52 52 52 52 1[35 32[58 12[{}49 90.9091 /CMBX10
+rf /Fi 132[45 40 48 48 66 48 51 35 36 36 48 51 45 51
+76 25 48 28 25 51 45 28 40 51 40 51 45 25 2[25 45 25
+56 68 68 93 68 68 66 51 67 71 62 71 68 83 57 71 47 33
+68 71 59 62 69 66 64 68 71 43 43 71 25 25 25 45 45 45
+45 45 45 45 45 45 45 45 25 30 25 71 45 35 35 25 71 76
+45 76 45 25 18[76 51 51 53 11[{}93 90.9091 /CMR10 rf
+/Fj 134[62 5[46 46 2[59 65 4[33 3[52 3[59 10[88 8[107
+25[59 59 59 59 1[33 46[{}15 119.552 /CMR12 rf /Fk 138[90
+63 64 66 2[81 90 134 45 2[45 1[81 49 74 1[72 90 78 12[112
+90 2[110 6[60 2[101 4[122 65[{}21 143.462 /CMBX12 rf
+/Fl 134[123 123 1[123 129 90 92 95 1[129 116 129 194
+65 2[65 129 116 71 106 129 103 129 113 11[179 162 129
+173 1[159 175 182 4[87 1[183 146 153 178 168 165 175
+17[116 1[77 5[65 26[129 12[{}40 206.559 /CMBX12 rf end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+%%BeginPaperSize: Letter
+letter
+%%EndPaperSize
+ end
+%%EndSetup
+%%Page: 1 1
+TeXDict begin 1 0 bop 861 1940 a Fl(FITSIO)76 b(User's)g(Guide)356
+2399 y Fk(A)54 b(Subroutine)d(In)l(terface)i(to)g(FITS)h(F)-13
+b(ormat)54 b(Files)1055 2659 y(for)g(F)-13 b(ortran)53
+b(Programmers)1667 3155 y Fj(V)-10 b(ersion)38 b(3.0)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)h(Cen)m(ter)1522
+4396 y(Green)m(b)s(elt,)f(MD)h(20771)1857 4509 y(USA)1701
+5298 y Fj(Ma)m(y)39 b(2011)p eop end
+%%Page: 2 2
+TeXDict begin 2 1 bop 0 299 a Fi(ii)p eop end
+%%Page: 3 3
+TeXDict begin 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)31 b(the)f(Library)58 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)32 b(the)e(Library)j(.)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)31 b(Programs)f(with)g(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(8)136 2766 y(2.4)94 b(Getting)32 b(Started)f(with)f(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)31 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)32 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(.)85 b(10)136 3252 y(2.7)94
+b(Ac)m(kno)m(wledgmen)m(ts)30 b(.)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(10)0
+3511 y Fh(3)119 b(A)35 b(FITS)f(Primer)2918 b(13)0 3771
+y(4)84 b(FITSIO)34 b(Con)m(v)m(en)m(tions)h(and)g(Guidelines)1993
+b(15)136 3933 y Fi(4.1)94 b(CFITSIO)29 b(Size)i(Limitations)42
+b(.)k(.)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(Multiple)32 b(Access)f(to)g(the)g(Same)f(FITS)
+g(File)h(.)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(16)136
+4257 y(4.3)94 b(Curren)m(t)30 b(Header)h(Data)h(Unit)e(\(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(16)136 4419
+y(4.4)94 b(Subroutine)29 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(16)136
+4581 y(4.5)94 b(Subroutine)29 b(F)-8 b(amilies)33 b(and)c(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(17)136
+4742 y(4.6)94 b(Implicit)31 b(Data)h(T)m(yp)s(e)e(Con)m(v)m(ersion)65
+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(17)136 4904 y(4.7)94 b(Data)32 b(Scaling)89 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(18)136 5066 y(4.8)94 b(Error)30
+b(Status)g(V)-8 b(alues)32 b(and)d(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(18)136 5228 y(4.9)94 b(V)-8 b(ariable-Length)33
+b(Arra)m(y)d(F)-8 b(acilit)m(y)34 b(in)c(Binary)g(T)-8
+b(ables)26 b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(19)136 5390 y(4.10)49
+b(Supp)s(ort)29 b(for)h(IEEE)g(Sp)s(ecial)g(V)-8 b(alues)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(.)85 b(20)136
+5552 y(4.11)49 b(When)31 b(the)f(Final)h(Size)g(of)g(the)f(FITS)g(HDU)h
+(is)f(Unkno)m(wn)k(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f
+(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(21)136 5714 y(4.12)49
+b(Lo)s(cal)32 b(FITS)d(Con)m(v)m(en)m(tions)j(supp)s(orted)c(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(21)1912 5942 y(iii)p
+eop end
+%%Page: 4 4
+TeXDict begin 4 3 bop 0 299 a Fi(iv)3311 b Fg(CONTENTS)345
+555 y Fi(4.12.1)61 b(Supp)s(ort)29 b(for)h(Long)g(String)g(Keyw)m(ord)g
+(V)-8 b(alues.)62 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g
+(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(21)345 716 y(4.12.2)61
+b(Arra)m(ys)31 b(of)f(Fixed-Length)h(Strings)f(in)g(Binary)h(T)-8
+b(ables)70 b(.)46 b(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g
+(.)f(.)85 b(22)345 876 y(4.12.3)61 b(Keyw)m(ord)30 b(Units)h(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(23)345 1037 y(4.12.4)61 b(HIERAR)m(CH)31 b(Con)m(v)m(en)m(tion)h(for)
+e(Extended)g(Keyw)m(ord)g(Names)83 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)f(.)85 b(23)136 1197 y(4.13)49 b(Optimizing)31
+b(Co)s(de)f(for)g(Maxim)m(um)h(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(24)345 1358 y(4.13.1)61 b(Bac)m(kground)31
+b(Information:)41 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(25)345 1518
+y(4.13.2)61 b(Optimization)32 b(Strategies)69 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(25)0
+1771 y Fh(5)119 b(Basic)36 b(In)m(terface)e(Routines)2504
+b(29)136 1931 y Fi(5.1)94 b(FITSIO)30 b(Error)f(Status)h(Routines)84
+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(29)136 2092 y(5.2)94 b(File)32 b(I/O)e(Routines)e(.)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(30)136 2252 y(5.3)94 b(Keyw)m(ord)31 b(I/O)f(Routines)36
+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(32)136 2412 y(5.4)94 b(Data)32 b(I/O)f(Routines)53
+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(33)0 2665 y Fh(6)119 b(Adv)-6 b(anced)36
+b(In)m(terface)e(Subroutines)2159 b(35)136 2826 y Fi(6.1)94
+b(FITS)30 b(File)i(Op)s(en)d(and)g(Close)i(Subroutines:)76
+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(35)136 2986 y(6.2)94
+b(HDU-Lev)m(el)33 b(Op)s(erations)108 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(38)136 3146
+y(6.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(41)136 3307 y(6.4)94
+b(FITS)30 b(Header)h(I/O)f(Subroutines)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(43)345 3467 y(6.4.1)106
+b(Header)31 b(Space)g(and)f(P)m(osition)h(Routines)60
+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(43)345 3628 y(6.4.2)106
+b(Read)31 b(or)f(W)-8 b(rite)32 b(Standard)d(Header)i(Routines)67
+b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)
+h(.)g(.)f(.)85 b(43)345 3788 y(6.4.3)106 b(W)-8 b(rite)32
+b(Keyw)m(ord)e(Subroutines)116 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(45)345 3949 y(6.4.4)106 b(Insert)30 b(Keyw)m(ord)g(Subroutines)108
+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(47)345 4109
+y(6.4.5)106 b(Read)31 b(Keyw)m(ord)f(Subroutines)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(47)345 4270
+y(6.4.6)106 b(Mo)s(dify)30 b(Keyw)m(ord)h(Subroutines)55
+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(49)345 4430
+y(6.4.7)106 b(Up)s(date)31 b(Keyw)m(ord)f(Subroutines)116
+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(50)345 4591
+y(6.4.8)106 b(Delete)33 b(Keyw)m(ord)d(Subroutines)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(50)136 4751
+y(6.5)94 b(Data)32 b(Scaling)g(and)d(Unde\014ned)g(Pixel)i(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(51)136 4912 y(6.6)94
+b(FITS)30 b(Primary)g(Arra)m(y)h(or)f(IMA)m(GE)h(Extension)g(I/O)f
+(Subroutines)117 b(.)46 b(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f
+(.)85 b(52)136 5072 y(6.7)94 b(FITS)30 b(ASCI)s(I)f(and)h(Binary)g(T)-8
+b(able)31 b(Data)h(I/O)e(Subroutines)d(.)46 b(.)g(.)g(.)f(.)h(.)g(.)f
+(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(55)345
+5232 y(6.7.1)106 b(Column)30 b(Information)g(Subroutines)121
+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(55)345 5393 y(6.7.2)106
+b(Lo)m(w-Lev)m(el)33 b(T)-8 b(able)31 b(Access)g(Subroutines)60
+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(58)345 5553 y(6.7.3)106
+b(Edit)31 b(Ro)m(ws)f(or)h(Columns)106 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(58)345 5714 y(6.7.4)106 b(Read)31
+b(and)f(W)-8 b(rite)31 b(Column)f(Data)i(Routines)66
+b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)f(.)85 b(60)p eop end
+%%Page: 5 5
+TeXDict begin 5 4 bop 0 299 a Fg(CONTENTS)3334 b Fi(v)136
+555 y(6.8)94 b(Ro)m(w)31 b(Selection)h(and)e(Calculator)i(Routines)95
+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(64)136 717 y(6.9)94
+b(Celestial)33 b(Co)s(ordinate)d(System)g(Subroutines)98
+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(65)136 879 y(6.10)49
+b(File)32 b(Chec)m(ksum)e(Subroutines)75 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(67)136 1041 y(6.11)80
+b(Date)32 b(and)d(Time)i(Utilit)m(y)h(Routines)69 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(68)136
+1204 y(6.12)49 b(General)32 b(Utilit)m(y)g(Subroutines)61
+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(69)0 1464 y Fh(7)119 b(The)35 b(CFITSIO)e(Iterator)g(F)-9
+b(unction)2154 b(75)0 1725 y(8)119 b(Extended)35 b(File)f(Name)h(Syn)m
+(tax)2330 b(77)136 1887 y Fi(8.1)94 b(Ov)m(erview)84
+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(77)136 2049 y(8.2)94
+b(Filet)m(yp)s(e)62 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(80)345 2211 y(8.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(80)345
+2373 y(8.2.2)106 b(Notes)32 b(ab)s(out)e(the)h(stream)f(\014let)m(yp)s
+(e)h(driv)m(er)54 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(81)345 2536
+y(8.2.3)106 b(Notes)32 b(ab)s(out)e(the)h(gsiftp)f(\014let)m(yp)s(e)83
+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(82)345 2698
+y(8.2.4)106 b(Notes)32 b(ab)s(out)e(the)h(ro)s(ot)f(\014let)m(yp)s(e)68
+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 2860
+y(8.2.5)106 b(Notes)32 b(ab)s(out)e(the)h(shmem)e(\014let)m(yp)s(e:)70
+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(84)136 3022 y(8.3)94
+b(Base)32 b(Filename)90 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(84)136
+3184 y(8.4)94 b(Output)30 b(File)h(Name)g(when)f(Op)s(ening)f(an)h
+(Existing)h(File)81 b(.)45 b(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)
+f(.)h(.)g(.)f(.)h(.)g(.)f(.)85 b(86)136 3346 y(8.5)94
+b(T)-8 b(emplate)32 b(File)g(Name)f(when)e(Creating)i(a)g(New)f(File)57
+b(.)46 b(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)f(.)h(.)g(.)g(.)f(.)h(.)g(.)
+f(.)h(.)g(.)f(.)85 b(88)136 3508 y(8.6)94 b(Image)32
+b(Tile-Compression)e(Sp)s(eci\014cation)91 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(88)136 3670 y(8.7)94 b(HDU)32 b(Lo)s(cation)f(Sp)s
+(eci\014cation)47 b(.)e(.)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(88)136 3832 y(8.8)94 b(Image)32 b(Section)39
+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(89)136 3994 y(8.9)94 b(Image)32
+b(T)-8 b(ransform)29 b(Filters)54 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(90)136 4156 y(8.10)49
+b(Column)30 b(and)g(Keyw)m(ord)g(Filtering)h(Sp)s(eci\014cation)91
+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(92)136 4318 y(8.11)49 b(Ro)m(w)31
+b(Filtering)h(Sp)s(eci\014cation)82 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(94)345 4481 y(8.11.1)61
+b(General)32 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(94)345 4643 y(8.11.2)61
+b(Bit)32 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(97)345 4805 y(8.11.3)61
+b(V)-8 b(ector)32 b(Columns)92 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(98)345 4967 y(8.11.4)61
+b(Go)s(o)s(d)30 b(Time)h(In)m(terv)-5 b(al)31 b(Filtering)62
+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(99)345 5129
+y(8.11.5)61 b(Spatial)31 b(Region)h(Filtering)59 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(100)345
+5291 y(8.11.6)61 b(Example)31 b(Ro)m(w)g(Filters)h(.)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(103)136 5453 y(8.12)80 b(Binning)30 b(or)g(Histogramming)i(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(104)0
+5714 y Fh(9)84 b(T)-9 b(emplate)35 b(Files)2933 b(107)p
+eop end
+%%Page: 6 6
+TeXDict begin 6 5 bop 0 299 a Fi(vi)3311 b Fg(CONTENTS)136
+555 y Fi(9.1)94 b(Detailed)33 b(T)-8 b(emplate)31 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(107)136 715 y(9.2)94 b(Auto-indexing)31 b(of)g(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(108)136 876 y(9.3)94 b(T)-8 b(emplate)32 b(P)m(arser)f(Directiv)m(es)
+87 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(109)136 1036 y(9.4)94 b(F)-8 b(ormal)32 b(T)-8 b(emplate)32
+b(Syn)m(tax)i(.)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(109)136 1196 y(9.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(.)40 b(110)136 1356 y(9.6)94
+b(Examples)72 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(110)0
+1607 y Fh(10)67 b(Summary)36 b(of)f(all)f(FITSIO)g(User-In)m(terface)h
+(Subroutines)1215 b(113)0 1858 y(11)67 b(P)m(arameter)35
+b(De\014nitions)2563 b(121)0 2109 y(12)67 b(FITSIO)33
+b(Error)i(Status)g(Co)s(des)2295 b(127)p eop end
+%%Page: 1 7
+TeXDict begin 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)33 b(do)s(cumen)m(t)i
+(describ)s(es)e(the)h(F)-8 b(ortran-callable)38 b(subroutine)33
+b(in)m(terface)j(that)f(is)f(pro)m(vided)g(as)g(part)g(of)h(the)0
+2293 y(CFITSIO)f(library)h(\(whic)m(h)h(is)g(written)g(in)f(ANSI)g
+(C\).)h(This)f(is)h(a)g(companion)g(do)s(cumen)m(t)f(to)i(the)e
+(CFITSIO)0 2406 y(User's)k(Guide)f(whic)m(h)h(should)e(b)s(e)h
+(consulted)h(for)f(further)g(information)h(ab)s(out)f(the)h(underlying)
+e(CFITSIO)0 2518 y(library)-8 b(.)50 b(In)32 b(the)i(remainder)f(of)g
+(this)h(do)s(cumen)m(t,)g(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)j(a)f(mac)m(hine-indep)
+s(enden)m(t)g(library)g(of)h(routines)f(for)g(reading)h(and)f(writing)g
+(data)h(\014les)0 2904 y(in)c(the)g(FITS)g(\(Flexible)i(Image)f(T)-8
+b(ransp)s(ort)29 b(System\))h(data)h(format.)41 b(It)31
+b(can)f(also)h(read)g(IRAF)f(format)h(image)0 3017 y(\014les)40
+b(and)e(ra)m(w)i(binary)f(data)h(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)g(FITS)f(format)h
+(\014le.)0 3130 y(This)32 b(library)h(w)m(as)g(written)g(to)h(pro)m
+(vide)f(a)h(p)s(o)m(w)m(erful)f(y)m(et)h(simple)f(in)m(terface)h(for)f
+(accessing)i(FITS)d(\014les)h(whic)m(h)0 3243 y(will)j(run)e(on)h(most)
+h(commonly)g(used)e(computers)h(and)g(w)m(orkstations.)57
+b(FITSIO)34 b(supp)s(orts)g(all)i(the)g(features)0 3356
+y(describ)s(ed)21 b(in)i(the)f(o\016cial)i(NOST)e(de\014nition)g(of)h
+(the)f(FITS)g(format)h(and)f(can)h(read)f(and)g(write)h(all)g(the)g
+(curren)m(tly)0 3469 y(de\014ned)40 b(t)m(yp)s(es)h(of)g(extensions,)j
+(including)d(ASCI)s(I)e(tables)j(\(T)-8 b(ABLE\),)42
+b(Binary)f(tables)h(\(BINT)-8 b(ABLE\))43 b(and)0 3582
+y(IMA)m(GE)36 b(extensions.)56 b(The)34 b(FITSIO)g(subroutines)g
+(insulate)i(the)f(programmer)g(from)g(ha)m(ving)h(to)g(deal)f(with)0
+3695 y(the)25 b(complicated)h(formatting)g(details)f(in)f(the)h(FITS)f
+(\014le,)i(ho)m(w)m(ev)m(er,)i(it)d(is)f(assumed)g(that)h(users)f(ha)m
+(v)m(e)i(a)f(general)0 3808 y(kno)m(wledge)31 b(ab)s(out)f(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)i(dev)m
+(elop)s(ed)e(b)m(y)f(the)h(HEASAR)m(C)g(\(High)h(Energy)e(Astroph)m
+(ysics)h(Science)0 4081 y(Arc)m(hiv)m(e)35 b(Researc)m(h)g(Cen)m(ter\))
+f(at)h(the)f(NASA)g(Go)s(ddard)e(Space)j(Fligh)m(t)g(Cen)m(ter)f(to)h
+(con)m(v)m(ert)g(v)-5 b(arious)34 b(existing)0 4194 y(and)25
+b(newly)h(acquired)g(astronomical)i(data)e(sets)h(in)m(to)g(FITS)e
+(format)h(and)f(to)i(further)e(analyze)i(data)g(already)f(in)0
+4307 y(FITS)h(format.)41 b(New)28 b(features)g(con)m(tin)m(ue)h(to)g(b)
+s(e)e(added)h(to)g(CFITSIO)f(in)g(large)i(part)f(due)g(to)g(con)m
+(tributions)h(of)0 4419 y(ideas)k(or)g(actual)h(co)s(de)f(from)f(users)
+g(of)h(the)g(pac)m(k)-5 b(age.)49 b(The)33 b(In)m(tegral)h(Science)f
+(Data)h(Cen)m(ter)f(in)g(Switzerland,)0 4532 y(and)g(the)g(XMM/ESTEC)h
+(pro)5 b(ject)34 b(in)f(The)g(Netherlands)g(made)g(esp)s(ecially)i
+(signi\014can)m(t)f(con)m(tributions)g(that)0 4645 y(resulted)c(in)g
+(man)m(y)h(of)f(the)h(new)f(features)g(that)h(app)s(eared)f(in)g(v2.0)i
+(of)e(CFITSIO.)0 4805 y(The)22 b(latest)i(v)m(ersion)f(of)g(the)f
+(CFITSIO)f(source)i(co)s(de,)h(do)s(cumen)m(tation,)i(and)21
+b(example)j(programs)e(are)h(a)m(v)-5 b(ailable)0 4918
+y(on)30 b(the)h(W)-8 b(orld-Wide)32 b(W)-8 b(eb)31 b(or)f(via)h(anon)m
+(ymous)f(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 end
+%%Page: 2 8
+TeXDict begin 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,)g(bug)f
+(rep)s(orts,)h(or)f(suggested)i(enhancemen)m(ts)f(related)g(to)h(the)e
+(CFITSIO)f(pac)m(k)-5 b(age)30 b(should)d(b)s(e)0 668
+y(sen)m(t)k(to)g(the)g(primary)e(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
+(William.D.Pence@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)40 b(User's)i(Guide)f(assumes)g(that)h(readers)f(already)g
+(ha)m(v)m(e)i(a)f(general)g(understanding)d(of)j(the)f(de\014nition)0
+1639 y(and)31 b(structure)g(of)h(FITS)e(format)i(\014les.)44
+b(F)-8 b(urther)32 b(information)f(ab)s(out)h(FITS)f(formats)g(is)h(a)m
+(v)-5 b(ailable)34 b(from)d(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,)i(the)f('NOST)f(FITS)g(Standard')0 1865
+y(giv)m(es)j(the)g(authoritativ)m(e)h(de\014nition)e(of)g(the)g(FITS)g
+(data)h(format,)g(and)f(the)g(`FITS)g(User's)g(Guide')g(pro)m(vides)0
+1978 y(additional)d(historical)h(bac)m(kground)e(and)g(practical)i
+(advice)f(on)f(using)g(FITS)g(\014les.)0 2138 y(CFITSIO)j(users)g(ma)m
+(y)h(also)h(b)s(e)f(in)m(terested)h(in)f(the)g(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)k(and)e(analyze)j(FITS)e(format)g(\014les.)59
+b(Information)36 b(ab)s(out)g(FTOOLS)f(can)i(b)s(e)f(obtained)g(on)h
+(the)0 2364 y(W)-8 b(eb)31 b(or)f(via)h(anon)m(ymous)g(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 end
+%%Page: 3 9
+TeXDict begin 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)f(one)j(m)m(ust)e(\014rst)g(build)g
+(the)h(CFITSIO)f(library)-8 b(,)46 b(whic)m(h)d(requires)f(a)h(C)0
+2580 y(compiler.)73 b(gcc)43 b(is)e(ideal,)j(or)d(most)h(other)f
+(ANSI-C)g(compilers)g(will)h(also)g(w)m(ork.)73 b(The)40
+b(CFITSIO)g(co)s(de)h(is)0 2692 y(con)m(tained)25 b(in)f(ab)s(out)f(40)
+i(C)f(source)g(\014les)f(\(*.c\))j(and)d(header)h(\014les)g(\(*.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)f(\(vmsieeed.mar)h(and)f(vmsieeer.mar\))h
+(are)g(also)g(needed.)0 2965 y(The)45 b(F)-8 b(ortran)46
+b(in)m(terface)g(subroutines)e(to)i(the)f(C)g(CFITSIO)f(routines)h(are)
+g(lo)s(cated)i(in)e(the)g(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.)38
+b(These)22 b(are)h(relativ)m(ely)i(simple)d('wrapp)s(ers')f(that)i
+(translate)h(the)f(argumen)m(ts)g(in)f(the)0 3191 y(F)-8
+b(ortran)26 b(subroutine)e(in)m(to)j(the)e(appropriate)h(format)g(for)f
+(the)g(corresp)s(onding)g(C)g(routine.)39 b(This)24 b(translation)j(is)
+0 3304 y(p)s(erformed)19 b(transparen)m(tly)i(to)g(the)g(user)f(b)m(y)g
+(a)h(set)h(of)e(C)h(macros)g(lo)s(cated)h(in)e(the)h(cfortran.h)f
+(\014le.)38 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)i(of)e(C)g(and)f(F)-8
+b(ortran)29 b(compilers)g(so)f(the)h(F)-8 b(ortran)28
+b(in)m(terface)0 3530 y(is)i(not)h(supp)s(orted)e(on)h(all)h
+(platforms.)41 b(\(see)31 b(further)e(notes)i(b)s(elo)m(w\).)0
+3690 y(A)f(standard)f(com)m(bination)j(of)e(C)f(and)h(F)-8
+b(ortran)30 b(compilers)h(will)f(b)s(e)f(assumed)h(b)m(y)f(default,)i
+(but)e(one)h(ma)m(y)h(also)0 3803 y(sp)s(ecify)f(a)h(particular)f(F)-8
+b(ortran)32 b(compiler)e(b)m(y)h(doing:)48 4064 y Fe(>)95
+b(setenv)46 b(CFLAGS)g(-DcompilerName=1)0 4324 y Fi(\(where)33
+b('compilerName')h(is)f(the)g(name)f(of)h(the)g(compiler\))h(b)s(efore)
+e(running)f(the)i(con\014gure)f(command.)47 b(The)0 4437
+y(curren)m(tly)30 b(recognized)i(compiler)f(names)f(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 end
+%%Page: 4 10
+TeXDict begin 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 1609 y Fi(Alternativ)m(ely)-8 b(,)42
+b(one)c(ma)m(y)g(edit)g(the)f(CFLA)m(GS)h(line)f(in)h(the)f(Mak)m
+(e\014le)i(to)f(add)f(the)h('-DcompilerName')i(\015ag)0
+1722 y(after)31 b(running)e(the)h('./con\014gure')h(command.)0
+1882 y(The)f(CFITSIO)f(library)h(is)g(built)g(on)h(Unix)f(systems)g(b)m
+(y)g(t)m(yping:)48 2146 y Fe(>)95 b(./configure)45 b
+([--prefix=/target/insta)o(llat)o(ion)o(/pat)o(h])764
+2259 y([--enable-sse2])e([--enable-ssse3])48 2372 y(>)95
+b(make)476 b(\(or)95 b('make)46 b(shared'\))48 2485 y(>)95
+b(make)47 b(install)93 b(\(this)46 b(step)h(is)g(optional\))0
+2749 y Fi(at)24 b(the)g(op)s(erating)g(system)g(prompt.)38
+b(The)23 b(con\014gure)g(command)g(customizes)i(the)f(Mak)m(e\014le)h
+(for)f(the)g(particular)0 2861 y(system,)g(then)d(the)g(`mak)m(e')i
+(command)e(compiles)h(the)f(source)h(\014les)f(and)g(builds)f(the)h
+(library)-8 b(.)38 b(T)m(yp)s(e)21 b(`./con\014gure')0
+2974 y(and)34 b(not)h(simply)f(`con\014gure')h(to)h(ensure)e(that)h
+(the)g(con\014gure)g(script)f(in)h(the)g(curren)m(t)f(directory)h(is)g
+(run)f(and)0 3087 y(not)29 b(some)g(other)g(system-wide)g(con\014gure)f
+(script.)40 b(The)29 b(optional)h('pre\014x')e(argumen)m(t)h(to)g
+(con\014gure)g(giv)m(es)h(the)0 3200 y(path)e(to)i(the)f(directory)g
+(where)f(the)h(CFITSIO)f(library)g(and)g(include)h(\014les)f(should)g
+(b)s(e)g(installed)i(via)f(the)g(later)0 3313 y('mak)m(e)j(install')f
+(command.)41 b(F)-8 b(or)31 b(example,)143 3577 y Fe(>)48
+b(./configure)c(--prefix=/usr1/local)0 3841 y Fi(will)25
+b(cause)h(the)f('mak)m(e)h(install')g(command)f(to)h(cop)m(y)g(the)f
+(CFITSIO)e(lib)s(c\014tsio)i(\014le)h(to)f(/usr1/lo)s(cal/lib)i(and)e
+(the)0 3953 y(necessary)33 b(include)e(\014les)i(to)f(/usr1/lo)s
+(cal/include)j(\(assuming)d(of)g(course)g(that)h(the)f(pro)s(cess)g
+(has)g(p)s(ermission)0 4066 y(to)f(write)g(to)g(these)g(directories\).)
+0 4227 y(The)24 b(optional)i({enable-sse2)g(and)e({enable-ssse3)i
+(\015ags)e(will)h(cause)g(con\014gure)f(to)h(attempt)h(to)f(build)e
+(CFITSIO)0 4339 y(using)31 b(faster)h(b)m(yte-sw)m(apping)g
+(algorithms.)46 b(See)32 b(the)g("Optimizing)g(Programs")g(section)h
+(of)f(this)f(man)m(ual)h(for)0 4452 y(more)f(information)f(ab)s(out)g
+(these)h(options.)0 4613 y(By)37 b(default,)i(the)f(Mak)m(e\014le)g
+(will)g(b)s(e)e(con\014gured)g(to)i(build)e(the)h(set)h(of)f(F)-8
+b(ortran-callable)40 b(wrapp)s(er)35 b(routines)0 4725
+y(whose)30 b(calling)i(sequences)f(are)f(describ)s(ed)g(later)h(in)f
+(this)g(do)s(cumen)m(t.)0 4886 y(The)e('mak)m(e)h(shared')f(option)h
+(builds)e(a)i(shared)e(or)i(dynamic)f(v)m(ersion)h(of)f(the)h(CFITSIO)d
+(library)-8 b(.)40 b(When)28 b(using)0 4999 y(the)f(shared)f(library)h
+(the)g(executable)h(co)s(de)f(is)g(not)g(copied)g(in)m(to)h(y)m(our)f
+(program)g(at)g(link)g(time)g(and)g(instead)g(the)0 5111
+y(program)g(lo)s(cates)i(the)f(necessary)g(library)f(co)s(de)h(at)g
+(run)e(time,)j(normally)f(through)e(LD)p 3065 5111 28
+4 v 33 w(LIBRAR)-8 b(Y)p 3514 5111 V 34 w(P)g(A)g(TH)28
+b(or)0 5224 y(some)j(other)f(metho)s(d.)41 b(The)29 b(adv)-5
+b(an)m(tages)33 b(of)d(using)g(a)h(shared)e(library)h(are:)143
+5488 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 5601 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
+5714 y(library)f(is)h(running)f(at)h(the)g(same)g(time)f(since)h(the)g
+(system)f(is)h(smart)p eop end
+%%Page: 5 11
+TeXDict begin 5 10 bop 0 299 a Fg(2.1.)72 b(BUILDING)31
+b(THE)f(LIBRAR)-8 b(Y)2507 b Fi(5)334 555 y Fe(enough)46
+b(to)h(share)g(copies)f(of)h(the)g(shared)f(library)g(at)h(run)g(time.)
+143 668 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 781 y(library)f(can)h(be)g(installed)
+e(without)h(relinking)f(all)i(the)g(software)334 894
+y(that)g(uses)f(it)i(\(as)e(long)h(as)g(the)g(subroutine)e(names)i(and)
+f(calling)334 1007 y(sequences)f(remain)h(unchanged\).)143
+1120 y(4.)95 b(No)47 b(run-time)f(penalty.)0 1346 y Fi(The)30
+b(disadv)-5 b(an)m(tages)32 b(are:)143 1572 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 1685 y(specially)f(or)h(have)f
+(LD_LIBRARY_PATH)e(set)j(right.)143 1798 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 1911 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 2024 y(either)f(really)h(slow)f
+(or)h(really)f(heavily)g(loaded.)0 2250 y Fi(On)30 b(HP/UX)i(systems,)g
+(the)f(en)m(vironmen)m(t)h(v)-5 b(ariable)32 b(CFLA)m(GS)f(should)f(b)s
+(e)h(set)g(to)h(-Ae)g(b)s(efore)f(running)e(con-)0 2363
+y(\014gure)h(to)h(enable)g("extended)g(ANSI")f(features.)0
+2523 y(It)j(ma)m(y)g(not)g(b)s(e)f(p)s(ossible)g(to)h(statically)i
+(link)e(programs)f(that)h(use)g(CFITSIO)e(on)h(some)h(platforms)g
+(\(namely)-8 b(,)0 2636 y(on)28 b(Solaris)h(2.6\))h(due)e(to)h(the)g
+(net)m(w)m(ork)g(driv)m(ers)f(\(whic)m(h)h(pro)m(vide)g(FTP)f(and)g
+(HTTP)g(access)h(to)h(FITS)d(\014les\).)41 b(It)0 2749
+y(is)33 b(p)s(ossible)f(to)i(mak)m(e)f(b)s(oth)g(a)g(dynamic)f(and)g(a)
+i(static)g(v)m(ersion)f(of)g(the)g(CFITSIO)e(library)-8
+b(,)34 b(but)e(net)m(w)m(ork)i(\014le)0 2862 y(access)e(will)e(not)h(b)
+s(e)f(p)s(ossible)g(using)g(the)g(static)i(v)m(ersion.)0
+3022 y(On)c(V)-10 b(AX/VMS)31 b(and)d(ALPHA/VMS)i(systems)f(the)h(mak)m
+(e)p 2100 3022 28 4 v 34 w(g\015oat.com)h(command)e(\014le)g(ma)m(y)h
+(b)s(e)f(executed)h(to)0 3135 y(build)35 b(the)i(c\014tsio.olb)g(ob)5
+b(ject)37 b(library)f(using)g(the)g(default)h(G-\015oating)g(p)s(oin)m
+(t)g(option)f(for)g(double)g(v)-5 b(ariables.)0 3248
+y(The)37 b(mak)m(e)p 405 3248 V 33 w(d\015oat.com)i(and)d(mak)m(e)p
+1279 3248 V 34 w(ieee.com)j(\014les)f(ma)m(y)f(b)s(e)g(used)f(instead)i
+(to)g(build)e(the)h(library)g(with)g(the)0 3361 y(other)26
+b(\015oating)i(p)s(oin)m(t)e(options.)39 b(Note)28 b(that)f(the)f
+(getcwd)h(function)f(that)h(is)f(used)f(in)h(the)h(group.c)f(mo)s(dule)
+f(ma)m(y)0 3474 y(require)44 b(that)i(programs)e(using)g(CFITSIO)f(b)s
+(e)h(link)m(ed)i(with)e(the)h(ALPHA$LIBRAR)-8 b(Y:V)e(AX)m(CR)i(TL.OLB)
+0 3587 y(library)g(.)41 b(See)30 b(the)h(example)g(link)f(line)h(in)f
+(the)h(next)f(section)i(of)e(this)h(do)s(cumen)m(t.)0
+3747 y(On)25 b(Windo)m(ws)h(IBM-PC)g(t)m(yp)s(e)g(platforms)f(the)h
+(situation)h(is)e(more)h(complicated)i(b)s(ecause)d(of)h(the)g(wide)g
+(v)-5 b(ariet)m(y)0 3860 y(of)43 b(F)-8 b(ortran)43 b(compilers)h(that)
+f(are)g(a)m(v)-5 b(ailable)45 b(and)d(b)s(ecause)h(of)g(the)g(inheren)m
+(t)g(complexities)i(of)d(calling)j(the)0 3973 y(CFITSIO)25
+b(C)g(routines)h(from)g(F)-8 b(ortran.)40 b(Tw)m(o)26
+b(di\013eren)m(t)h(v)m(ersions)f(of)g(the)h(CFITSIO)d(dll)i(library)g
+(are)g(a)m(v)-5 b(ailable,)0 4085 y(compiled)28 b(with)e(the)i(Borland)
+f(C++)f(compiler)i(and)e(the)i(Microsoft)g(Visual)g(C++)e(compiler,)i
+(resp)s(ectiv)m(ely)-8 b(,)30 b(in)0 4198 y(the)g(\014les)g(c\014tsio)s
+(dll)p 679 4198 V 33 w(2xxx)p 901 4198 V 34 w(b)s(orland.zip)f(and)g
+(c\014tsio)s(dll)p 1924 4198 V 33 w(3xxx)p 2146 4198
+V 33 w(v)m(cc.zip,)j(where)e('3xxx')h(represen)m(ts)f(the)g(curren)m(t)
+0 4311 y(release)44 b(n)m(um)m(b)s(er.)76 b(Both)43 b(these)g(dll)g
+(libraries)g(con)m(tain)h(a)f(set)g(of)f(F)-8 b(ortran)44
+b(wrapp)s(er)d(routines)h(whic)m(h)g(ma)m(y)0 4424 y(b)s(e)37
+b(compatible)i(with)e(some,)j(but)d(probably)g(not)g(all,)k(a)m(v)-5
+b(ailable)40 b(F)-8 b(ortran)38 b(compilers.)63 b(T)-8
+b(o)38 b(test)g(if)g(they)g(are)0 4537 y(compatible,)29
+b(compile)f(the)f(program)g(testf77.f)h(and)f(try)f(linking)i(to)f
+(these)h(dll)e(libraries.)40 b(If)27 b(these)g(libraries)g(do)0
+4650 y(not)i(w)m(ork)g(with)f(a)h(particular)g(F)-8 b(ortran)30
+b(compiler,)g(then)e(there)h(are)g(2)g(p)s(ossible)g(solutions.)40
+b(The)28 b(\014rst)g(solution)0 4763 y(w)m(ould)h(b)s(e)h(to)g(mo)s
+(dify)f(the)h(\014le)f(cfortran.h)h(for)f(that)i(particular)f(com)m
+(bination)h(of)f(C)f(and)g(F)-8 b(ortran)30 b(compilers,)0
+4876 y(and)k(then)g(rebuild)f(the)i(CFITSIO)d(dll)j(library)-8
+b(.)52 b(This)34 b(will)h(require,)g(ho)m(w)m(ev)m(er,)i(a)e(some)f
+(exp)s(ertise)h(in)f(mixed)0 4989 y(language)e(programming.)40
+b(The)30 b(other)h(solution)f(is)h(to)g(use)f(the)g(older)h(v5.03)h(F)
+-8 b(ortran-77)32 b(implemen)m(tation)g(of)0 5102 y(FITSIO)25
+b(that)h(is)g(still)h(a)m(v)-5 b(ailable)28 b(from)d(the)h(FITSIO)f(w)m
+(eb-site.)40 b(This)25 b(v)m(ersion)h(is)g(no)g(longer)g(supp)s(orted,)
+f(but)g(it)0 5215 y(do)s(es)k(pro)m(vide)h(the)g(basic)h(functions)e
+(for)g(reading)h(and)f(writing)h(FITS)f(\014les)h(and)f(should)g(b)s(e)
+g(compatible)i(with)0 5327 y(most)g(F)-8 b(ortran)31
+b(compilers.)0 5488 y(CFITSIO)e(has)h(curren)m(tly)g(b)s(een)g(tested)h
+(on)f(the)h(follo)m(wing)h(platforms:)95 5714 y Fe(OPERATING)46
+b(SYSTEM)523 b(COMPILER)p eop end
+%%Page: 6 12
+TeXDict begin 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(Sun)47 b(OS)1002 b(gcc)47 b(and)g(cc)g(\(3.0.1\))143
+668 y(Sun)g(Solaris)762 b(gcc)47 b(and)g(cc)143 781 y(Silicon)f
+(Graphics)g(IRIX)285 b(gcc)47 b(and)g(cc)143 894 y(Silicon)f(Graphics)g
+(IRIX64)189 b(MIPS)143 1007 y(Dec)47 b(Alpha)f(OSF/1)572
+b(gcc)47 b(and)g(cc)143 1120 y(DECstation)93 b(Ultrix)428
+b(gcc)143 1233 y(Dec)47 b(Alpha)f(OpenVMS)476 b(cc)143
+1346 y(DEC)47 b(VAX/VMS)762 b(gcc)47 b(and)g(cc)143 1458
+y(HP-UX)1049 b(gcc)143 1571 y(IBM)47 b(AIX)954 b(gcc)143
+1684 y(Linux)1049 b(gcc)143 1797 y(MkLinux)953 b(DR3)143
+1910 y(Windows)46 b(95/98/NT)523 b(Borland)46 b(C++)h(V4.5)143
+2023 y(Windows)f(95/98/NT/ME/XP)235 b(Microsoft/Compaq)43
+b(Visual)j(C++)h(v5.0,)g(v6.0)143 2136 y(Windows)f(95/98/NT)523
+b(Cygwin)46 b(gcc)143 2249 y(OS/2)1097 b(gcc)47 b(+)g(EMX)143
+2362 y(MacOS)g(7.1)f(or)i(greater)332 b(Metrowerks)45
+b(10.+)0 2591 y Fi(CFITSIO)26 b(will)j(probably)e(run)f(on)i(most)g
+(other)h(Unix)e(platforms.)40 b(Cra)m(y)28 b(sup)s(ercomputers)e(are)j
+(curren)m(tly)f(not)0 2704 y(supp)s(orted.)0 3033 y Fd(2.2)135
+b(T)-11 b(esting)46 b(the)f(Library)0 3283 y Fi(The)40
+b(CFITSIO)e(library)i(should)f(b)s(e)g(tested)i(b)m(y)f(building)f(and)
+g(running)g(the)h(testprog.c)h(program)f(that)h(is)0
+3396 y(included)30 b(with)g(the)g(release.)42 b(On)30
+b(Unix)g(systems)g(t)m(yp)s(e:)191 3625 y Fe(\045)47
+b(make)g(testprog)191 3738 y(\045)g(testprog)f(>)h(testprog.lis)191
+3850 y(\045)g(diff)g(testprog.lis)d(testprog.out)191
+3963 y(\045)j(cmp)g(testprog.fit)e(testprog.std)0 4192
+y Fi(On)30 b(VMS)g(systems,)g(\(assuming)h(cc)g(is)f(the)h(name)f(of)h
+(the)f(C)g(compiler)h(command\),)g(t)m(yp)s(e:)191 4421
+y Fe($)47 b(cc)h(testprog.c)191 4534 y($)f(link)g(testprog,)e
+(cfitsio/lib,)g(alpha$library:vaxcrtl/l)o(ib)191 4647
+y($)i(run)g(testprog)0 4876 y Fi(The)30 b(testprog)h(program)g(should)e
+(pro)s(duce)g(a)i(FITS)f(\014le)g(called)i(`testprog.\014t')g(that)f
+(is)f(iden)m(tical)j(to)e(the)f(`test-)0 4989 y(prog.std')25
+b(FITS)f(\014le)g(included)g(with)g(this)h(release.)40
+b(The)24 b(diagnostic)i(messages)g(\(whic)m(h)e(w)m(ere)h(pip)s(ed)f
+(to)h(the)g(\014le)0 5102 y(testprog.lis)h(in)e(the)h(Unix)f(example\))
+i(should)d(b)s(e)h(iden)m(tical)j(to)e(the)g(listing)g(con)m(tained)h
+(in)e(the)h(\014le)f(testprog.out.)0 5215 y(The)30 b('di\013)7
+b(')31 b(and)e('cmp')i(commands)f(sho)m(wn)g(ab)s(o)m(v)m(e)h(should)f
+(not)g(rep)s(ort)g(an)m(y)h(di\013erences)g(in)f(the)g(\014les.)41
+b(\(There)0 5328 y(ma)m(y)35 b(b)s(e)e(some)h(minor)g(formatting)g
+(di\013erences,)i(suc)m(h)d(as)i(the)f(presence)g(or)g(absence)g(of)g
+(leading)h(zeros,)h(or)e(3)0 5441 y(digit)d(exp)s(onen)m(ts)f(in)g(n)m
+(um)m(b)s(ers,)g(whic)m(h)g(can)g(b)s(e)g(ignored\).)0
+5601 y(The)f(F)-8 b(ortran)31 b(wrapp)s(ers)d(in)h(CFITSIO)f(ma)m(y)j
+(b)s(e)e(tested)h(with)g(the)g(testf77)h(program.)40
+b(On)29 b(Unix)h(systems)g(the)0 5714 y(fortran)g(compilation)i(and)e
+(link)g(command)g(ma)m(y)h(b)s(e)f(called)h('f77')h(or)e('g77',)j(dep)s
+(ending)c(on)h(the)g(system.)p eop end
+%%Page: 7 13
+TeXDict begin 7 12 bop 0 299 a Fg(2.2.)72 b(TESTING)29
+b(THE)h(LIBRAR)-8 b(Y)2555 b Fi(7)143 555 y Fe(\045)48
+b(f77)f(-o)g(testf77)f(testf77.f)f(-L.)i(-lcfitsio)e(-lnsl)h(-lsocket)
+48 668 y(or)143 781 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\))48 894 y(or)143
+1007 y(\045)h(f77)f(-o)g(testf77)f(testf77.f)f(-Wl,-L.)h(-lcfitsio)f
+(-lm)i(-lnsl)f(-lsocket)g(\(HP/UX\))48 1120 y(or)143
+1233 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 1458 y(\045)h(testf77)d
+(>)j(testf77.lis)143 1571 y(\045)g(diff)e(testf77.lis)f(testf77.out)143
+1684 y(\045)j(cmp)f(testf77.fit)d(testf77.std)0 1934
+y Fi(On)31 b(mac)m(hines)h(running)f(SUN)g(O/S,)h(F)-8
+b(ortran)33 b(programs)e(m)m(ust)h(b)s(e)f(compiled)h(with)g(the)g('-f)
+7 b(')32 b(option)h(to)f(force)0 2047 y(double)24 b(precision)g(v)-5
+b(ariables)25 b(to)g(b)s(e)e(aligned)i(on)f(8-b)m(yte)i(b)s(oundaries)c
+(to)j(mak)m(e)g(the)g(fortran-declared)f(v)-5 b(ariables)0
+2160 y(compatible)34 b(with)e(C.)g(A)h(similar)g(compiler)g(option)g
+(ma)m(y)g(b)s(e)f(required)g(on)g(other)h(platforms.)48
+b(F)-8 b(ailing)34 b(to)f(use)0 2273 y(this)26 b(option)g(ma)m(y)g
+(cause)h(the)f(program)f(to)i(crash)e(on)h(FITSIO)f(routines)g(that)i
+(read)f(or)f(write)h(double)g(precision)0 2386 y(v)-5
+b(ariables.)0 2546 y(On)27 b(Windo)m(ws)h(platforms,)g(linking)g(F)-8
+b(ortran)28 b(programs)f(with)h(a)g(C)f(library)g(often)h(dep)s(ends)e
+(on)i(the)g(particular)0 2659 y(compilers)40 b(in)m(v)m(olv)m(ed.)71
+b(Some)40 b(users)f(ha)m(v)m(e)i(found)d(the)i(follo)m(wing)i(commands)
+d(w)m(ork)h(when)f(using)g(the)h(In)m(tel)0 2772 y(F)-8
+b(ortran)31 b(compiler:)0 3022 y Fe(ifort)46 b(/libs.dll)g(cfitsio.lib)
+e(/MD)j(testf77.f)f(/Gm)0 3247 y(or)h(possibly,)0 3473
+y(ifort)f(/libs:dll)g(cfitsio.lib)e(/MD)j(/fpp)g
+(/extfpp:cfortran.h,fitsi)o(o.h)191 3586 y(/iface:cvf)e(testf77.f)0
+3836 y Fi(Also)32 b(note)h(that)f(on)g(some)g(systems)f(the)h(output)g
+(listing)g(of)g(the)g(testf77)h(program)f(ma)m(y)g(di\013er)f(sligh)m
+(tly)i(from)0 3949 y(the)f(testf77.std)i(template)g(if)e(leading)h
+(zeros)g(are)g(not)g(prin)m(ted)e(b)m(y)i(default)f(b)s(efore)g(the)g
+(decimal)i(p)s(oin)m(t)e(when)0 4062 y(using)e(F)h(format.)0
+4222 y(A)f(few)h(other)f(utilit)m(y)i(programs)e(are)h(included)e(with)
+h(CFITSIO:)191 4472 y Fe(speed)46 b(-)i(measures)d(the)i(maximum)f
+(throughput)f(\(in)i(MB)g(per)g(second\))668 4585 y(for)g(writing)f
+(and)h(reading)f(FITS)g(files)h(with)f(CFITSIO)191 4811
+y(listhead)f(-)j(lists)e(all)h(the)g(header)f(keywords)g(in)h(any)g
+(FITS)f(file)191 5036 y(fitscopy)f(-)j(copies)e(any)h(FITS)g(file)f
+(\(especially)f(useful)h(in)h(conjunction)811 5149 y(with)g(the)g
+(CFITSIO's)e(extended)h(input)g(filename)g(syntax\))191
+5375 y(cookbook)f(-)j(a)f(sample)f(program)g(that)h(performs)e(common)i
+(read)f(and)811 5488 y(write)h(operations)e(on)i(a)g(FITS)g(file.)191
+5714 y(iter_a,)f(iter_b,)g(iter_c)g(-)h(examples)f(of)h(the)g(CFITSIO)f
+(iterator)f(routine)p eop end
+%%Page: 8 14
+TeXDict begin 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(The)f(\014rst)f(4)i(of)g(these)g(utilit)m(y)g(programs)f(can)h(b)s
+(e)f(compiled)h(and)e(link)m(ed)i(b)m(y)f(t)m(yping)143
+816 y Fe(\045)95 b(make)47 b(program_name)0 1151 y Fd(2.3)135
+b(Linking)45 b(Programs)h(with)f(FITSIO)0 1402 y Fi(When)31
+b(linking)g(applications)i(soft)m(w)m(are)f(with)f(the)g(FITSIO)f
+(library)-8 b(,)32 b(sev)m(eral)h(system)e(libraries)g(usually)g(need)0
+1515 y(to)26 b(b)s(e)f(sp)s(eci\014ed)g(on)g(the)h(link)g(comman)f
+(Unix)h(systems,)h(the)e(most)h(reliable)h(w)m(a)m(y)f(to)h(determine)e
+(what)h(libraries)0 1627 y(are)32 b(required)f(is)g(to)i(t)m(yp)s(e)e
+('mak)m(e)i(testprog')g(and)e(see)h(what)f(libraries)h(the)g
+(con\014gure)f(script)h(has)f(added.)43 b(The)0 1740
+y(t)m(ypical)25 b(libraries)f(that)g(ma)m(y)g(need)f(to)h(b)s(e)f
+(added)g(are)g(-lm)h(\(the)g(math)f(library\))h(and)f(-lnsl)g(and)g
+(-lso)s(c)m(k)m(et)j(\(needed)0 1853 y(only)h(for)f(FTP)g(and)g(HTTP)g
+(\014le)h(access\).)41 b(These)26 b(latter)i(2)f(libraries)g(are)g(not)
+g(needed)f(on)g(VMS)h(and)f(Windo)m(ws)0 1966 y(platforms,)31
+b(b)s(ecause)f(FTP)g(\014le)h(access)g(is)g(not)f(curren)m(tly)h(supp)s
+(orted)d(on)i(those)h(platforms.)0 2126 y(Note)i(that)g(when)e
+(upgrading)g(to)i(a)f(new)m(er)g(v)m(ersion)g(of)g(CFITSIO)f(it)h(is)g
+(usually)g(necessary)g(to)h(recompile,)h(as)0 2239 y(w)m(ell)d(as)g
+(relink,)g(the)f(programs)g(that)h(use)f(CFITSIO,)f(b)s(ecause)i(the)f
+(de\014nitions)g(in)g(\014tsio.h)h(often)f(c)m(hange.)0
+2574 y Fd(2.4)135 b(Getting)46 b(Started)g(with)f(FITSIO)0
+2825 y Fi(In)32 b(order)h(to)h(e\013ectiv)m(ely)i(use)d(the)g(FITSIO)f
+(library)h(as)h(quic)m(kly)g(as)f(p)s(ossible,)h(it)g(is)f(recommended)
+g(that)g(new)0 2938 y(users)d(follo)m(w)h(these)g(steps:)0
+3098 y(1.)62 b(Read)38 b(the)f(follo)m(wing)i(`FITS)e(Primer')g(c)m
+(hapter)h(for)g(a)f(brief)g(o)m(v)m(erview)i(of)f(the)g(structure)e(of)
+i(FITS)f(\014les.)0 3211 y(This)25 b(is)h(esp)s(ecially)h(imp)s(ortan)m
+(t)g(for)e(users)h(who)f(ha)m(v)m(e)i(not)g(previously)e(dealt)i(with)f
+(the)g(FITS)f(table)i(and)f(image)0 3324 y(extensions.)0
+3484 y(2.)41 b(W)-8 b(rite)32 b(a)f(simple)f(program)g(to)h(read)g(or)f
+(write)g(a)h(FITS)f(\014le)g(using)g(the)h(Basic)g(In)m(terface)h
+(routines.)0 3644 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)f(included)f(with)g(this)h(release)h(for)e
+(examples)i(of)f(routines)f(that)0 3757 y(p)s(erform)h(v)-5
+b(arious)30 b(common)h(FITS)f(\014le)g(op)s(erations.)0
+3917 y(4.)52 b(Read)34 b(Chapters)g(4)g(and)f(5)i(to)g(b)s(ecome)f
+(familiar)h(with)e(the)i(con)m(v)m(en)m(tions)h(and)d(adv)-5
+b(anced)34 b(features)h(of)f(the)0 4030 y(FITSIO)29 b(in)m(terface.)0
+4190 y(5.)47 b(Scan)32 b(through)f(the)h(more)h(extensiv)m(e)g(set)g
+(of)g(routines)f(that)g(are)h(pro)m(vided)f(in)g(the)g(`Adv)-5
+b(anced)32 b(In)m(terface'.)0 4303 y(These)22 b(routines)f(p)s(erform)g
+(more)h(sp)s(ecialized)h(functions)e(than)g(are)i(pro)m(vided)e(b)m(y)h
+(the)g(Basic)h(In)m(terface)g(routines.)0 4638 y Fd(2.5)135
+b(Example)46 b(Program)0 4888 y Fi(The)32 b(follo)m(wing)i(listing)f
+(sho)m(ws)f(an)g(example)i(of)e(ho)m(w)h(to)g(use)f(the)g(FITSIO)g
+(routines)g(in)g(a)h(F)-8 b(ortran)33 b(program.)0 5001
+y(Refer)38 b(to)h(the)g(co)s(okb)s(o)s(ok.f)f(program)g(that)h(is)f
+(included)f(with)h(the)h(FITSIO)e(distribution)g(for)h(examples)h(of)0
+5114 y(other)31 b(FITS)e(programs.)286 5375 y Fe(program)46
+b(writeimage)0 5601 y(C)238 b(Create)46 b(a)i(FITS)f(primary)e(array)i
+(containing)e(a)i(2-D)g(image)p eop end
+%%Page: 9 15
+TeXDict begin 9 14 bop 0 299 a Fg(2.5.)72 b(EXAMPLE)31
+b(PR)m(OGRAM)2664 b Fi(9)286 555 y Fe(integer)46 b
+(status,unit,blocksize,bit)o(pix,)o(nax)o(is,n)o(axes)o(\(2\))286
+668 y(integer)g(i,j,group,fpixel,nelement)o(s,ar)o(ray)o(\(300)o(,200)o
+(\))286 781 y(character)g(filename*80)286 894 y(logical)g
+(simple,extend)286 1120 y(status=0)0 1233 y(C)238 b(Name)47
+b(of)g(the)g(FITS)g(file)f(to)i(be)f(created:)286 1346
+y(filename='ATESTFILE.FITS')0 1571 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 1684 y(call)g(ftgiou\(unit,status\))0 1910 y(C)238
+b(create)46 b(the)h(new)g(empty)g(FITS)f(file)286 2023
+y(blocksize=1)286 2136 y(call)h(ftinit\(unit,filename,blo)o(cksi)o
+(ze,s)o(tat)o(us\))0 2362 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
+2475 y(simple=.true.)286 2588 y(bitpix=16)286 2700 y(naxis=2)286
+2813 y(naxes\(1\)=300)286 2926 y(naxes\(2\)=200)286 3039
+y(extend=.true.)0 3265 y(C)238 b(write)47 b(the)g(required)e(header)h
+(keywords)286 3378 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 3604 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 3717 y(do)h(j=1,naxes\(2\))477 3830
+y(do)f(i=1,naxes\(1\))668 3942 y(array\(i,j\)=i+j)477
+4055 y(end)g(do)286 4168 y(end)g(do)0 4394 y(C)238 b(write)47
+b(the)g(array)f(to)h(the)g(FITS)g(file)286 4507 y(group=1)286
+4620 y(fpixel=1)286 4733 y(nelements=naxes\(1\)*naxes\(2)o(\))286
+4846 y(call)g(ftpprj\(unit,group,fpixel)o(,nel)o(emen)o(ts,)o(arra)o
+(y,st)o(atu)o(s\))0 5072 y(C)238 b(write)47 b(another)f(optional)f
+(keyword)h(to)h(the)g(header)286 5185 y(call)g
+(ftpkyj\(unit,'EXPOSURE',1)o(500,)o('Tot)o(al)41 b(Exposure)46
+b(Time',status\))0 5410 y(C)238 b(close)47 b(the)g(file)f(and)h(free)g
+(the)g(unit)f(number)286 5523 y(call)h(ftclos\(unit,)d(status\))286
+5636 y(call)j(ftfiou\(unit,)d(status\))p eop end
+%%Page: 10 16
+TeXDict begin 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)286 555
+y Fe(end)0 948 y Fd(2.6)135 b(Legal)46 b(Stu\013)0 1210
+y Fi(Cop)m(yrigh)m(t)37 b(\(Unpublished{all)g(righ)m(ts)g(reserv)m(ed)g
+(under)e(the)i(cop)m(yrigh)m(t)h(la)m(ws)f(of)g(the)g(United)g
+(States\),)j(U.S.)0 1323 y(Go)m(v)m(ernmen)m(t)30 b(as)g(represen)m
+(ted)e(b)m(y)h(the)g(Administrator)g(of)g(the)g(National)h(Aeronautics)
+g(and)e(Space)h(Adminis-)0 1436 y(tration.)42 b(No)31
+b(cop)m(yrigh)m(t)g(is)g(claimed)g(in)f(the)h(United)f(States)h(under)e
+(Title)j(17,)f(U.S.)f(Co)s(de.)0 1596 y(P)m(ermission)g(to)g(freely)f
+(use,)h(cop)m(y)-8 b(,)31 b(mo)s(dify)-8 b(,)29 b(and)g(distribute)g
+(this)g(soft)m(w)m(are)i(and)e(its)h(do)s(cumen)m(tation)g(without)0
+1709 y(fee)f(is)f(hereb)m(y)g(gran)m(ted,)i(pro)m(vided)e(that)h(this)f
+(cop)m(yrigh)m(t)i(notice)f(and)f(disclaimer)h(of)f(w)m(arran)m(t)m(y)i
+(app)s(ears)d(in)h(all)0 1822 y(copies.)0 1982 y(DISCLAIMER:)0
+2142 y(THE)33 b(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
+2255 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 2368 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 2481 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 2594 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
+2707 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 2819 y(SOFTW)-10 b(ARE)31 b(WILL)h(BE)g(ERR)m(OR)g
+(FREE.)g(IN)g(NO)g(EVENT)f(SHALL)g(NASA)h(BE)g(LIABLE)g(F)m(OR)g(ANY)0
+2932 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 3045 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
+3158 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 3271 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 3384 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 3497
+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 3610 y(VICES)29 b(PR)m(O)m(VIDED)j(HEREUNDER.")0
+4002 y Fd(2.7)135 b(Ac)l(kno)l(wledgmen)l(ts)0 4264 y
+Fi(The)29 b(dev)m(elopmen)m(t)h(of)g(man)m(y)f(of)h(the)f(p)s(o)m(w)m
+(erful)g(features)g(in)g(CFITSIO)f(w)m(as)i(made)f(p)s(ossible)g
+(through)f(collab-)0 4377 y(orations)35 b(with)f(man)m(y)h(p)s(eople)f
+(or)h(organizations)h(from)e(around)f(the)i(w)m(orld.)52
+b(The)34 b(follo)m(wing,)j(in)d(particular,)0 4490 y(ha)m(v)m(e)e(made)
+e(esp)s(ecially)i(signi\014can)m(t)f(con)m(tributions:)0
+4650 y(Programmers)25 b(from)h(the)f(In)m(tegral)i(Science)g(Data)g
+(Cen)m(ter,)g(Switzerland)f(\(namely)-8 b(,)28 b(Jurek)c(Bork)m(o)m
+(wski,)29 b(Bruce)0 4763 y(O'Neel,)34 b(and)e(Don)h(Jennings\),)f
+(designed)g(the)h(concept)g(for)f(the)h(plug-in)f(I/O)g(driv)m(ers)g
+(that)h(w)m(as)g(in)m(tro)s(duced)0 4876 y(with)i(CFITSIO)e(2.0.)56
+b(The)34 b(use)h(of)g(`driv)m(ers')g(greatly)h(simpli\014ed)f(the)g(lo)
+m(w-lev)m(el)j(I/O,)d(whic)m(h)f(in)h(turn)f(made)0 4989
+y(other)40 b(new)f(features)i(in)e(CFITSIO)f(\(e.g.,)45
+b(supp)s(ort)38 b(for)h(compressed)h(FITS)f(\014les)h(and)f(supp)s(ort)
+f(for)i(IRAF)0 5102 y(format)32 b(image)g(\014les\))g(m)m(uc)m(h)f
+(easier)i(to)f(implemen)m(t.)44 b(Jurek)31 b(Bork)m(o)m(wski)h(wrote)g
+(the)g(Shared)e(Memory)i(driv)m(er,)0 5215 y(and)23 b(Bruce)i(O'Neel)g
+(wrote)f(the)g(driv)m(ers)g(for)f(accessing)j(FITS)d(\014les)h(o)m(v)m
+(er)h(the)f(net)m(w)m(ork)h(using)e(the)i(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)h(pro)m(vided)f(the)h(template)h(parsing)e
+(routines)g(\(written)h(b)m(y)f(Jurek)g(Bork)m(o)m(wski\))i(and)e(the)0
+5601 y(hierarc)m(hical)39 b(grouping)d(routines)h(\(written)h(b)m(y)f
+(Don)h(Jennings\).)60 b(The)37 b(ISDC)f(D)m(AL)i(\(Data)h(Access)f(La)m
+(y)m(er\))0 5714 y(routines)30 b(are)h(la)m(y)m(ered)h(on)e(top)h(of)f
+(CFITSIO)f(and)h(mak)m(e)h(extensiv)m(e)h(use)e(of)h(these)g(features.)
+p eop end
+%%Page: 11 17
+TeXDict begin 11 16 bop 0 299 a Fg(2.7.)72 b(A)m(CKNO)m(WLEDGMENTS)2577
+b Fi(11)0 555 y(Uw)m(e)25 b(Lammers)e(\(XMM/ESA/ESTEC,)h(The)g
+(Netherlands\))g(designed)g(the)g(high-p)s(erformance)f(lexical)j
+(pars-)0 668 y(ing)42 b(algorithm)h(that)f(is)g(used)f(to)i(do)e
+(on-the-\015y)h(\014ltering)g(of)g(FITS)f(tables.)76
+b(This)41 b(algorithm)i(essen)m(tially)0 781 y(pre-compiles)36
+b(the)g(user-supplied)e(selection)k(expression)d(in)m(to)i(a)f(form)g
+(that)g(can)g(b)s(e)f(rapidly)g(ev)-5 b(aluated)37 b(for)0
+894 y(eac)m(h)31 b(ro)m(w.)40 b(P)m(eter)31 b(Wilson)f(\(RSTX,)f
+(NASA/GSF)m(C\))i(then)e(wrote)h(the)g(parsing)f(routines)g(used)g(b)m
+(y)g(CFITSIO)0 1007 y(based)i(on)f(Lammers')h(design,)g(com)m(bined)g
+(with)g(other)g(tec)m(hniques)g(suc)m(h)g(as)g(the)g(CFITSIO)f
+(iterator)i(routine)0 1120 y(to)g(further)e(enhance)h(the)h(data)g(pro)
+s(cessing)f(throughput.)42 b(This)31 b(e\013ort)h(also)g(b)s
+(ene\014ted)e(from)h(a)h(m)m(uc)m(h)f(earlier)0 1233
+y(lexical)25 b(parsing)f(routine)f(that)h(w)m(as)g(dev)m(elop)s(ed)g(b)
+m(y)g(Ken)m(t)g(Blac)m(kburn)f(\(NASA/GSF)m(C\).)i(More)g(recen)m(tly)
+-8 b(,)27 b(Craig)0 1346 y(Markw)m(ardt)i(\(NASA/GSF)m(C\))g(implemen)m
+(ted)g(additional)g(functions)f(\(median,)h(a)m(v)m(erage,)j(stddev\))c
+(and)g(other)0 1458 y(enhancemen)m(ts)j(to)g(the)g(lexical)h(parser.)0
+1619 y(The)40 b(CFITSIO)g(iterator)i(function)e(is)h(lo)s(osely)h
+(based)f(on)f(similar)i(ideas)f(dev)m(elop)s(ed)g(for)g(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)g(\(RSTX,)f(NASA/GSF)m(C\))h(wrote)g(the)f(complete)i(set)e
+(of)h(F)-8 b(ortran-callable)27 b(wrapp)s(ers)22 b(for)i(all)h(the)0
+2005 y(CFITSIO)k(routines,)h(whic)m(h)g(in)g(turn)g(rely)g(on)h(the)f
+(CF)m(OR)-8 b(TRAN)31 b(macro)g(dev)m(elop)s(ed)g(b)m(y)f(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)i(or)f(binning)e(input)h(FITS)h(\014les)g(is)g(based)f(on)
+h(ideas)h(dev)m(elop)s(ed)0 2278 y(for)41 b(the)g(AXAF)h(Science)g(Cen)
+m(ter)g(Data)h(Mo)s(del)e(b)m(y)g(Jonathan)g(McDo)m(w)m(ell,)47
+b(An)m(tonella)c(F)-8 b(ruscione,)45 b(Aneta)0 2391 y(Siemigino)m(wsk)
+-5 b(a)27 b(and)e(Bill)i(Jo)m(y)m(e.)41 b(See)26 b(h)m
+(ttp://heasarc.gsfc.nasa.go)m(v/do)s(cs/journal/axa)q(f7.h)m(t)q(ml)32
+b(for)25 b(further)0 2503 y(description)30 b(of)h(the)g(AXAF)g(Data)h
+(Mo)s(del.)0 2664 y(The)j(\014le)g(decompression)g(co)s(de)g(w)m(ere)h
+(tak)m(en)g(directly)g(from)e(the)i(gzip)f(\(GNU)h(zip\))g(program)f
+(dev)m(elop)s(ed)g(b)m(y)0 2777 y(Jean-loup)30 b(Gailly)i(and)e
+(others.)0 2937 y(Doug)h(Mink,)g(SA)m(O,)f(pro)m(vided)g(the)h
+(routines)f(for)g(con)m(v)m(erting)i(IRAF)f(format)g(images)g(in)m(to)g
+(FITS)f(format.)0 3097 y(Martin)j(Reinec)m(k)m(e)i(\(Max)f(Planc)m(k)f
+(Institute,)h(Garc)m(hing\)\))g(pro)m(vided)f(the)g(mo)s(di\014cations)
+f(to)i(cfortran.h)e(that)0 3210 y(are)d(necessary)h(to)f(supp)s(ort)e
+(64-bit)k(in)m(teger)f(v)-5 b(alues)29 b(when)f(calling)i(C)f(routines)
+g(from)f(fortran)h(programs.)39 b(The)0 3323 y(cfortran.h)30
+b(macros)h(w)m(ere)g(originally)h(dev)m(elop)s(ed)e(b)m(y)h(Burkhard)e
+(Buro)m(w)h(\(CERN\).)0 3483 y(Julian)f(T)-8 b(a)m(ylor)31
+b(\(ESO,)e(Garc)m(hing\))i(pro)m(vided)e(the)g(fast)h(b)m(yte-sw)m
+(apping)g(algorithms)h(that)f(use)f(the)h(SSE2)f(and)0
+3596 y(SSSE3)g(mac)m(hine)i(instructions)f(a)m(v)-5 b(ailable)33
+b(on)d(x86)p 1784 3596 28 4 v 34 w(64)h(CPUs.)0 3756
+y(In)c(addition,)i(man)m(y)f(other)g(p)s(eople)g(ha)m(v)m(e)h(made)f(v)
+-5 b(aluable)29 b(con)m(tributions)f(to)h(the)f(dev)m(elopmen)m(t)h(of)
+f(CFITSIO.)0 3869 y(These)i(include)g(\(with)h(ap)s(ologies)h(to)f
+(others)f(that)h(ma)m(y)g(ha)m(v)m(e)h(inadv)m(erten)m(tly)g(b)s(een)d
+(omitted\):)0 4029 y(Stev)m(e)g(Allen,)g(Carl)f(Ak)m(erlof,)h(Keith)f
+(Arnaud,)g(Morten)g(Krabb)s(e)e(Barfo)s(ed,)j(Ken)m(t)f(Blac)m(kburn,)h
+(G)f(Bo)s(dammer,)0 4142 y(Romk)m(e)h(Bon)m(tek)m(o)s(e,)i(Lucio)d
+(Chiapp)s(etti,)g(Keith)g(Costorf,)g(Robin)g(Corb)s(et,)g(John)e(Da)m
+(vis,)k(Ric)m(hard)e(Fink,)h(Ning)0 4255 y(Gan,)g(Emily)e(Greene,)i(Jo)
+s(e)f(Harrington,)h(Cheng)e(Ho,)i(Phil)e(Ho)s(dge,)i(Jim)f(Ingham,)g(Y)
+-8 b(oshitak)j(a)29 b(Ishisaki,)f(Diab)0 4368 y(Jerius,)j(Mark)h
+(Levine,)g(T)-8 b(o)s(dd)30 b(Karak)-5 b(askian,)32 b(Edw)m(ard)f
+(King,)g(Scott)i(Ko)s(c)m(h,)e(Claire)h(Larkin,)f(Rob)h(Managan,)0
+4481 y(Eric)38 b(Mandel,)i(John)d(Matto)m(x,)43 b(Carsten)37
+b(Mey)m(er,)42 b(Emi)37 b(Miy)m(ata,)43 b(Stefan)38 b(Mo)s(c)m(hnac)m
+(ki,)j(Mik)m(e)f(Noble,)g(Oliv)m(er)0 4594 y(Ob)s(erdorf,)c(Cliv)m(e)i
+(P)m(age,)i(Arvind)35 b(P)m(armar,)j(Je\013)f(P)m(edelt)m(y)-8
+b(,)40 b(Tim)c(P)m(earson,)j(Maren)e(Purv)m(es,)h(Scott)f(Randall,)0
+4706 y(Chris)d(Rogers,)j(Arnold)e(Rots,)i(Barry)f(Sc)m(hlesinger,)h
+(Robin)e(Stebbins,)g(Andrew)f(Szymk)m(o)m(wiak,)k(Allyn)e(T)-8
+b(en-)0 4819 y(nan)m(t,)31 b(P)m(eter)g(T)-8 b(eub)s(en,)30
+b(James)g(Theiler,)h(Doug)g(T)-8 b(o)s(dy)g(,)31 b(Shiro)e(Ueno,)j
+(Stev)m(e)f(W)-8 b(alton,)33 b(Arc)m(hie)e(W)-8 b(arno)s(c)m(k,)32
+b(Alan)0 4932 y(W)-8 b(atson,)32 b(Dan)f(Whipple,)f(Wim)h(Wimmers,)g(P)
+m(eter)g(Y)-8 b(oung,)31 b(Jianjun)e(Xu,)h(and)g(Nelson)h(Zarate.)p
+eop end
+%%Page: 12 18
+TeXDict begin 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 end
+%%Page: 13 19
+TeXDict begin 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)23 b(section)j(giv)m
+(es)f(a)g(brief)e(o)m(v)m(erview)j(of)e(the)h(structure)e(of)i(FITS)e
+(\014les.)38 b(Users)24 b(should)g(refer)f(to)i(the)g(do)s(cumen-)0
+2293 y(tation)j(a)m(v)-5 b(ailable)30 b(from)d(the)g(NOST,)f(as)i
+(describ)s(ed)e(in)h(the)g(in)m(tro)s(duction,)h(for)f(more)g(detailed)
+i(information)e(on)0 2406 y(FITS)j(formats.)0 2566 y(FITS)37
+b(w)m(as)g(\014rst)g(dev)m(elop)s(ed)h(in)f(the)g(late)i(1970's)g(as)f
+(a)f(standard)g(data)h(in)m(terc)m(hange)h(format)f(b)s(et)m(w)m(een)g
+(v)-5 b(ar-)0 2679 y(ious)38 b(astronomical)h(observ)-5
+b(atories.)64 b(Since)37 b(then)g(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)h(data)f(analysis)g(soft)m(w)m(are)g(pac)
+m(k)-5 b(ages.)0 2952 y(A)34 b(FITS)f(\014le)g(consists)h(of)g(one)g
+(or)g(more)g(Header)g(+)f(Data)i(Units)f(\(HDUs\),)i(where)d(the)h
+(\014rst)f(HDU)h(is)g(called)0 3065 y(the)j(`Primary)f(HDU',)i(or)f
+(`Primary)f(Arra)m(y'.)60 b(The)36 b(primary)g(arra)m(y)h(con)m(tains)h
+(an)e(N-dimensional)i(arra)m(y)f(of)0 3177 y(pixels,)32
+b(suc)m(h)g(as)f(a)h(1-D)h(sp)s(ectrum,)e(a)h(2-D)h(image,)g(or)f(a)g
+(3-D)g(data)h(cub)s(e.)43 b(Six)31 b(di\013eren)m(t)h(primary)f(datat)m
+(yp)s(es)0 3290 y(are)g(supp)s(orted:)39 b(Unsigned)30
+b(8-bit)h(b)m(ytes,)g(16,)g(32,)h(and)e(64-bit)h(signed)g(in)m(tegers,)
+h(and)d(32)j(and)d(64-bit)j(\015oating)0 3403 y(p)s(oin)m(t)d(reals.)41
+b(FITS)29 b(also)i(has)e(a)h(con)m(v)m(en)m(tion)h(for)e(storing)h
+(unsigned)f(in)m(tegers)h(\(see)h(the)e(later)i(section)f(en)m(titled)0
+3516 y(`Unsigned)h(In)m(tegers')h(for)f(more)g(details\).)43
+b(The)31 b(primary)f(HDU)i(ma)m(y)f(also)h(consist)g(of)f(only)g(a)g
+(header)g(with)g(a)0 3629 y(n)m(ull)f(arra)m(y)h(con)m(taining)h(no)e
+(data)h(pixels.)0 3789 y(An)m(y)i(n)m(um)m(b)s(er)e(of)h(additional)i
+(HDUs)f(ma)m(y)g(follo)m(w)h(the)e(primary)g(arra)m(y;)i(these)f
+(additional)h(HDUs)f(are)g(called)0 3902 y(FITS)d(`extensions'.)41
+b(There)30 b(are)h(curren)m(tly)f(3)h(t)m(yp)s(es)g(of)f(extensions)h
+(de\014ned)e(b)m(y)h(the)h(FITS)f(standard:)136 4171
+y Fc(\017)46 b Fi(Image)31 b(Extension)g(-)g(a)f(N-dimensional)h(arra)m
+(y)g(of)g(pixels,)g(lik)m(e)g(in)f(a)h(primary)e(arra)m(y)136
+4368 y Fc(\017)46 b Fi(ASCI)s(I)29 b(T)-8 b(able)31 b(Extension)g(-)f
+(ro)m(ws)h(and)e(columns)h(of)h(data)g(in)f(ASCI)s(I)f(c)m(haracter)j
+(format)136 4564 y Fc(\017)46 b Fi(Binary)31 b(T)-8 b(able)31
+b(Extension)f(-)h(ro)m(ws)f(and)g(columns)g(of)h(data)g(in)f(binary)f
+(represen)m(tation)0 4833 y(In)k(eac)m(h)i(case)g(the)f(HDU)h(consists)
+g(of)f(an)g(ASCI)s(I)e(Header)i(Unit)h(follo)m(w)m(ed)g(b)m(y)f(an)g
+(optional)h(Data)g(Unit.)52 b(F)-8 b(or)0 4946 y(historical)37
+b(reasons,)g(eac)m(h)f(Header)g(or)g(Data)h(unit)e(m)m(ust)g(b)s(e)g
+(an)g(exact)i(m)m(ultiple)f(of)g(2880)h(8-bit)f(b)m(ytes)g(long.)0
+5059 y(An)m(y)30 b(un)m(used)g(space)g(is)h(padded)e(with)h(\014ll)g(c)
+m(haracters)i(\(ASCI)s(I)d(blanks)h(or)h(zeros\).)0 5219
+y(Eac)m(h)i(Header)f(Unit)h(consists)g(of)f(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')
+g(whic)m(h)0 5332 y(ha)m(v)m(e)f(the)e(general)i(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 end
+%%Page: 14 20
+TeXDict begin 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)g(and)e
+(can)h(only)h(con)m(tain)g(upp)s(ercase)e(letters,)k(the)0
+668 y(digits)25 b(0-9,)i(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)f(\(usually\))h
+(follo)m(w)m(ed)i(b)m(y)d(an)0 781 y(equals)29 b(sign)g(and)f(a)g
+(space)i(c)m(haracter)g(\(=)e(\))h(in)f(columns)h(9)g(-)f(10)i(of)f
+(the)f(record,)h(follo)m(w)m(ed)i(b)m(y)d(the)h(v)-5
+b(alue)29 b(of)g(the)0 894 y(k)m(eyw)m(ord)34 b(whic)m(h)g(ma)m(y)g(b)s
+(e)f(either)h(an)g(in)m(teger,)i(a)e(\015oating)g(p)s(oin)m(t)g(n)m(um)
+m(b)s(er,)g(a)g(c)m(haracter)h(string)e(\(enclosed)i(in)0
+1007 y(single)28 b(quotes\),)i(or)e(a)g(b)s(o)s(olean)g(v)-5
+b(alue)28 b(\(the)g(letter)h(T)f(or)f(F\).)i(A)f(k)m(eyw)m(ord)g(ma)m
+(y)h(also)f(ha)m(v)m(e)h(a)g(n)m(ull)e(or)h(unde\014ned)0
+1120 y(v)-5 b(alue)31 b(if)f(there)h(is)f(no)g(sp)s(eci\014ed)g(v)-5
+b(alue)31 b(string,)g(as)f(in)g(the)h(second)f(example.)0
+1280 y(The)42 b(last)h(k)m(eyw)m(ord)g(in)f(the)h(header)f(is)g(alw)m
+(a)m(ys)i(the)f(`END')g(k)m(eyw)m(ord)g(whic)m(h)f(has)g(no)h(v)-5
+b(alue)42 b(or)h(commen)m(t)0 1393 y(\014elds.)d(There)30
+b(are)h(man)m(y)f(rules)g(go)m(v)m(erning)i(the)e(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)g(is)f(b)s(etter)h(to)g(rely)g(on)f
+(standard)g(in)m(terface)i(soft)m(w)m(are)g(lik)m(e)g(FITSIO)d(to)j
+(correctly)g(construct)0 1619 y(or)d(to)h(parse)g(the)f(k)m(eyw)m(ord)h
+(records)f(rather)g(than)h(try)f(to)h(deal)g(directly)g(with)f(the)g
+(ra)m(w)h(FITS)f(formats.)0 1779 y(Eac)m(h)37 b(Header)g(Unit)f(b)s
+(egins)g(with)g(a)g(series)h(of)f(required)g(k)m(eyw)m(ords)g(whic)m(h)
+g(dep)s(end)f(on)h(the)g(t)m(yp)s(e)h(of)f(HDU.)0 1892
+y(These)31 b(required)g(k)m(eyw)m(ords)h(sp)s(ecify)g(the)f(size)i(and)
+e(format)h(of)g(the)g(follo)m(wing)h(Data)g(Unit.)45
+b(The)31 b(header)g(ma)m(y)0 2005 y(con)m(tain)h(other)f(optional)g(k)m
+(eyw)m(ords)g(to)h(describ)s(e)e(other)g(asp)s(ects)h(of)g(the)g(data,)
+g(suc)m(h)g(as)g(the)f(units)g(or)h(scaling)0 2118 y(v)-5
+b(alues.)44 b(Other)31 b(COMMENT)g(or)g(HISTOR)-8 b(Y)30
+b(k)m(eyw)m(ords)i(are)g(also)g(frequen)m(tly)g(added)e(to)i(further)e
+(do)s(cumen)m(t)0 2230 y(the)h(data)g(\014le.)0 2391
+y(The)36 b(optional)h(Data)h(Unit)f(immediately)g(follo)m(ws)h(the)e
+(last)h(2880-b)m(yte)i(blo)s(c)m(k)e(in)f(the)g(Header)h(Unit.)59
+b(Some)0 2503 y(HDUs)31 b(do)f(not)h(ha)m(v)m(e)g(a)g(Data)h(Unit)f
+(and)f(only)g(consist)h(of)g(the)f(Header)h(Unit.)0 2664
+y(If)24 b(there)i(is)f(more)g(than)f(one)h(HDU)h(in)f(the)g(FITS)f
+(\014le,)i(then)f(the)g(Header)h(Unit)f(of)g(the)g(next)g(HDU)h
+(immediately)0 2777 y(follo)m(ws)g(the)e(last)i(2880-b)m(yte)h(blo)s(c)
+m(k)e(of)g(the)f(previous)g(Data)j(Unit)d(\(or)h(Header)g(Unit)g(if)f
+(there)h(is)g(no)f(Data)i(Unit\).)0 2937 y(The)k(main)g(required)g(k)m
+(eyw)m(ords)g(in)g(FITS)g(primary)g(arra)m(ys)g(or)h(image)g
+(extensions)g(are:)136 3172 y Fc(\017)46 b Fi(BITPIX)33
+b({)h(de\014nes)e(the)i(datat)m(yp)s(e)g(of)f(the)g(arra)m(y:)47
+b(8,)35 b(16,)g(32,)g(64,)g(-32,)g(-64)g(for)e(unsigned)f(8{bit)i(b)m
+(yte,)227 3284 y(16{bit)27 b(signed)e(in)m(teger,)i(32{bit)g(signed)e
+(in)m(teger,)j(64{bit)e(signed)f(in)m(teger,)j(32{bit)e(IEEE)f
+(\015oating)h(p)s(oin)m(t,)227 3397 y(and)k(64{bit)i(IEEE)e(double)f
+(precision)i(\015oating)g(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)g(in)g(the)h(arra)m(y)-8 b(,)31 b(usually)f(0,)h(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)g
+(of)g(eac)m(h)g(dimension.)0 4008 y(FITS)e(tables)i(start)g(with)f(the)
+g(k)m(eyw)m(ord)g(XTENSION)g(=)f(`T)-8 b(ABLE')31 b(\(for)f(ASCI)s(I)f
+(tables\))i(or)f(XTENSION)f(=)0 4120 y(`BINT)-8 b(ABLE')32
+b(\(for)e(binary)g(tables\))h(and)f(ha)m(v)m(e)i(the)e(follo)m(wing)i
+(main)e(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)g(or)h(columns)f(in)g(the)g
+(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)f(the)g(table)136 4731 y Fc(\017)46 b
+Fi(TTYPEn)29 b({)i(for)f(eac)m(h)i(column)e(\(n)g(ranges)h(from)f(1)g
+(to)h(TFIELDS\))g(giv)m(es)g(the)g(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)g(units)f(of)g(the)h(column)f(\(optional\))0
+5341 y(Users)k(should)f(refer)h(to)h(the)f(FITS)g(Supp)s(ort)e(O\016ce)
+i(at)h Fe(http://fits.gsfc.nasa.gov)27 b Fi(for)34 b(further)f(infor-)0
+5454 y(mation)e(ab)s(out)f(the)h(FITS)e(format)i(and)f(related)h(soft)m
+(w)m(are)h(pac)m(k)-5 b(ages.)p eop end
+%%Page: 15 21
+TeXDict begin 15 20 bop 0 1225 a Ff(Chapter)65 b(4)0
+1687 y Fl(FITSIO)76 b(Con)-6 b(v)g(en)g(tions)76 b(and)h(Guidelines)0
+2216 y Fd(4.1)135 b(CFITSIO)44 b(Size)h(Limitations)0
+2524 y Fi(CFITSIO)31 b(places)i(few)g(restrictions)g(on)g(the)f(size)i
+(of)e(FITS)g(\014les)h(that)g(it)g(reads)f(or)h(writes.)47
+b(There)32 b(are)h(a)g(few)0 2636 y(limits,)e(ho)m(w)m(ev)m(er,)h(whic)
+m(h)e(ma)m(y)h(a\013ect)h(some)f(extreme)g(cases:)0 2797
+y(1.)43 b(The)31 b(maxim)m(um)g(n)m(um)m(b)s(er)f(of)h(FITS)f(\014les)h
+(that)h(ma)m(y)g(b)s(e)e(sim)m(ultaneously)i(op)s(ened)f(b)m(y)g
+(CFITSIO)e(is)i(set)h(b)m(y)0 2910 y(NMAXFILES)i(as)g(de\014ned)f(in)h
+(\014tsio2.h.)52 b(It)34 b(is)g(curren)m(tly)g(set)h(=)f(300)h(b)m(y)f
+(default.)52 b(CFITSIO)32 b(will)i(allo)s(cate)0 3022
+y(ab)s(out)f(80)g(*)h(NMAXFILES)f(b)m(ytes)g(of)g(memory)g(for)g(in)m
+(ternal)g(use.)48 b(Note)34 b(that)g(the)f(underlying)f(C)g(compiler)0
+3135 y(or)39 b(op)s(erating)h(system,)j(ma)m(y)d(ha)m(v)m(e)g(a)g
+(smaller)g(limit)h(on)e(the)h(n)m(um)m(b)s(er)e(of)i(op)s(ened)e
+(\014les.)68 b(The)39 b(C)h(sym)m(b)s(olic)0 3248 y(constan)m(t)31
+b(F)m(OPEN)p 690 3248 28 4 v 34 w(MAX)f(is)g(in)m(tended)g(to)h
+(de\014ne)e(the)i(maxim)m(um)f(n)m(um)m(b)s(er)e(of)j(\014les)f(that)g
+(ma)m(y)h(op)s(en)e(at)i(once)0 3361 y(\(including)g(an)m(y)g(other)g
+(text)h(or)f(binary)f(\014les)h(that)h(ma)m(y)f(b)s(e)g(op)s(en,)f(not)
+h(just)g(FITS)f(\014les\).)43 b(On)30 b(some)h(systems)0
+3474 y(it)g(has)f(b)s(een)g(found)f(that)i(gcc)g(supp)s(orts)e(a)h
+(maxim)m(um)h(of)f(255)i(op)s(ened)e(\014les.)0 3634
+y(2.)54 b(By)35 b(default,)h(CFITSIO)d(can)i(handle)g(FITS)f(\014les)g
+(up)g(to)h(2.1)h(GB)g(in)e(size)i(\(2**31)h(b)m(ytes\).)54
+b(This)34 b(\014le)h(size)0 3747 y(limit)41 b(is)g(often)f(imp)s(osed)g
+(b)m(y)g(32-bit)i(op)s(erating)e(systems.)71 b(More)41
+b(recen)m(tly)-8 b(,)45 b(as)c(64-bit)g(op)s(erating)g(systems)0
+3860 y(b)s(ecome)33 b(more)g(common,)g(an)g(industry-wide)e(standard)h
+(\(at)i(least)f(on)g(Unix)f(systems\))h(has)g(b)s(een)f(dev)m(elop)s
+(ed)0 3973 y(to)39 b(supp)s(ort)d(larger)i(sized)h(\014les)f(\(see)g(h)
+m(ttp://ftp.sas.com/standards/large.\014le/\).)69 b(Starting)38
+b(with)f(v)m(ersion)0 4086 y(2.1)45 b(of)e(CFITSIO,)f(larger)i(FITS)f
+(\014les)g(up)g(to)h(6)g(terab)m(ytes)h(in)e(size)h(ma)m(y)g(b)s(e)f
+(read)g(and)g(written)h(on)f(sup-)0 4199 y(p)s(orted)f(platforms.)76
+b(In)42 b(order)g(to)h(supp)s(ort)e(these)h(larger)h(\014les,)j
+(CFITSIO)41 b(m)m(ust)h(b)s(e)g(compiled)h(with)f(the)0
+4312 y('-D)p 129 4312 V 34 w(LAR)m(GEFILE)p 696 4312
+V 33 w(SOUR)m(CE')g(and)g(`-D)p 1491 4312 V 34 w(FILE)p
+1736 4312 V 33 w(OFFSET)p 2137 4312 V 32 w(BITS=64')h(compiler)g
+(\015ags.)78 b(Some)43 b(platforms)0 4425 y(ma)m(y)c(also)g(require)f
+(the)g(`-D)p 1002 4425 V 34 w(LAR)m(GE)p 1358 4425 V
+33 w(FILES')g(compiler)h(\015ag.)64 b(This)38 b(causes)g(the)h
+(compiler)g(to)g(allo)s(cate)h(8-)0 4538 y(b)m(ytes)k(instead)g(of)g
+(4-b)m(ytes)h(for)f(the)g(`o\013)p 1473 4538 V 33 w(t')g(datat)m(yp)s
+(e)h(whic)m(h)f(is)f(used)g(to)i(store)f(\014le)g(o\013set)h(p)s
+(ositions.)81 b(It)0 4650 y(app)s(ears)31 b(that)i(in)e(most)i(cases)g
+(it)f(is)g(not)g(necessary)h(to)f(also)h(include)f(these)g(compiler)h
+(\015ags)f(when)f(compiling)0 4763 y(programs)f(that)h(link)f(to)h(the)
+g(CFITSIO)e(library)-8 b(.)0 4924 y(If)21 b(CFITSIO)e(is)i(compiled)h
+(with)f(the)g(-D)p 1386 4924 V 33 w(LAR)m(GEFILE)p 1952
+4924 V 34 w(SOUR)m(CE)f(and)g(-D)p 2654 4924 V 34 w(FILE)p
+2899 4924 V 33 w(OFFSET)p 3300 4924 V 32 w(BITS=64)h(\015ags)0
+5036 y(on)36 b(a)g(platform)g(that)g(supp)s(orts)e(large)j(\014les,)h
+(then)d(it)i(can)f(read)g(and)f(write)h(FITS)f(\014les)h(that)g(con)m
+(tain)h(up)e(to)0 5149 y(2**31)k(2880-b)m(yte)g(FITS)d(records,)j(or)d
+(appro)m(ximately)i(6)f(terab)m(ytes)h(in)f(size.)60
+b(It)37 b(is)g(still)h(required)d(that)j(the)0 5262 y(v)-5
+b(alue)30 b(of)f(the)g(NAXISn)f(and)h(PCOUNT)f(k)m(eyw)m(ords)h(in)g
+(eac)m(h)h(extension)g(b)s(e)e(within)h(the)g(range)h(of)f(a)g(signed)g
+(4-)0 5375 y(b)m(yte)c(in)m(teger)h(\(max)f(v)-5 b(alue)26
+b(=)e(2,147,483,648\).)44 b(Th)m(us,)25 b(eac)m(h)h(dimension)e(of)h
+(an)f(image)i(\(giv)m(en)g(b)m(y)f(the)g(NAXISn)0 5488
+y(k)m(eyw)m(ords\),)32 b(the)f(total)i(width)d(of)h(a)g(table)h
+(\(NAXIS1)g(k)m(eyw)m(ord\),)g(the)f(n)m(um)m(b)s(er)f(of)h(ro)m(ws)g
+(in)f(a)h(table)h(\(NAXIS2)0 5601 y(k)m(eyw)m(ord\),)c(and)d(the)h
+(total)i(size)f(of)f(the)g(v)-5 b(ariable-length)28 b(arra)m(y)e(heap)g
+(in)g(binary)f(tables)i(\(PCOUNT)e(k)m(eyw)m(ord\))0
+5714 y(m)m(ust)30 b(b)s(e)g(less)h(than)f(this)g(limit.)1905
+5942 y(15)p eop end
+%%Page: 16 22
+TeXDict begin 16 21 bop 0 299 a Fi(16)1277 b Fg(CHAPTER)29
+b(4.)72 b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0
+555 y Fi(Curren)m(tly)-8 b(,)31 b(supp)s(ort)e(for)i(large)h(\014les)f
+(within)f(CFITSIO)f(has)i(b)s(een)f(tested)i(on)f(the)g(Lin)m(ux,)g
+(Solaris,)g(and)f(IBM)0 668 y(AIX)g(op)s(erating)h(systems.)0
+1133 y Fd(4.2)135 b(Multiple)46 b(Access)e(to)i(the)f(Same)g(FITS)f
+(File)0 1409 y Fi(CFITSIO)35 b(supp)s(orts)g(sim)m(ultaneous)i(read)f
+(and)g(write)h(access)g(to)h(m)m(ultiple)f(HDUs)g(in)f(the)h(same)g
+(FITS)f(\014le.)0 1522 y(Th)m(us,)43 b(one)e(can)h(op)s(en)e(the)h
+(same)h(FITS)e(\014le)h(t)m(wice)i(within)d(a)i(single)f(program)g(and)
+g(mo)m(v)m(e)h(to)g(2)f(di\013eren)m(t)0 1635 y(HDUs)30
+b(in)f(the)h(\014le,)g(and)f(then)g(read)h(and)e(write)i(data)g(or)g(k)
+m(eyw)m(ords)g(to)g(the)g(2)f(extensions)i(just)d(as)i(if)g(one)f(w)m
+(ere)0 1748 y(accessing)f(2)f(completely)h(separate)f(FITS)f(\014les.)
+39 b(Since)27 b(in)f(general)h(it)g(is)g(not)g(p)s(ossible)f(to)h(ph)m
+(ysically)g(op)s(en)f(the)0 1861 y(same)36 b(\014le)g(t)m(wice)h(and)e
+(then)g(exp)s(ect)h(to)g(b)s(e)f(able)h(to)h(sim)m(ultaneously)f(\(or)g
+(in)f(alternating)i(succession\))g(write)0 1974 y(to)e(2)f(di\013eren)m
+(t)h(lo)s(cations)h(in)d(the)i(\014le,)g(CFITSIO)e(recognizes)j(when)d
+(the)h(\014le)g(to)h(b)s(e)f(op)s(ened)f(\(in)h(the)h(call)g(to)0
+2087 y(\014ts)p 127 2087 28 4 v 32 w(op)s(en)p 349 2087
+V 33 w(\014le\))29 b(has)f(already)h(b)s(een)f(op)s(ened)g(and)g
+(instead)h(of)g(actually)h(op)s(ening)e(the)h(\014le)g(again,)h(just)e
+(logically)0 2199 y(links)i(the)h(new)f(\014le)h(to)g(the)g(old)f
+(\014le.)42 b(\(This)30 b(only)h(applies)f(if)h(the)g(\014le)f(is)h(op)
+s(ened)f(more)g(than)g(once)i(within)e(the)0 2312 y(same)e(program,)g
+(and)f(do)s(es)h(not)f(prev)m(en)m(t)i(the)f(same)g(\014le)f(from)g(b)s
+(eing)h(sim)m(ultaneously)g(op)s(ened)f(b)m(y)g(more)h(than)0
+2425 y(one)h(program\).)40 b(Then)28 b(b)s(efore)g(CFITSIO)f(reads)h
+(or)h(writes)g(to)g(either)g(\(logical\))j(\014le,)d(it)g(mak)m(es)h
+(sure)d(that)j(an)m(y)0 2538 y(mo)s(di\014cations)i(made)f(to)h(the)g
+(other)g(\014le)f(ha)m(v)m(e)i(b)s(een)e(completely)i(\015ushed)c(from)
+i(the)h(in)m(ternal)g(bu\013ers)f(to)h(the)0 2651 y(\014le.)44
+b(Th)m(us,)30 b(in)h(principle,)h(one)f(could)g(op)s(en)g(a)h(\014le)f
+(t)m(wice,)i(in)e(one)h(case)g(p)s(oin)m(ting)g(to)g(the)f(\014rst)g
+(extension)h(and)0 2764 y(in)i(the)h(other)g(p)s(oin)m(ting)f(to)i(the)
+e(2nd)g(extension)i(and)d(then)i(write)f(data)i(to)f(b)s(oth)f
+(extensions,)i(in)e(an)m(y)h(order,)0 2877 y(without)25
+b(danger)h(of)f(corrupting)h(the)f(\014le,)i(There)e(ma)m(y)h(b)s(e)f
+(some)h(e\016ciency)g(p)s(enalties)g(in)f(doing)h(this)f(ho)m(w)m(ev)m
+(er,)0 2990 y(since)j(CFITSIO)f(has)h(to)h(\015ush)d(all)j(the)f(in)m
+(ternal)h(bu\013ers)e(related)i(to)g(one)f(\014le)g(b)s(efore)g(switc)m
+(hing)g(to)h(the)f(other,)0 3103 y(so)i(it)h(w)m(ould)f(still)h(b)s(e)f
+(pruden)m(t)f(to)i(minimize)g(the)f(n)m(um)m(b)s(er)f(of)i(times)f(one)
+h(switc)m(hes)g(bac)m(k)g(and)e(forth)h(b)s(et)m(w)m(een)0
+3216 y(doing)g(I/O)h(to)g(di\013eren)m(t)g(HDUs)g(in)f(the)g(same)h
+(\014le.)0 3680 y Fd(4.3)135 b(Curren)l(t)46 b(Header)f(Data)h(Unit)g
+(\(CHDU\))0 3957 y Fi(In)32 b(general,)j(a)f(FITS)e(\014le)i(can)f(con)
+m(tain)h(m)m(ultiple)g(Header)g(Data)h(Units,)f(also)g(called)g
+(extensions.)49 b(CFITSIO)0 4070 y(only)38 b(op)s(erates)h(within)f
+(one)g(HDU)h(at)g(an)m(y)g(giv)m(en)g(time,)i(and)d(the)g(curren)m(tly)
+g(selected)i(HDU)f(is)f(called)i(the)0 4183 y(Curren)m(t)f(Header)h
+(Data)h(Unit)f(\(CHDU\).)h(When)f(a)g(FITS)f(\014le)h(is)f(\014rst)g
+(created)i(or)f(op)s(ened)f(the)h(CHDU)g(is)0 4295 y(automatically)28
+b(de\014ned)23 b(to)j(b)s(e)e(the)h(\014rst)f(HDU)i(\(i.e.,)h(the)e
+(primary)f(arra)m(y\).)40 b(CFITSIO)23 b(routines)i(are)g(pro)m(vided)0
+4408 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)g(HDU)h(within)e(the)h(FITS)f(\014le)g(or)h(to)g(app)s(end)e
+(or)i(insert)f(a)h(new)0 4521 y(HDU)31 b(in)f(the)h(FITS)e(\014le)i
+(whic)m(h)f(then)g(b)s(ecomes)h(the)f(CHDU.)0 4986 y
+Fd(4.4)135 b(Subroutine)45 b(Names)0 5262 y Fi(All)26
+b(FITSIO)f(subroutine)g(names)h(b)s(egin)f(with)h(the)g(letters)h('ft')
+f(to)h(distinguish)e(them)h(from)f(other)h(subroutines)0
+5375 y(and)34 b(are)h(5)g(or)f(6)h(c)m(haracters)h(long.)54
+b(Users)34 b(should)g(not)g(name)h(their)g(o)m(wn)f(subroutines)f(b)s
+(eginning)h(with)g('ft')0 5488 y(to)e(a)m(v)m(oid)i(con\015icts.)45
+b(\(The)32 b(SPP)f(in)m(terface)i(routines)e(all)i(b)s(egin)e(with)h
+('fs'\).)45 b(Subroutines)30 b(whic)m(h)h(read)h(or)g(get)0
+5601 y(information)e(from)g(the)h(FITS)e(\014le)h(ha)m(v)m(e)i(names)e
+(b)s(eginning)f(with)h('ftg...'.)43 b(Subroutines)28
+b(whic)m(h)i(write)g(or)h(put)0 5714 y(information)g(in)m(to)g(the)g
+(FITS)e(\014le)i(ha)m(v)m(e)g(names)g(b)s(eginning)e(with)h('ftp...'.)p
+eop end
+%%Page: 17 23
+TeXDict begin 17 22 bop 0 299 a Fg(4.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(17)0 555 y Fd(4.5)135 b(Subroutine)45 b(F)-11 b(amilies)46
+b(and)f(Datat)l(yp)t(es)0 805 y Fi(Man)m(y)h(of)g(the)g(subroutines)e
+(come)j(in)e(families)h(whic)m(h)g(di\013er)f(only)h(in)f(the)h(datat)m
+(yp)s(e)g(of)g(the)f(asso)s(ciated)0 918 y(parameter\(s\))34
+b(.)47 b(The)32 b(datat)m(yp)s(e)i(of)f(these)g(subroutines)e(is)i
+(indicated)g(b)m(y)g(the)g(last)g(letter)h(of)f(the)g(subroutine)0
+1031 y(name)d(\(e.g.,)j('j')d(in)g('ftpkyj'\))h(as)f(follo)m(ws:)382
+1284 y Fe(x)47 b(-)h(bit)382 1397 y(b)f(-)h(character*1)c(\(unsigned)i
+(byte\))382 1510 y(i)h(-)h(short)e(integer)g(\(I*2\))382
+1623 y(j)h(-)h(integer)e(\(I*4,)g(32-bit)g(integer\))382
+1735 y(k)h(-)h(long)e(long)h(integer)f(\(I*8,)g(64-bit)g(integer\))382
+1848 y(e)h(-)h(real)e(exponential)f(floating)h(point)g(\(R*4\))382
+1961 y(f)h(-)h(real)e(fixed-format)f(floating)g(point)i(\(R*4\))382
+2074 y(d)g(-)h(double)e(precision)f(real)i(floating-point)d(\(R*8\))382
+2187 y(g)j(-)h(double)e(precision)f(fixed-format)g(floating)g(point)h
+(\(R*8\))382 2300 y(c)h(-)h(complex)e(reals)g(\(pairs)g(of)h(R*4)g
+(values\))382 2413 y(m)g(-)h(double)e(precision)f(complex)h(\(pairs)g
+(of)h(R*8)g(values\))382 2526 y(l)g(-)h(logical)e(\(L*4\))382
+2639 y(s)h(-)h(character)d(string)0 2891 y Fi(When)23
+b(dealing)h(with)f(the)g(FITS)g(b)m(yte)g(datat)m(yp)s(e,)j(it)e(is)f
+(imp)s(ortan)m(t)h(to)f(remem)m(b)s(er)g(that)h(the)f(ra)m(w)g(v)-5
+b(alues)24 b(\(b)s(efore)0 3004 y(an)m(y)h(scaling)g(b)m(y)f(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\))25 b(in)f(b)m(yte)h(arra)m(ys)0
+3117 y(\(BITPIX)37 b(=)f(8\))h(or)f(b)m(yte)i(columns)e(\(TF)m(ORMn)h
+(=)f('B'\))h(are)g(in)m(terpreted)g(as)g(unsigned)e(b)m(ytes)i(with)g
+(v)-5 b(alues)0 3230 y(ranging)40 b(from)f(0)i(to)f(255.)71
+b(Some)40 b(F)-8 b(ortran)40 b(compilers)h(supp)s(ort)d(a)i
+(non-standard)f(b)m(yte)h(datat)m(yp)s(e)h(suc)m(h)f(as)0
+3343 y(INTEGER*1,)34 b(LOGICAL*1,)g(or)f(BYTE,)g(whic)m(h)f(can)h
+(sometimes)h(b)s(e)e(used)g(instead)h(of)g(CHARA)m(CTER*1)0
+3456 y(v)-5 b(ariables.)39 b(Man)m(y)23 b(mac)m(hines)g(p)s(ermit)g
+(passing)f(a)h(n)m(umeric)g(datat)m(yp)s(e)g(\(suc)m(h)g(as)g
+(INTEGER*1\))h(to)f(the)g(FITSIO)0 3569 y(subroutines)41
+b(whic)m(h)i(are)g(exp)s(ecting)g(a)g(CHARA)m(CTER*1)h(datat)m(yp)s(e,)
+j(but)42 b(this)g(tec)m(hnically)j(violates)g(the)0 3682
+y(F)-8 b(ortran-77)29 b(standard)d(and)g(is)h(not)g(supp)s(orted)e(on)i
+(all)h(mac)m(hines)f(\(e.g.,)j(on)c(a)i(V)-10 b(AX/VMS)27
+b(mac)m(hine)h(one)f(m)m(ust)0 3795 y(use)j(the)h(V)-10
+b(AX-sp)s(eci\014c)31 b(\045DESCR)e(function\).)0 3955
+y(One)22 b(feature)h(of)g(the)g(CFITSIO)e(routines)i(is)f(that)i(they)f
+(can)g(op)s(erate)g(on)f(a)h(`X')h(\(bit\))f(column)g(in)f(a)h(binary)f
+(table)0 4068 y(as)35 b(though)e(it)i(w)m(ere)g(a)g(`B')g(\(b)m(yte\))g
+(column.)53 b(F)-8 b(or)35 b(example)g(a)f(`11X')i(datat)m(yp)s(e)f
+(column)f(can)h(b)s(e)f(in)m(terpreted)0 4181 y(the)28
+b(same)h(as)f(a)g(`2B')i(column)e(\(i.e.,)i(2)e(unsigned)f(8-bit)i(b)m
+(ytes\).)41 b(In)27 b(some)i(instances,)g(it)f(can)h(b)s(e)e(more)h
+(e\016cien)m(t)0 4294 y(to)j(read)f(and)g(write)h(whole)f(b)m(ytes)h
+(at)g(a)g(time,)g(rather)g(than)f(reading)g(or)h(writing)f(eac)m(h)i
+(individual)d(bit.)0 4454 y(The)41 b(double)h(precision)g(complex)g
+(datat)m(yp)s(e)h(is)f(not)g(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 4567
+y(F)-8 b(ortran)35 b(compiler)g(do)s(es)f(not)h(directly)g(supp)s(ort)e
+(this)i(datat)m(yp)s(e,)h(then)f(one)f(ma)m(y)h(instead)g(pass)f(an)h
+(arra)m(y)g(of)0 4680 y(pairs)d(of)h(double)f(precision)h(v)-5
+b(alues)32 b(to)i(these)f(subroutines.)45 b(The)33 b(\014rst)e(v)-5
+b(alue)33 b(in)f(eac)m(h)i(pair)e(is)h(the)g(real)g(part,)0
+4792 y(and)d(the)g(second)h(is)f(the)h(imaginary)g(part.)0
+5125 y Fd(4.6)135 b(Implicit)46 b(Data)g(T)l(yp)t(e)f(Con)l(v)l(ersion)
+0 5375 y Fi(The)22 b(FITSIO)g(routines)h(that)h(read)e(and)h(write)g(n)
+m(umerical)g(data)h(can)f(p)s(erform)f(implicit)i(data)f(t)m(yp)s(e)g
+(con)m(v)m(ersion.)0 5488 y(This)i(means)g(that)h(the)g(data)g(t)m(yp)s
+(e)g(of)g(the)g(v)-5 b(ariable)26 b(or)g(arra)m(y)g(in)f(the)h(program)
+f(do)s(es)g(not)h(need)g(to)g(b)s(e)f(the)h(same)0 5601
+y(as)i(the)f(data)h(t)m(yp)s(e)g(of)f(the)h(v)-5 b(alue)28
+b(in)f(the)g(FITS)g(\014le.)40 b(Data)28 b(t)m(yp)s(e)g(con)m(v)m
+(ersion)h(is)e(supp)s(orted)f(for)h(n)m(umerical)h(and)0
+5714 y(string)33 b(data)h(t)m(yp)s(es)f(\(if)h(the)g(string)f(con)m
+(tains)h(a)g(v)-5 b(alid)33 b(n)m(um)m(b)s(er)f(enclosed)i(in)f
+(quotes\))h(when)f(reading)g(a)h(FITS)p eop end
+%%Page: 18 24
+TeXDict begin 18 23 bop 0 299 a Fi(18)1277 b Fg(CHAPTER)29
+b(4.)72 b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0
+555 y Fi(header)g(k)m(eyw)m(ord)g(v)-5 b(alue)31 b(and)g(for)f(n)m
+(umeric)h(v)-5 b(alues)31 b(when)f(reading)h(or)g(writing)g(v)-5
+b(alues)31 b(in)f(the)h(primary)f(arra)m(y)0 668 y(or)40
+b(a)h(table)h(column.)70 b(CFITSIO)39 b(returns)h(status)g(=)h(NUM)p
+2185 668 28 4 v 33 w(O)m(VERFLO)m(W)g(if)g(the)f(con)m(v)m(erted)i
+(data)f(v)-5 b(alue)0 781 y(exceeds)33 b(the)g(range)g(of)g(the)f
+(output)g(data)i(t)m(yp)s(e.)47 b(Implicit)33 b(data)g(t)m(yp)s(e)g
+(con)m(v)m(ersion)h(is)e(not)h(supp)s(orted)d(within)0
+894 y(binary)g(tables)h(for)f(string,)g(logical,)k(complex,)d(or)f
+(double)g(complex)h(data)g(t)m(yp)s(es.)0 1054 y(In)g(addition,)h(an)m
+(y)f(table)h(column)f(ma)m(y)h(b)s(e)f(read)g(as)h(if)f(it)h(con)m
+(tained)g(string)f(v)-5 b(alues.)44 b(In)31 b(the)g(case)i(of)e(n)m
+(umeric)0 1167 y(columns)f(the)h(returned)e(string)h(will)h(b)s(e)f
+(formatted)h(using)e(the)i(TDISPn)e(displa)m(y)i(format)f(if)h(it)g
+(exists.)0 1496 y Fd(4.7)135 b(Data)46 b(Scaling)0 1746
+y Fi(When)38 b(reading)f(n)m(umerical)i(data)f(v)-5 b(alues)38
+b(in)f(the)h(primary)f(arra)m(y)h(or)g(a)g(table)h(column,)h(the)d(v)-5
+b(alues)38 b(will)h(b)s(e)0 1859 y(scaled)f(automatically)j(b)m(y)c
+(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 1972 y(v)-5 b(alues)33 b(if)f(they)g(are)h
+(presen)m(t)g(in)f(the)g(header.)47 b(The)31 b(scaled)j(data)f(that)g
+(is)f(returned)f(to)i(the)g(reading)f(program)0 2085
+y(will)f(ha)m(v)m(e)382 2316 y Fe(output)46 b(value)g(=)i(\(FITS)e
+(value\))g(*)i(BSCALE)e(+)h(BZERO)0 2546 y Fi(\(a)30
+b(corresp)s(onding)e(form)m(ula)h(using)g(TSCALn)e(and)i(TZER)m(On)e
+(is)i(used)g(when)f(reading)h(from)g(table)h(columns\).)0
+2659 y(In)h(the)i(case)g(of)f(in)m(teger)h(output)f(v)-5
+b(alues)32 b(the)h(\015oating)g(p)s(oin)m(t)f(scaled)g(v)-5
+b(alue)33 b(is)f(truncated)g(to)h(an)f(in)m(teger)h(\(not)0
+2772 y(rounded)38 b(to)i(the)g(nearest)g(in)m(teger\).)70
+b(The)39 b(ftpscl)g(and)g(fttscl)i(subroutines)d(ma)m(y)i(b)s(e)f(used)
+g(to)h(o)m(v)m(erride)h(the)0 2885 y(scaling)30 b(parameters)f
+(de\014ned)e(in)h(the)h(header)f(\(e.g.,)j(to)e(turn)f(o\013)h(the)f
+(scaling)i(so)f(that)g(the)g(program)f(can)h(read)0 2998
+y(the)i(ra)m(w)f(unscaled)g(v)-5 b(alues)31 b(from)f(the)g(FITS)g
+(\014le\).)0 3158 y(When)44 b(writing)h(n)m(umerical)g(data)g(to)g(the)
+g(primary)f(arra)m(y)h(or)f(to)h(a)g(table)h(column)e(the)h(data)g(v)-5
+b(alues)45 b(will)0 3271 y(generally)29 b(b)s(e)f(automatically)j(in)m
+(v)m(ersely)f(scaled)f(b)m(y)f(the)g(v)-5 b(alue)29 b(of)f(the)h
+(BSCALE)e(and)h(BZER)m(O)g(\(or)h(TSCALn)0 3384 y(and)h(TZER)m(On\))g
+(header)g(k)m(eyw)m(ord)h(v)-5 b(alues)31 b(if)g(they)g(they)g(exist)g
+(in)f(the)h(header.)42 b(These)30 b(k)m(eyw)m(ords)h(m)m(ust)g(ha)m(v)m
+(e)0 3497 y(b)s(een)f(written)h(to)h(the)g(header)e(b)s(efore)h(an)m(y)
+h(data)f(is)g(written)h(for)e(them)i(to)f(ha)m(v)m(e)i(an)m(y)e
+(e\013ect.)44 b(Otherwise,)32 b(one)0 3610 y(ma)m(y)i(use)f(the)g
+(ftpscl)g(and)g(fttscl)h(subroutines)d(to)j(de\014ne)f(or)g(o)m(v)m
+(erride)h(the)f(scaling)i(k)m(eyw)m(ords)e(in)g(the)g(header)0
+3723 y(\(e.g.,)h(to)f(turn)d(o\013)j(the)f(scaling)h(so)f(that)g(the)g
+(program)g(can)g(write)g(the)g(ra)m(w)g(unscaled)g(v)-5
+b(alues)32 b(in)m(to)h(the)f(FITS)0 3836 y(\014le\).)43
+b(If)30 b(scaling)i(is)f(p)s(erformed,)e(the)i(in)m(v)m(erse)h(scaled)g
+(output)e(v)-5 b(alue)32 b(that)f(is)g(written)g(in)m(to)h(the)f(FITS)f
+(\014le)h(will)0 3949 y(ha)m(v)m(e)430 4179 y Fe(FITS)46
+b(value)h(=)g(\(\(input)f(value\))g(-)h(BZERO\))f(/)i(BSCALE)0
+4410 y Fi(\(a)39 b(corresp)s(onding)d(form)m(ula)i(using)g(TSCALn)e
+(and)h(TZER)m(On)g(is)h(used)f(when)f(writing)i(to)h(table)g
+(columns\).)0 4523 y(Rounding)19 b(to)i(the)g(nearest)g(in)m(teger,)i
+(rather)e(than)f(truncation,)j(is)d(p)s(erformed)f(when)g(writing)h(in)
+m(teger)i(datat)m(yp)s(es)0 4636 y(to)31 b(the)g(FITS)e(\014le.)0
+4965 y Fd(4.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 5215 y Fi(The)33
+b(last)i(parameter)f(in)g(nearly)g(ev)m(ery)g(FITSIO)f(subroutine)g(is)
+h(the)g(error)f(status)h(v)-5 b(alue)35 b(whic)m(h)e(is)h(b)s(oth)f(an)
+0 5328 y(input)j(and)f(an)i(output)f(parameter.)60 b(A)36
+b(returned)f(p)s(ositiv)m(e)j(v)-5 b(alue)37 b(for)f(this)h(parameter)g
+(indicates)g(an)f(error)0 5441 y(w)m(as)31 b(detected.)42
+b(A)30 b(listing)h(of)g(all)g(the)g(FITSIO)e(status)i(co)s(de)f(v)-5
+b(alues)31 b(is)f(giv)m(en)i(at)f(the)f(end)g(of)h(this)f(do)s(cumen)m
+(t.)0 5601 y(The)22 b(FITSIO)g(library)g(uses)h(an)f(`inherited)h
+(status')g(con)m(v)m(en)m(tion)i(for)e(the)g(status)g(parameter)g(whic)
+m(h)g(means)f(that)0 5714 y(if)i(a)h(subroutine)f(is)g(called)i(with)e
+(a)h(p)s(ositiv)m(e)g(input)f(v)-5 b(alue)25 b(of)g(the)f(status)h
+(parameter,)h(then)f(the)f(subroutine)g(will)p eop end
+%%Page: 19 25
+TeXDict begin 19 24 bop 0 299 a Fg(4.9.)72 b(V)-10 b(ARIABLE-LENGTH)31
+b(ARRA)-8 b(Y)31 b(F)-10 b(A)m(CILITY)30 b(IN)h(BINAR)-8
+b(Y)31 b(T)-8 b(ABLES)956 b Fi(19)0 555 y(exit)26 b(immediately)f
+(without)g(c)m(hanging)h(the)e(v)-5 b(alue)25 b(of)g(the)g(status)g
+(parameter.)39 b(Th)m(us,)25 b(if)g(one)f(passes)h(the)g(status)0
+668 y(v)-5 b(alue)31 b(returned)e(from)h(eac)m(h)i(FITSIO)d(routine)h
+(as)h(input)f(to)h(the)f(next)h(FITSIO)e(subroutine,)h(then)g(whenev)m
+(er)0 781 y(an)39 b(error)g(is)h(detected)g(all)h(further)d(FITSIO)g
+(pro)s(cessing)h(will)h(cease.)69 b(This)39 b(con)m(v)m(en)m(tion)i
+(can)f(simplify)f(the)0 894 y(error)30 b(c)m(hec)m(king)j(in)d
+(application)i(programs)f(b)s(ecause)g(it)g(is)g(not)g(necessary)g(to)g
+(c)m(hec)m(k)i(the)e(v)-5 b(alue)31 b(of)g(the)g(status)0
+1007 y(parameter)j(after)g(ev)m(ery)g(single)h(FITSIO)d(subroutine)g
+(call.)52 b(If)33 b(a)h(program)f(con)m(tains)i(a)f(sequence)g(of)g
+(sev)m(eral)0 1120 y(FITSIO)23 b(calls,)j(one)e(can)g(just)g(c)m(hec)m
+(k)h(the)f(status)g(v)-5 b(alue)24 b(after)h(the)f(last)g(call.)40
+b(Since)24 b(the)g(returned)e(status)j(v)-5 b(alues)0
+1233 y(are)36 b(generally)h(distinctiv)m(e,)i(it)d(should)f(b)s(e)g(p)s
+(ossible)g(to)h(determine)g(whic)m(h)f(subroutine)g(originally)i
+(returned)0 1346 y(the)31 b(error)f(status.)0 1506 y(FITSIO)i(also)i
+(main)m(tains)f(an)g(in)m(ternal)h(stac)m(k)g(of)f(error)g(messages)h
+(\(80-c)m(haracter)i(maxim)m(um)d(length\))g(whic)m(h)0
+1619 y(in)j(man)m(y)g(cases)h(pro)m(vide)f(a)g(more)g(detailed)i
+(explanation)f(of)f(the)g(cause)h(of)f(the)g(error)g(than)f(is)h(pro)m
+(vided)g(b)m(y)0 1732 y(the)k(error)e(status)i(n)m(um)m(b)s(er)e
+(alone.)69 b(It)39 b(is)h(recommended)f(that)g(the)h(error)f(message)h
+(stac)m(k)h(b)s(e)e(prin)m(ted)g(out)0 1844 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,)h(call)h(the)f(FTGMSG)g(routine)f(rep)s(eatedly)h
+(to)0 1957 y(get)h(the)g(successiv)m(e)g(messages)h(on)e(the)g(stac)m
+(k.)48 b(When)32 b(the)h(stac)m(k)g(is)g(empt)m(y)f(FTGMSG)h(will)g
+(return)e(a)h(blank)0 2070 y(string.)41 b(Note)31 b(that)g(this)f(is)g
+(a)g(`First)h(In)e({)i(First)f(Out')g(stac)m(k,)i(so)e(the)h(oldest)g
+(error)e(message)j(is)e(returned)f(\014rst)0 2183 y(b)m(y)h(ftgmsg.)0
+2557 y Fd(4.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 2815
+y Fi(FITSIO)38 b(pro)m(vides)i(easy-to-use)h(supp)s(ort)d(for)h
+(reading)g(and)g(writing)h(data)g(in)f(v)-5 b(ariable)40
+b(length)g(\014elds)f(of)h(a)0 2928 y(binary)35 b(table.)56
+b(The)35 b(v)-5 b(ariable)36 b(length)f(columns)g(ha)m(v)m(e)i(TF)m
+(ORMn)e(k)m(eyw)m(ord)h(v)-5 b(alues)35 b(of)h(the)f(form)g
+(`1Pt\(len\)')0 3041 y(or)30 b(`1Qt\(len\)')h(where)f(`t')g(is)g(the)g
+(datat)m(yp)s(e)h(co)s(de)f(\(e.g.,)i(I,)e(J,)f(E,)h(D,)h(etc.\))42
+b(and)29 b(`len')h(is)g(an)g(in)m(teger)h(sp)s(ecifying)0
+3154 y(the)f(maxim)m(um)g(length)g(of)g(the)g(v)m(ector)h(in)f(the)g
+(table.)41 b(If)30 b(the)g(v)-5 b(alue)30 b(of)g(`len')g(is)g(not)g(sp)
+s(eci\014ed)f(when)g(the)h(table)0 3267 y(is)j(created)g(\(e.g.,)i(if)e
+(the)f(TF)m(ORM)h(k)m(eyw)m(ord)g(v)-5 b(alue)33 b(is)g(simply)f(sp)s
+(eci\014ed)g(as)h('1PE')g(instead)g(of)f('1PE\(400\))j(\),)0
+3380 y(then)28 b(FITSIO)f(will)h(automatically)k(scan)c(the)g(table)h
+(when)f(it)g(is)h(closed)g(to)g(determine)f(the)g(maxim)m(um)h(length)0
+3493 y(of)i(the)f(v)m(ector)i(and)e(will)h(app)s(end)d(this)j(v)-5
+b(alue)30 b(to)i(the)e(TF)m(ORMn)g(v)-5 b(alue.)0 3653
+y(The)25 b(same)h(routines)g(whic)m(h)f(read)h(and)f(write)h(data)g(in)
+f(an)h(ordinary)f(\014xed)g(length)h(binary)f(table)h(extension)h(are)0
+3766 y(also)k(used)e(for)h(v)-5 b(ariable)31 b(length)g(\014elds,)e(ho)
+m(w)m(ev)m(er,)j(the)e(subroutine)f(parameters)i(tak)m(e)h(on)e(a)g
+(sligh)m(tly)h(di\013eren)m(t)0 3878 y(in)m(terpretation)h(as)e
+(describ)s(ed)g(b)s(elo)m(w.)0 4039 y(All)37 b(the)f(data)h(in)f(a)h(v)
+-5 b(ariable)37 b(length)f(\014eld)g(is)g(written)h(in)m(to)g(an)f
+(area)h(called)h(the)e(`heap')g(whic)m(h)g(follo)m(ws)i(the)0
+4152 y(main)26 b(\014xed-length)g(FITS)f(binary)h(table.)40
+b(The)25 b(size)i(of)g(the)f(heap,)h(in)f(b)m(ytes,)h(is)f(sp)s
+(eci\014ed)g(with)f(the)i(PCOUNT)0 4264 y(k)m(eyw)m(ord)21
+b(in)f(the)h(FITS)f(header.)37 b(When)20 b(creating)i(a)f(new)f(binary)
+g(table,)j(the)e(initial)h(v)-5 b(alue)21 b(of)f(PCOUNT)g(should)0
+4377 y(usually)31 b(b)s(e)f(set)i(to)g(zero.)44 b(FITSIO)30
+b(will)h(recompute)h(the)f(size)h(of)g(the)f(heap)g(as)g(the)h(data)g
+(is)f(written)g(and)g(will)0 4490 y(automatically)d(up)s(date)c(the)i
+(PCOUNT)e(k)m(eyw)m(ord)h(v)-5 b(alue)26 b(when)e(the)h(table)h(is)f
+(closed.)40 b(When)25 b(writing)g(v)-5 b(ariable)0 4603
+y(length)34 b(data)g(to)g(a)g(table,)i(CFITSIO)c(will)h(automatically)k
+(extend)c(the)h(size)g(of)g(the)g(heap)f(area)h(if)g(necessary)-8
+b(,)0 4716 y(so)31 b(that)g(an)m(y)f(follo)m(wing)i(HDUs)f(do)f(not)h
+(get)h(o)m(v)m(erwritten.)0 4876 y(By)e(default)f(the)h(heap)f(data)i
+(area)f(starts)g(immediately)h(after)f(the)f(last)i(ro)m(w)e(of)h(the)g
+(\014xed-length)f(table.)42 b(This)0 4989 y(default)27
+b(starting)g(lo)s(cation)i(ma)m(y)e(b)s(e)f(o)m(v)m(erridden)h(b)m(y)g
+(the)g(THEAP)f(k)m(eyw)m(ord,)i(but)f(this)f(is)h(not)g(recommended.)0
+5102 y(If)34 b(additional)h(ro)m(ws)f(of)g(data)h(are)g(added)e(to)i
+(the)f(table,)j(CFITSIO)32 b(will)j(automatically)i(shift)c(the)i(the)f
+(heap)0 5215 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)i(is)e(ob)m(viously)i(b)s(e)e(more)h(e\016cien)m(t)h
+(to)f(initially)h(create)h(the)0 5328 y(table)31 b(with)e(the)h
+(necessary)g(n)m(um)m(b)s(er)f(of)h(blank)f(ro)m(ws,)h(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
+5441 y(mo)m(v)m(ed.)0 5601 y(When)40 b(writing)h(to)g(a)g(v)-5
+b(ariable)41 b(length)g(\014eld,)i(the)e(en)m(tire)h(arra)m(y)f(of)f(v)
+-5 b(alues)41 b(for)f(a)h(giv)m(en)h(ro)m(w)f(of)f(the)h(table)0
+5714 y(m)m(ust)36 b(b)s(e)g(written)g(with)g(a)g(single)h(call)h(to)f
+(FTPCLx.)57 b(The)36 b(total)i(length)f(of)f(the)g(arra)m(y)h(is)f
+(calculated)i(from)p eop end
+%%Page: 20 26
+TeXDict begin 20 25 bop 0 299 a Fi(20)1277 b Fg(CHAPTER)29
+b(4.)72 b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0
+555 y Fi(\(NELEM+FELEM-1\).)44 b(One)30 b(cannot)i(app)s(end)d(more)i
+(elemen)m(ts)h(to)g(an)e(existing)i(\014eld)f(at)g(a)h(later)g(time;)g
+(an)m(y)0 668 y(attempt)j(to)f(do)g(so)g(will)g(simply)f(o)m(v)m
+(erwrite)j(all)e(the)g(data)h(whic)m(h)e(w)m(as)h(previously)g
+(written.)51 b(Note)35 b(also)f(that)0 781 y(the)g(new)g(data)g(will)h
+(b)s(e)e(written)h(to)h(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 894 y(write)j(cannot)h
+(b)s(e)e(reclaimed.)62 b(F)-8 b(or)38 b(this)f(reason)g(it)h(is)f
+(advised)g(that)h(eac)m(h)g(ro)m(w)f(of)h(a)f(v)-5 b(ariable)38
+b(length)f(\014eld)0 1007 y(only)c(b)s(e)g(written)g(once.)50
+b(An)33 b(exception)h(to)g(this)f(general)h(rule)f(o)s(ccurs)g(when)f
+(setting)i(elemen)m(ts)h(of)e(an)g(arra)m(y)0 1120 y(as)38
+b(unde\014ned.)63 b(One)37 b(m)m(ust)i(\014rst)e(write)h(a)h(dumm)m(y)e
+(v)-5 b(alue)39 b(in)m(to)g(the)g(arra)m(y)f(with)g(FTPCLx,)i(and)e
+(then)g(call)0 1233 y(FTPCLU)33 b(to)i(\015ag)f(the)f(desired)h(elemen)
+m(ts)h(as)e(unde\014ned.)49 b(\(Do)35 b(not)f(use)f(the)h(FTPCNx)f
+(family)h(of)g(routines)0 1346 y(with)28 b(v)-5 b(ariable)30
+b(length)f(\014elds\).)40 b(Note)30 b(that)f(the)g(ro)m(ws)g(of)g(a)g
+(table,)h(whether)e(\014xed)g(or)h(v)-5 b(ariable)29
+b(length,)h(do)f(not)0 1458 y(ha)m(v)m(e)j(to)f(b)s(e)e(written)i
+(consecutiv)m(ely)h(and)e(ma)m(y)h(b)s(e)f(written)g(in)g(an)m(y)h
+(order.)0 1619 y(When)40 b(writing)h(to)g(a)g(v)-5 b(ariable)41
+b(length)g(ASCI)s(I)e(c)m(haracter)j(\014eld)e(\(e.g.,)45
+b(TF)m(ORM)c(=)f('1P)-8 b(A'\))43 b(only)d(a)h(single)0
+1732 y(c)m(haracter)33 b(string)f(written.)44 b(FTPCLS)30
+b(writes)i(the)g(whole)f(length)h(of)g(the)g(input)e(string)i(\(min)m
+(us)f(an)m(y)h(trailing)0 1844 y(blank)37 b(c)m(haracters\),)42
+b(th)m(us)37 b(the)h(NELEM)f(and)g(FELEM)h(parameters)g(are)g(ignored.)
+62 b(If)37 b(the)h(input)e(string)i(is)0 1957 y(completely)28
+b(blank)f(then)f(FITSIO)g(will)h(write)g(one)g(blank)f(c)m(haracter)j
+(to)e(the)g(FITS)f(\014le.)40 b(Similarly)-8 b(,)28 b(FTGCVS)0
+2070 y(and)35 b(FTGCFS)g(read)g(the)h(en)m(tire)g(string)g(\(truncated)
+f(to)i(the)e(width)g(of)g(the)h(c)m(haracter)h(string)e(argumen)m(t)h
+(in)0 2183 y(the)31 b(subroutine)e(call\))j(and)e(also)h(ignore)g(the)f
+(NELEM)h(and)f(FELEM)g(parameters.)0 2343 y(The)35 b(FTPDES)h
+(subroutine)e(is)i(useful)f(in)g(situations)i(where)e(m)m(ultiple)i(ro)
+m(ws)e(of)h(a)g(v)-5 b(ariable)37 b(length)f(column)0
+2456 y(ha)m(v)m(e)c(the)e(iden)m(tical)i(arra)m(y)f(of)g(v)-5
+b(alues.)41 b(One)30 b(can)g(simply)g(write)h(the)f(arra)m(y)h(once)g
+(for)g(the)f(\014rst)g(ro)m(w,)g(and)g(then)0 2569 y(use)36
+b(FTPDES)g(to)h(write)g(the)f(same)h(descriptor)g(v)-5
+b(alues)36 b(in)m(to)i(the)e(other)h(ro)m(ws)f(\(use)h(the)f(FTGDES)h
+(routine)0 2682 y(to)f(read)f(the)h(\014rst)f(descriptor)g(v)-5
+b(alue\);)39 b(all)d(the)g(ro)m(ws)f(will)h(then)f(p)s(oin)m(t)g(to)h
+(the)g(same)f(storage)i(lo)s(cation)g(th)m(us)0 2795
+y(sa)m(ving)31 b(disk)f(space.)0 2955 y(When)35 b(reading)g(from)f(a)i
+(v)-5 b(ariable)35 b(length)h(arra)m(y)f(\014eld)g(one)g(can)g(only)h
+(read)e(as)i(man)m(y)f(elemen)m(ts)h(as)f(actually)0
+3068 y(exist)i(in)e(that)i(ro)m(w)e(of)h(the)g(table;)k(reading)c(do)s
+(es)g(not)g(automatically)i(con)m(tin)m(ue)f(with)f(the)g(next)g(ro)m
+(w)g(of)g(the)0 3181 y(table)29 b(as)f(o)s(ccurs)g(when)f(reading)h(an)
+g(ordinary)g(\014xed)f(length)h(table)h(\014eld.)40 b(A)m(ttempts)29
+b(to)g(read)f(more)g(than)g(this)0 3294 y(will)k(cause)h(an)e(error)h
+(status)g(to)g(b)s(e)f(returned.)44 b(One)32 b(can)g(determine)g(the)g
+(n)m(um)m(b)s(er)e(of)i(elemen)m(ts)h(in)f(eac)m(h)h(ro)m(w)0
+3407 y(of)e(a)f(v)-5 b(ariable)31 b(column)g(with)f(the)g(FTGDES)h
+(subroutine.)0 3859 y Fd(4.10)136 b(Supp)t(ort)44 b(for)h(IEEE)g(Sp)t
+(ecial)h(V)-11 b(alues)0 4133 y Fi(The)26 b(ANSI/IEEE-754)h
+(\015oating-p)s(oin)m(t)h(n)m(um)m(b)s(er)d(standard)g(de\014nes)h
+(certain)h(sp)s(ecial)g(v)-5 b(alues)26 b(that)h(are)g(used)e(to)0
+4246 y(represen)m(t)j(suc)m(h)g(quan)m(tities)h(as)f(Not-a-Num)m(b)s
+(er)h(\(NaN\),)h(denormalized,)f(under\015o)m(w,)e(o)m(v)m(er\015o)m
+(w,)j(and)d(in\014nit)m(y)-8 b(.)0 4359 y(\(See)29 b(the)f(App)s(endix)
+e(in)i(the)g(NOST)g(FITS)f(standard)g(or)h(the)g(NOST)g(FITS)f(User's)h
+(Guide)g(for)g(a)g(list)h(of)f(these)0 4472 y(v)-5 b(alues\).)41
+b(The)30 b(FITSIO)f(subroutines)g(that)i(read)f(\015oating)i(p)s(oin)m
+(t)e(data)h(in)f(FITS)f(\014les)i(recognize)h(these)f(IEEE)0
+4585 y(sp)s(ecial)40 b(v)-5 b(alues)39 b(and)g(b)m(y)g(default)g(in)m
+(terpret)h(the)f(o)m(v)m(er\015o)m(w)i(and)d(in\014nit)m(y)h(v)-5
+b(alues)40 b(as)f(b)s(eing)g(equiv)-5 b(alen)m(t)41 b(to)f(a)0
+4698 y(NaN,)35 b(and)e(con)m(v)m(ert)i(the)f(under\015o)m(w)e(and)h
+(denormalized)h(v)-5 b(alues)34 b(in)m(to)h(zeros.)51
+b(In)33 b(some)h(cases)h(programmers)0 4811 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,)32
+b(without)f(an)m(y)h(mo)s(di\014cation)f(b)m(y)g(FITSIO.)g(This)f(can)i
+(b)s(e)e(done)0 4924 y(b)m(y)k(calling)j(the)d(FTGPVx)h(or)g(FTGCVx)g
+(routines)f(while)h(sp)s(ecifying)f(0.0)i(as)f(the)f(v)-5
+b(alue)35 b(of)g(the)g(NULL)-10 b(V)g(AL)0 5036 y(parameter.)72
+b(This)39 b(will)i(force)g(FITSIO)e(to)j(simply)e(pass)g(the)g(IEEE)g
+(v)-5 b(alues)41 b(through)f(to)h(the)g(application)0
+5149 y(program,)30 b(without)g(an)m(y)g(mo)s(di\014cation.)41
+b(This)30 b(do)s(es)f(not)h(w)m(ork)g(for)g(double)g(precision)g(v)-5
+b(alues)30 b(on)g(V)-10 b(AX/VMS)0 5262 y(mac)m(hines,)38
+b(ho)m(w)m(ev)m(er,)h(where)d(there)g(is)g(no)g(easy)g(w)m(a)m(y)h(to)g
+(b)m(ypass)f(the)g(default)g(in)m(terpretation)h(of)f(the)h(IEEE)0
+5375 y(sp)s(ecial)45 b(v)-5 b(alues.)83 b(This)44 b(is)h(also)g(not)g
+(supp)s(orted)d(when)i(reading)h(\015oating-p)s(oin)m(t)g(images)h
+(that)f(ha)m(v)m(e)h(b)s(een)0 5488 y(compressed)29 b(with)h(the)f
+(FITS)g(tiled)i(image)f(compression)g(con)m(v)m(en)m(tion)i(that)e(is)g
+(discussed)e(in)i(section)h(5.6;)g(the)0 5601 y(pixels)k(v)-5
+b(alues)35 b(in)g(tile)g(compressed)g(images)h(are)f(represen)m(ted)g
+(b)m(y)f(scaled)i(in)m(tegers,)h(and)d(a)i(reserv)m(ed)f(in)m(teger)0
+5714 y(v)-5 b(alue)31 b(\(not)g(a)g(NaN\))g(is)f(used)g(to)h(represen)m
+(t)g(unde\014ned)d(pixels.)p eop end
+%%Page: 21 27
+TeXDict begin 21 26 bop 0 299 a Fg(4.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(21)0 555 y Fd(4.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 805 y Fi(It)27 b(is)h(not)f(required)f
+(to)i(kno)m(w)f(the)h(total)h(size)f(of)f(a)h(FITS)e(data)i(arra)m(y)g
+(or)f(table)h(b)s(efore)f(b)s(eginning)f(to)i(write)g(the)0
+918 y(data)k(to)f(the)g(FITS)f(\014le.)43 b(In)30 b(the)h(case)h(of)f
+(the)g(primary)f(arra)m(y)h(or)g(an)f(image)j(extension,)e(one)h
+(should)d(initially)0 1031 y(create)i(the)e(arra)m(y)h(with)e(the)i
+(size)g(of)f(the)g(highest)g(dimension)g(\(largest)i(NAXISn)d(k)m(eyw)m
+(ord\))i(set)g(to)g(a)f(dumm)m(y)0 1144 y(v)-5 b(alue,)26
+b(suc)m(h)e(as)g(1.)39 b(Then)23 b(after)i(all)g(the)g(data)f(ha)m(v)m
+(e)i(b)s(een)d(written)h(and)g(the)g(true)g(dimensions)g(are)g(kno)m
+(wn,)h(then)0 1257 y(the)31 b(NAXISn)e(v)-5 b(alue)31
+b(should)f(b)s(e)g(up)s(dated)f(using)h(the)h(\014ts)p
+2051 1257 28 4 v 62 w(up)s(date)p 2389 1257 V 32 w(k)m(ey)h(routine)e
+(b)s(efore)g(mo)m(ving)i(to)f(another)0 1370 y(extension)g(or)f
+(closing)i(the)e(FITS)g(\014le.)0 1530 y(When)f(writing)g(to)g(FITS)g
+(tables,)h(CFITSIO)d(automatically)32 b(k)m(eeps)e(trac)m(k)g(of)f(the)
+g(highest)h(ro)m(w)f(n)m(um)m(b)s(er)e(that)0 1643 y(is)32
+b(written)g(to,)h(and)e(will)h(increase)h(the)f(size)h(of)f(the)g
+(table)g(if)g(necessary)-8 b(.)46 b(CFITSIO)30 b(will)i(also)h
+(automatically)0 1756 y(insert)j(space)h(in)f(the)g(FITS)f(\014le)i(if)
+f(necessary)-8 b(,)39 b(to)e(ensure)e(that)i(the)f(data)h('heap',)h(if)
+e(it)h(exists,)h(and/or)f(an)m(y)0 1869 y(additional)29
+b(HDUs)g(that)g(follo)m(w)g(the)g(table)g(do)f(not)h(get)g(o)m(v)m
+(erwritten)h(as)e(new)g(ro)m(ws)g(are)h(written)f(to)h(the)g(table.)0
+2029 y(As)37 b(a)h(general)g(rule)f(it)h(is)f(b)s(est)g(to)h(sp)s
+(ecify)f(the)h(initial)g(n)m(um)m(b)s(er)e(of)i(ro)m(ws)f(=)g(0)g(when)
+g(the)g(table)h(is)g(created,)0 2142 y(then)g(let)h(CFITSIO)e(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)i(written.)65 b(The)38 b(application)0 2255
+y(program)e(should)f(not)i(man)m(ually)g(up)s(date)e(the)i(n)m(um)m(b)s
+(er)e(of)h(ro)m(ws)g(in)g(the)h(table)g(\(as)g(giv)m(en)g(b)m(y)f(the)h
+(NAXIS2)0 2368 y(k)m(eyw)m(ord\))j(since)f(CFITSIO)e(do)s(es)i(this)g
+(automatically)-8 b(.)69 b(If)38 b(a)i(table)f(is)g(initially)i
+(created)f(with)e(more)h(than)0 2481 y(zero)i(ro)m(ws,)j(then)c(this)h
+(will)f(usually)h(b)s(e)f(considered)g(as)h(the)g(minim)m(um)f(size)h
+(of)g(the)g(table,)j(ev)m(en)d(if)g(few)m(er)0 2594 y(ro)m(ws)30
+b(are)g(actually)h(written)f(to)h(the)f(table.)41 b(Th)m(us,)30
+b(if)f(a)i(table)f(is)g(initially)h(created)g(with)f(NAXIS2)g(=)g(20,)h
+(and)0 2706 y(CFITSIO)g(only)i(writes)f(10)i(ro)m(ws)e(of)h(data)g(b)s
+(efore)f(closing)i(the)f(table,)h(then)e(NAXIS2)h(will)g(remain)f
+(equal)h(to)0 2819 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)f(to)h(this)f(table,)i(then)e(NAXIS2)h
+(will)f(b)s(e)g(increased)g(from)g(20)0 2932 y(to)f(30.)44
+b(The)31 b(one)g(exception)i(to)f(this)f(automatic)i(up)s(dating)d(of)h
+(the)h(NAXIS2)f(k)m(eyw)m(ord)h(is)f(if)g(the)h(application)0
+3045 y(program)c(directly)g(mo)s(di\014es)f(the)i(v)-5
+b(alue)28 b(of)g(NAXIS2)g(\(up)f(or)h(do)m(wn\))g(itself)h(just)e(b)s
+(efore)h(closing)h(the)f(table.)41 b(In)0 3158 y(this)28
+b(case,)i(CFITSIO)d(do)s(es)h(not)h(up)s(date)e(NAXIS2)i(again,)h
+(since)f(it)g(assumes)f(that)h(the)f(application)i(program)0
+3271 y(m)m(ust)i(ha)m(v)m(e)h(had)f(a)g(go)s(o)s(d)g(reason)h(for)f(c)m
+(hanging)h(the)f(v)-5 b(alue)33 b(directly)-8 b(.)47
+b(This)31 b(is)h(not)h(recommended,)f(ho)m(w)m(ev)m(er,)0
+3384 y(and)j(is)h(only)g(pro)m(vided)g(for)f(bac)m(kw)m(ard)h
+(compatibilit)m(y)i(with)e(soft)m(w)m(are)h(that)g(initially)g(creates)
+g(a)f(table)h(with)0 3497 y(a)d(large)h(n)m(um)m(b)s(er)e(of)h(ro)m
+(ws,)h(than)f(decreases)g(the)h(NAXIS2)f(v)-5 b(alue)34
+b(to)h(the)f(actual)h(smaller)g(v)-5 b(alue)34 b(just)f(b)s(efore)0
+3610 y(closing)e(the)g(table.)0 3941 y Fd(4.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
+4191 y Fi(CFITSIO)25 b(supp)s(orts)g(sev)m(eral)j(lo)s(cal)f(FITS)f
+(con)m(v)m(en)m(tions)j(whic)m(h)d(are)h(not)g(de\014ned)e(in)h(the)h
+(o\016cial)h(NOST)e(FITS)0 4304 y(standard)k(and)g(whic)m(h)h(are)g
+(not)g(necessarily)g(recognized)h(or)f(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 4417 y(Programmers)36
+b(should)f(b)s(e)g(cautious)i(ab)s(out)e(using)h(these)g(features,)i
+(esp)s(ecially)f(if)f(the)g(FITS)f(\014les)h(that)h(are)0
+4530 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)f(do)h(not)f(use)h
+(the)f(CFITSIO)0 4642 y(in)m(terface.)0 4930 y Fb(4.12.1)113
+b(Supp)s(ort)37 b(for)h(Long)g(String)f(Keyw)m(ord)h(V)-9
+b(alues.)0 5149 y Fi(The)23 b(length)i(of)f(a)g(standard)f(FITS)g
+(string)h(k)m(eyw)m(ord)g(is)g(limited)h(to)f(68)h(c)m(haracters)g(b)s
+(ecause)f(it)g(m)m(ust)g(\014t)g(en)m(tirely)0 5262 y(within)35
+b(a)h(single)h(FITS)e(header)h(k)m(eyw)m(ord)g(record.)57
+b(In)35 b(some)h(instances)g(it)h(is)e(necessary)i(to)f(enco)s(de)g
+(strings)0 5375 y(longer)27 b(than)f(this)g(limit,)i(so)e(FITSIO)f
+(supp)s(orts)f(a)j(lo)s(cal)g(con)m(v)m(en)m(tion)h(in)e(whic)m(h)g
+(the)g(string)g(v)-5 b(alue)27 b(is)f(con)m(tin)m(ued)0
+5488 y(o)m(v)m(er)34 b(m)m(ultiple)g(k)m(eyw)m(ords.)49
+b(This)32 b(con)m(tin)m(uation)j(con)m(v)m(en)m(tion)h(uses)c(an)h(amp)
+s(ersand)f(c)m(haracter)i(at)g(the)f(end)g(of)0 5601
+y(eac)m(h)c(substring)d(to)i(indicate)h(that)f(it)g(is)g(con)m(tin)m
+(ued)g(on)f(the)h(next)g(k)m(eyw)m(ord,)h(and)d(the)i(con)m(tin)m
+(uation)i(k)m(eyw)m(ords)0 5714 y(all)44 b(ha)m(v)m(e)h(the)f(name)f
+(CONTINUE)g(without)g(an)h(equal)g(sign)f(in)g(column)h(9.)80
+b(The)43 b(string)h(v)-5 b(alue)43 b(ma)m(y)i(b)s(e)p
+eop end
+%%Page: 22 28
+TeXDict begin 22 27 bop 0 299 a Fi(22)1277 b Fg(CHAPTER)29
+b(4.)72 b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0
+555 y Fi(con)m(tin)m(ued)e(in)f(this)h(w)m(a)m(y)g(o)m(v)m(er)h(as)e
+(man)m(y)h(additional)g(CONTINUE)f(k)m(eyw)m(ords)g(as)h(is)f
+(required.)40 b(The)27 b(follo)m(wing)0 668 y(lines)k(illustrate)g
+(this)f(con)m(tin)m(uation)j(con)m(v)m(en)m(tion)f(whic)m(h)e(is)h
+(used)e(in)h(the)h(v)-5 b(alue)31 b(of)f(the)h(STRKEY)e(k)m(eyw)m(ord:)
+0 920 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 1033 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 1146 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 1259 y(CONTINUE)e('FITS)47 b(header.')e(/)j(This)e(is)h(another)f
+(optional)g(comment.)0 1511 y Fi(It)29 b(is)g(recommended)f(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)i(b)
+s(e)d(included)g(in)g(an)m(y)h(HDU)0 1624 y(that)f(uses)e(this)h
+(longstring)h(con)m(v)m(en)m(tion.)42 b(A)27 b(subroutine)f(called)i
+(FTPLSW)f(has)g(b)s(een)f(pro)m(vided)h(in)f(CFITSIO)0
+1737 y(to)31 b(write)g(this)f(k)m(eyw)m(ord)h(if)f(it)h(do)s(es)f(not)h
+(already)g(exist.)0 1897 y(This)23 b(long)i(string)g(con)m(v)m(en)m
+(tion)h(is)e(supp)s(orted)f(b)m(y)h(the)g(follo)m(wing)i(FITSIO)d
+(subroutines)g(that)i(deal)g(with)f(string-)0 2010 y(v)-5
+b(alued)30 b(k)m(eyw)m(ords:)286 2262 y Fe(ftgkys)46
+b(-)i(read)f(a)g(string)f(keyword)286 2375 y(ftpkls)g(-)i(write)e
+(\(append\))g(a)h(string)f(keyword)286 2488 y(ftikls)g(-)i(insert)e(a)h
+(string)g(keyword)286 2601 y(ftmkls)f(-)i(modify)e(the)h(value)f(of)h
+(an)h(existing)d(string)h(keyword)286 2714 y(ftukls)g(-)i(update)e(an)h
+(existing)f(keyword,)f(or)i(write)g(a)g(new)g(keyword)286
+2827 y(ftdkey)f(-)i(delete)e(a)h(keyword)0 3079 y Fi(These)41
+b(routines)f(will)h(transparen)m(tly)g(read,)j(write,)g(or)d(delete)h
+(a)f(long)g(string)g(v)-5 b(alue)41 b(in)g(the)g(FITS)f(\014le,)k(so)0
+3192 y(programmers)36 b(in)g(general)h(do)f(not)h(ha)m(v)m(e)g(to)g(b)s
+(e)f(concerned)g(ab)s(out)g(the)g(details)i(of)e(the)h(con)m(v)m(en)m
+(tion)h(that)f(is)0 3304 y(used)32 b(to)i(enco)s(de)f(the)g(long)g
+(string)g(in)g(the)g(FITS)f(header.)48 b(When)33 b(reading)g(a)g(long)h
+(string,)g(one)f(m)m(ust)g(ensure)0 3417 y(that)h(the)f(c)m(haracter)i
+(string)f(parameter)g(used)e(in)h(these)h(subroutine)e(calls)j(has)e(b)
+s(een)f(declared)i(long)g(enough)0 3530 y(to)d(hold)f(the)h(en)m(tire)g
+(string,)g(otherwise)f(the)h(returned)e(string)h(v)-5
+b(alue)31 b(will)g(b)s(e)f(truncated.)0 3690 y(Note)d(that)e(the)h
+(more)f(commonly)h(used)e(FITSIO)g(subroutine)h(to)h(write)f(string)g
+(v)-5 b(alued)25 b(k)m(eyw)m(ords)h(\(FTPKYS\))0 3803
+y(do)s(es)38 b(NOT)g(supp)s(ort)f(this)h(long)h(string)g(con)m(v)m(en)m
+(tion)h(and)e(only)h(supp)s(orts)d(strings)i(up)g(to)h(68)g(c)m
+(haracters)h(in)0 3916 y(length.)i(This)30 b(has)g(b)s(een)g(done)h
+(delib)s(erately)g(to)h(prev)m(en)m(t)f(programs)g(from)f(inadv)m
+(erten)m(tly)i(writing)f(k)m(eyw)m(ords)0 4029 y(using)38
+b(this)h(non-standard)e(con)m(v)m(en)m(tion)k(without)e(the)f(explicit)
+i(in)m(ten)m(t)g(of)f(the)g(programmer)f(or)h(user.)64
+b(The)0 4142 y(FTPKLS)28 b(subroutine)g(m)m(ust)h(b)s(e)g(called)h
+(instead)g(to)g(write)f(long)h(strings.)40 b(This)28
+b(routine)i(can)f(also)h(b)s(e)f(used)f(to)0 4255 y(write)j(ordinary)e
+(string)i(v)-5 b(alues)30 b(less)h(than)f(68)h(c)m(haracters)h(in)e
+(length.)0 4544 y Fb(4.12.2)113 b(Arra)m(ys)37 b(of)g(Fixed-Length)j
+(Strings)e(in)f(Binary)h(T)-9 b(ables)0 4763 y Fi(CFITSIO)25
+b(supp)s(orts)g(2)i(w)m(a)m(ys)g(to)g(sp)s(ecify)f(that)i(a)f(c)m
+(haracter)h(column)e(in)g(a)h(binary)f(table)i(con)m(tains)f(an)g(arra)
+m(y)g(of)0 4876 y(\014xed-length)32 b(strings.)46 b(The)32
+b(\014rst)f(w)m(a)m(y)-8 b(,)34 b(whic)m(h)e(is)g(o\016cially)i(supp)s
+(orted)c(b)m(y)i(the)h(FITS)e(Standard)g(do)s(cumen)m(t,)0
+4989 y(uses)38 b(the)g(TDIMn)g(k)m(eyw)m(ord.)65 b(F)-8
+b(or)39 b(example,)i(if)d(TF)m(ORMn)g(=)g('60A')h(and)f(TDIMn)g(=)g
+('\(12,5\)')i(then)e(that)0 5102 y(column)30 b(will)h(b)s(e)f(in)m
+(terpreted)g(as)h(con)m(taining)h(an)e(arra)m(y)h(of)g(5)f(strings,)h
+(eac)m(h)g(12)g(c)m(haracters)h(long.)0 5262 y(FITSIO)40
+b(also)i(supp)s(orts)d(a)i(lo)s(cal)h(con)m(v)m(en)m(tion)h(for)e(the)g
+(format)h(of)f(the)g(TF)m(ORMn)g(k)m(eyw)m(ord)g(v)-5
+b(alue)42 b(of)f(the)0 5375 y(form)h('rAw')g(where)g('r')g(is)h(an)f
+(in)m(teger)i(sp)s(ecifying)e(the)g(total)j(width)c(in)h(c)m(haracters)
+i(of)f(the)f(column,)k(and)0 5488 y('w')36 b(is)g(an)g(in)m(teger)h(sp)
+s(ecifying)f(the)g(\(\014xed\))g(length)h(of)f(an)g(individual)f(unit)h
+(string)f(within)h(the)g(v)m(ector.)59 b(F)-8 b(or)0
+5601 y(example,)47 b(TF)m(ORM1)d(=)f('120A10')j(w)m(ould)d(indicate)h
+(that)f(the)h(binary)e(table)i(column)f(is)g(120)h(c)m(haracters)0
+5714 y(wide)32 b(and)g(consists)h(of)g(12)g(10-c)m(haracter)i(length)e
+(strings.)47 b(This)31 b(con)m(v)m(en)m(tion)k(is)d(recognized)i(b)m(y)
+e(the)h(FITSIO)p eop end
+%%Page: 23 29
+TeXDict begin 23 28 bop 0 299 a Fg(4.12.)73 b(LOCAL)29
+b(FITS)h(CONVENTIONS)f(SUPPOR)-8 b(TED)29 b(BY)i(FITSIO)1168
+b Fi(23)0 555 y(subroutines)40 b(that)h(read)g(or)g(write)g(strings)f
+(in)h(binary)f(tables.)73 b(The)40 b(Binary)h(T)-8 b(able)42
+b(de\014nition)e(do)s(cumen)m(t)0 668 y(sp)s(eci\014es)31
+b(that)i(other)e(optional)i(c)m(haracters)g(ma)m(y)g(follo)m(w)g(the)e
+(datat)m(yp)s(e)i(co)s(de)f(in)f(the)h(TF)m(ORM)g(k)m(eyw)m(ord,)h(so)0
+781 y(this)j(lo)s(cal)i(con)m(v)m(en)m(tion)h(is)e(in)f(compliance)i
+(with)e(the)h(FITS)f(standard,)h(although)g(other)g(FITS)f(readers)h
+(are)0 894 y(not)31 b(required)e(to)i(recognize)h(this)f(con)m(v)m(en)m
+(tion.)0 1054 y(The)25 b(Binary)h(T)-8 b(able)27 b(de\014nition)e(do)s
+(cumen)m(t)h(that)h(w)m(as)f(appro)m(v)m(ed)g(b)m(y)g(the)g(IA)m(U)g
+(in)g(1994)i(con)m(tains)f(an)e(app)s(endix)0 1167 y(describing)d(an)h
+(alternate)h(con)m(v)m(en)m(tion)h(for)e(sp)s(ecifying)f(arra)m(ys)h
+(of)g(\014xed)f(or)h(v)-5 b(ariable)24 b(length)f(strings)f(in)h(a)g
+(binary)0 1280 y(table)35 b(c)m(haracter)g(column)f(\(with)g(the)h
+(form)e('rA:SSTRw/nnn\)'.)50 b(This)33 b(app)s(endix)f(w)m(as)j(not)f
+(o\016cially)i(v)m(oted)0 1393 y(on)30 b(b)m(y)h(the)f(IA)m(U)h(and)f
+(hence)g(is)h(still)g(pro)m(visional.)42 b(FITSIO)29
+b(do)s(es)h(not)h(curren)m(tly)f(supp)s(ort)f(this)h(prop)s(osal.)0
+1687 y Fb(4.12.3)113 b(Keyw)m(ord)37 b(Units)h(Strings)0
+1907 y Fi(One)f(de\014ciency)h(of)g(the)g(curren)m(t)g(FITS)f(Standard)
+f(is)i(that)h(it)f(do)s(es)f(not)h(de\014ne)f(a)i(sp)s(eci\014c)e(con)m
+(v)m(en)m(tion)j(for)0 2020 y(recording)30 b(the)g(ph)m(ysical)h(units)
+f(of)g(a)g(k)m(eyw)m(ord)h(v)-5 b(alue.)41 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)f(the)0
+2133 y(ph)m(ysical)36 b(units)f(of)g(the)h(v)-5 b(alues)36
+b(in)f(a)g(table)i(column,)f(but)f(there)g(is)h(no)f(analogous)i(con)m
+(v)m(en)m(tion)g(for)e(k)m(eyw)m(ord)0 2246 y(v)-5 b(alues.)42
+b(The)30 b(commen)m(t)h(\014eld)g(of)f(the)h(k)m(eyw)m(ord)g(is)g
+(often)g(used)f(for)g(this)g(purp)s(ose,)g(but)f(the)i(units)f(are)h
+(usually)0 2359 y(not)g(sp)s(eci\014ed)e(in)h(a)h(w)m(ell)g(de\014ned)f
+(format)g(that)h(FITS)f(readers)g(can)h(easily)g(recognize)h(and)e
+(extract.)0 2519 y(T)-8 b(o)28 b(solv)m(e)h(this)e(de\014ciency)-8
+b(,)30 b(FITSIO)c(uses)h(a)h(lo)s(cal)h(con)m(v)m(en)m(tion)h(in)d
+(whic)m(h)g(the)h(k)m(eyw)m(ord)g(units)f(are)h(enclosed)g(in)0
+2632 y(square)20 b(brac)m(k)m(ets)j(as)e(the)f(\014rst)g(tok)m(en)i(in)
+f(the)f(k)m(eyw)m(ord)i(commen)m(t)f(\014eld;)j(more)d(sp)s
+(eci\014cally)-8 b(,)24 b(the)d(op)s(ening)f(square)0
+2745 y(brac)m(k)m(et)28 b(immediately)g(follo)m(ws)f(the)g(slash)f('/')
+h(commen)m(t)h(\014eld)e(delimiter)h(and)f(a)g(single)h(space)g(c)m
+(haracter.)41 b(The)0 2858 y(follo)m(wing)32 b(examples)f(illustrate)g
+(k)m(eyw)m(ords)g(that)g(use)f(this)g(con)m(v)m(en)m(tion:)0
+3121 y Fe(EXPOSURE=)713 b(1800.0)47 b(/)g([s])g(elapsed)f(exposure)f
+(time)0 3234 y(V_HELIO)h(=)763 b(16.23)47 b(/)g([km)g(s**\(-1\)])e
+(heliocentric)g(velocity)0 3347 y(LAMBDA)94 b(=)763 b(5400.)47
+b(/)g([angstrom])e(central)h(wavelength)0 3460 y(FLUX)190
+b(=)47 b(4.9033487787637465E-30)42 b(/)47 b([J/cm**2/s])e(average)h
+(flux)0 3723 y Fi(In)28 b(general,)h(the)g(units)e(named)h(in)g(the)h
+(IA)m(U\(1988\))i(St)m(yle)e(Guide)f(are)h(recommended,)f(with)g(the)h
+(main)f(excep-)0 3836 y(tion)j(that)g(the)f(preferred)g(unit)f(for)i
+(angle)g(is)f('deg')i(for)e(degrees.)0 3996 y(The)24
+b(FTPUNT)g(and)g(FTGUNT)h(subroutines)f(in)g(FITSIO)f(write)i(and)f
+(read,)i(resp)s(ectiv)m(ely)-8 b(,)28 b(the)c(k)m(eyw)m(ord)h(unit)0
+4109 y(strings)30 b(in)g(an)h(existing)g(k)m(eyw)m(ord.)0
+4403 y Fb(4.12.4)113 b(HIERAR)m(CH)34 b(Con)m(v)m(en)m(tion)k(for)f
+(Extended)h(Keyw)m(ord)f(Names)0 4623 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)i(whic)m(h)e(allo)m
+(ws)h(k)m(eyw)m(ord)f(names)g(that)h(are)0 4736 y(longer)34
+b(then)e(8)i(c)m(haracters)g(and)f(ma)m(y)h(con)m(tain)g(the)f(full)g
+(range)g(of)h(prin)m(table)f(ASCI)s(I)e(text)j(c)m(haracters.)51
+b(This)0 4849 y(con)m(v)m(en)m(tion)39 b(w)m(as)f(dev)m(elop)s(ed)f(at)
+h(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 4962
+y(FITS)30 b(k)m(eyw)m(ord)g(suc)m(h)h(as:)0 5225 y Fe(HIERARCH)46
+b(ESO)g(INS)h(FOCU)g(POS)g(=)g(-0.00002500)e(/)j(Focus)e(position)0
+5488 y Fi(Basically)-8 b(,)55 b(this)47 b(con)m(v)m(en)m(tion)j(uses)d
+(the)h(FITS)f(k)m(eyw)m(ord)h('HIERAR)m(CH')h(to)f(indicate)h(that)f
+(this)f(con)m(v)m(en-)0 5601 y(tion)e(is)f(b)s(eing)g(used,)j(then)d
+(the)g(actual)i(k)m(eyw)m(ord)e(name)h(\()p Fe('ESO)i(INS)f(FOCU)h
+(POS')c Fi(in)h(this)g(example\))h(b)s(e-)0 5714 y(gins)40
+b(in)f(column)g(10)i(and)e(can)h(con)m(tain)g(an)m(y)g(prin)m(table)g
+(ASCI)s(I)e(text)j(c)m(haracters,)i(including)d(spaces.)68
+b(The)p eop end
+%%Page: 24 30
+TeXDict begin 24 29 bop 0 299 a Fi(24)1277 b Fg(CHAPTER)29
+b(4.)72 b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0
+555 y Fi(equals)44 b(sign)h(marks)e(the)h(end)g(of)g(the)g(k)m(eyw)m
+(ord)h(name)f(and)f(is)i(follo)m(w)m(ed)g(b)m(y)f(the)g(usual)g(v)-5
+b(alue)45 b(and)e(com-)0 668 y(men)m(t)31 b(\014elds)f(just)g(as)h(in)f
+(standard)g(FITS)g(k)m(eyw)m(ords.)41 b(F)-8 b(urther)30
+b(details)i(of)f(this)f(con)m(v)m(en)m(tion)j(are)e(describ)s(ed)e(at)0
+781 y(h)m(ttp://arcdev.hq.eso.org/dicb/dicd/dic-1-1.4.)q(h)m(tml)36
+b(\(searc)m(h)c(for)e(HIERAR)m(CH\).)0 941 y(This)43
+b(con)m(v)m(en)m(tion)k(allo)m(ws)f(a)e(m)m(uc)m(h)h(broader)e(range)i
+(of)f(k)m(eyw)m(ord)h(names)f(than)h(is)f(allo)m(w)m(ed)i(b)m(y)e(the)h
+(FITS)0 1054 y(Standard.)40 b(Here)30 b(are)h(more)g(examples)g(of)f
+(suc)m(h)g(k)m(eyw)m(ords:)0 1296 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
+1409 y(HIERARCH)g(XTE$TEMP)f(=)j(98.6)e(/)i(Keyword)d(contains)h(the)h
+('$')g(character)0 1522 y(HIERARCH)f(Earth)g(is)h(a)h(star)e(=)i(F)f(/)
+h(Keyword)d(contains)h(embedded)f(spaces)0 1764 y Fi(CFITSIO)40
+b(will)i(transparen)m(tly)g(read)g(and)f(write)g(these)i(k)m(eyw)m
+(ords,)i(so)d(application)h(programs)e(do)g(not)h(in)0
+1877 y(general)33 b(need)f(to)h(kno)m(w)f(an)m(ything)h(ab)s(out)f(the)
+g(sp)s(eci\014c)g(implemen)m(tation)i(details)f(of)g(the)f(HIERAR)m(CH)
+g(con-)0 1990 y(v)m(en)m(tion.)50 b(In)32 b(particular,)j(application)f
+(programs)e(do)h(not)h(need)e(to)i(sp)s(ecify)f(the)g(`HIERAR)m(CH')h
+(part)f(of)g(the)0 2103 y(k)m(eyw)m(ord)g(name)f(when)g(reading)g(or)g
+(writing)h(k)m(eyw)m(ords)f(\(although)h(it)g(ma)m(y)g(b)s(e)f
+(included)f(if)i(desired\).)46 b(When)0 2216 y(writing)35
+b(a)g(k)m(eyw)m(ord,)h(CFITSIO)d(\014rst)h(c)m(hec)m(ks)i(to)f(see)g
+(if)g(the)g(k)m(eyw)m(ord)g(name)f(is)h(legal)h(as)f(a)g(standard)f
+(FITS)0 2328 y(k)m(eyw)m(ord)k(\(no)g(more)f(than)h(8)g(c)m(haracters)h
+(long)f(and)f(con)m(taining)i(only)e(letters,)k(digits,)f(or)e(a)g(min)
+m(us)e(sign)i(or)0 2441 y(underscore\).)68 b(If)39 b(so)h(it)g(writes)g
+(it)g(as)f(a)h(standard)f(FITS)g(k)m(eyw)m(ord,)k(otherwise)d(it)g
+(uses)f(the)h(hierarc)m(h)f(con-)0 2554 y(v)m(en)m(tion)34
+b(to)f(write)g(the)f(k)m(eyw)m(ord.)48 b(The)32 b(maxim)m(um)g(k)m(eyw)
+m(ord)h(name)f(length)h(is)g(67)g(c)m(haracters,)i(whic)m(h)d(lea)m(v)m
+(es)0 2667 y(only)c(1)h(space)g(for)f(the)h(v)-5 b(alue)29
+b(\014eld.)39 b(A)29 b(more)f(practical)i(limit)f(is)g(ab)s(out)f(40)h
+(c)m(haracters,)i(whic)m(h)d(lea)m(v)m(es)i(enough)0
+2780 y(ro)s(om)e(for)h(most)f(k)m(eyw)m(ord)h(v)-5 b(alues.)41
+b(CFITSIO)27 b(returns)g(an)h(error)h(if)f(there)h(is)f(not)h(enough)f
+(ro)s(om)h(for)f(b)s(oth)g(the)0 2893 y(k)m(eyw)m(ord)k(name)f(and)f
+(the)i(k)m(eyw)m(ord)f(v)-5 b(alue)32 b(on)f(the)h(80-c)m(haracter)h
+(card,)f(except)g(for)f(string-v)-5 b(alued)32 b(k)m(eyw)m(ords)0
+3006 y(whic)m(h)h(are)g(simply)f(truncated)h(so)g(that)h(the)f(closing)
+h(quote)g(c)m(haracter)g(falls)f(in)g(column)g(80.)49
+b(In)32 b(the)h(curren)m(t)0 3119 y(implemen)m(tation,)e(CFITSIO)c
+(preserv)m(es)i(the)g(case)h(of)f(the)g(letters)h(when)e(writing)h(the)
+g(k)m(eyw)m(ord)g(name,)g(but)f(it)0 3232 y(is)d(case-insensitiv)m(e)i
+(when)d(reading)h(or)g(searc)m(hing)h(for)f(a)g(k)m(eyw)m(ord.)40
+b(The)24 b(curren)m(t)h(implemen)m(tation)h(allo)m(ws)h(an)m(y)0
+3345 y(ASCI)s(I)i(text)j(c)m(haracter)h(\(ASCI)s(I)c(32)j(to)f(ASCI)s
+(I)f(126\))i(in)f(the)g(k)m(eyw)m(ord)g(name)g(except)h(for)e(the)h
+('=')g(c)m(haracter.)0 3458 y(A)f(space)h(is)g(also)g(required)f(on)g
+(either)h(side)f(of)h(the)f(equal)h(sign.)0 3788 y Fd(4.13)136
+b(Optimizing)45 b(Co)t(de)g(for)h(Maxim)l(um)f(Pro)t(cessing)g(Sp)t
+(eed)0 4039 y Fi(CFITSIO)22 b(has)h(b)s(een)f(carefully)i(designed)f
+(to)h(obtain)g(the)f(highest)h(p)s(ossible)e(sp)s(eed)h(when)f(reading)
+h(and)g(writing)0 4152 y(FITS)33 b(\014les.)51 b(In)33
+b(order)h(to)g(ac)m(hiev)m(e)i(the)e(b)s(est)g(p)s(erformance,)g(ho)m
+(w)m(ev)m(er,)i(application)g(programmers)d(m)m(ust)h(b)s(e)0
+4264 y(careful)24 b(to)h(call)g(the)f(CFITSIO)f(routines)g
+(appropriately)i(and)e(in)h(an)f(e\016cien)m(t)j(sequence;)h
+(inappropriate)c(usage)0 4377 y(of)31 b(CFITSIO)d(routines)j(can)f
+(greatly)i(slo)m(w)f(do)m(wn)f(the)h(execution)g(sp)s(eed)f(of)g(a)h
+(program.)0 4538 y(The)f(maxim)m(um)h(p)s(ossible)f(I/O)h(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 4650 y(that)g(it)f(is)g(running)e(on.)41
+b(As)30 b(a)g(rough)g(guide,)g(the)g(curren)m(t)g(generation)h(of)f(w)m
+(orkstations)h(can)g(ac)m(hiev)m(e)h(sp)s(eeds)0 4763
+y(of)j(2)g({)g(10)g(MB/s)h(when)e(reading)h(or)f(writing)h(FITS)f
+(images)i(and)e(similar,)i(or)f(sligh)m(tly)h(slo)m(w)m(er)g(sp)s(eeds)
+d(with)0 4876 y(FITS)c(binary)h(tables.)41 b(Reading)31
+b(of)f(FITS)g(\014les)g(can)h(o)s(ccur)f(at)h(ev)m(en)f(higher)g(rates)
+h(\(30MB/s)i(or)d(more\))h(if)f(the)0 4989 y(FITS)c(\014le)h(is)f
+(still)i(cac)m(hed)g(in)e(system)h(memory)f(follo)m(wing)j(a)e
+(previous)f(read)g(or)h(write)g(op)s(eration)g(on)g(the)g(same)0
+5102 y(\014le.)44 b(T)-8 b(o)32 b(more)g(accurately)h(predict)e(the)h
+(b)s(est)f(p)s(erformance)g(that)h(is)f(p)s(ossible)g(on)h(an)m(y)g
+(particular)f(system,)i(a)0 5215 y(diagnostic)h(program)f(called)h
+(\\sp)s(eed.c")f(is)g(included)f(with)h(the)g(CFITSIO)e(distribution)h
+(whic)m(h)h(can)g(b)s(e)f(run)0 5328 y(to)f(appro)m(ximately)h(measure)
+e(the)h(maxim)m(um)f(p)s(ossible)g(sp)s(eed)f(of)i(writing)f(and)g
+(reading)h(a)f(test)i(FITS)d(\014le.)0 5488 y(The)k(follo)m(wing)h(2)g
+(sections)g(pro)m(vide)g(some)f(bac)m(kground)g(on)h(ho)m(w)f(CFITSIO)f
+(in)m(ternally)i(manages)g(the)f(data)0 5601 y(I/O)g(and)g(describ)s
+(es)f(some)i(strategies)h(that)f(ma)m(y)g(b)s(e)e(used)h(to)h(optimize)
+g(the)g(pro)s(cessing)f(sp)s(eed)f(of)h(soft)m(w)m(are)0
+5714 y(that)e(uses)f(CFITSIO.)p eop end
+%%Page: 25 31
+TeXDict begin 25 30 bop 0 299 a Fg(4.13.)73 b(OPTIMIZING)29
+b(CODE)h(F)m(OR)h(MAXIMUM)g(PR)m(OCESSING)f(SPEED)971
+b Fi(25)0 555 y Fb(4.13.1)113 b(Bac)m(kground)38 b(Information:)50
+b(Ho)m(w)37 b(CFITSIO)h(Manages)h(Data)f(I/O)0 776 y
+Fi(Man)m(y)22 b(CFITSIO)e(op)s(erations)i(in)m(v)m(olv)m(e)i
+(transferring)d(only)h(a)g(small)g(n)m(um)m(b)s(er)f(of)h(b)m(ytes)g
+(to)g(or)g(from)f(the)h(FITS)f(\014le)0 889 y(\(e.g,)31
+b(reading)e(a)g(k)m(eyw)m(ord,)h(or)f(writing)g(a)g(ro)m(w)g(in)f(a)h
+(table\);)i(it)f(w)m(ould)e(b)s(e)g(v)m(ery)i(ine\016cien)m(t)g(to)f
+(ph)m(ysically)h(read)0 1002 y(or)i(write)h(suc)m(h)f(small)g(blo)s(c)m
+(ks)h(of)f(data)h(directly)g(in)f(the)g(FITS)g(\014le)g(on)g(disk,)h
+(therefore)f(CFITSIO)f(main)m(tains)0 1115 y(a)38 b(set)g(of)g(in)m
+(ternal)h(Input{Output)c(\(IO\))j(bu\013ers)f(in)g(RAM)h(memory)g(that)
+g(eac)m(h)h(con)m(tain)g(one)f(FITS)f(blo)s(c)m(k)0 1228
+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)f(the)g(FITS)f(\014le,)j
+(it)e(\014rst)f(transfers)h(the)0 1341 y(FITS)30 b(blo)s(c)m(k)h(con)m
+(taining)h(those)f(b)m(ytes)g(in)m(to)g(one)g(of)f(the)h(IO)f
+(bu\013ers)f(in)h(memory)-8 b(.)42 b(The)30 b(next)g(time)h(CFITSIO)0
+1454 y(needs)36 b(to)g(access)i(b)m(ytes)e(in)g(the)g(same)h(blo)s(c)m
+(k)f(it)h(can)f(then)g(go)h(to)f(the)h(fast)f(IO)f(bu\013er)g(rather)h
+(than)g(using)g(a)0 1567 y(m)m(uc)m(h)c(slo)m(w)m(er)i(system)e(disk)g
+(access)h(routine.)46 b(The)32 b(n)m(um)m(b)s(er)f(of)h(a)m(v)-5
+b(ailable)35 b(IO)d(bu\013ers)f(is)h(determined)g(b)m(y)g(the)0
+1680 y(NIOBUF)f(parameter)g(\(in)f(\014tsio2.h\))h(and)f(is)h(curren)m
+(tly)f(set)h(to)g(40.)0 1840 y(Whenev)m(er)24 b(CFITSIO)f(reads)g(or)h
+(writes)g(data)g(it)h(\014rst)e(c)m(hec)m(ks)i(to)g(see)f(if)g(that)g
+(blo)s(c)m(k)h(of)f(the)g(FITS)f(\014le)g(is)h(already)0
+1953 y(loaded)33 b(in)m(to)g(one)f(of)g(the)g(IO)g(bu\013ers.)44
+b(If)32 b(not,)h(and)e(if)h(there)g(is)g(an)g(empt)m(y)h(IO)e(bu\013er)
+g(a)m(v)-5 b(ailable,)35 b(then)d(it)h(will)0 2066 y(load)g(that)h(blo)
+s(c)m(k)f(in)m(to)g(the)g(IO)g(bu\013er)e(\(when)h(reading)h(a)g(FITS)f
+(\014le\))h(or)g(will)g(initialize)i(a)e(new)f(blo)s(c)m(k)i(\(when)0
+2179 y(writing)j(to)h(a)g(FITS)f(\014le\).)62 b(If)37
+b(all)h(the)g(IO)e(bu\013ers)h(are)g(already)h(full,)h(it)f(m)m(ust)g
+(decide)f(whic)m(h)g(one)h(to)g(reuse)0 2291 y(\(generally)c(the)f(one)
+g(that)g(has)f(b)s(een)g(accessed)i(least)f(recen)m(tly\),)i(and)d
+(\015ush)f(the)i(con)m(ten)m(ts)h(bac)m(k)g(to)f(disk)f(if)g(it)0
+2404 y(has)e(b)s(een)g(mo)s(di\014ed)f(b)s(efore)h(loading)h(the)g(new)
+f(blo)s(c)m(k.)0 2565 y(The)g(one)g(ma)5 b(jor)30 b(exception)i(to)f
+(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)i(con)m(tiguous)f(set)g(of)f(b)m(ytes)h(are)0
+2677 y(accessed,)37 b(as)d(migh)m(t)i(o)s(ccur)e(when)f(reading)i(or)f
+(writing)g(a)h(FITS)f(image.)54 b(In)34 b(this)g(case)h(CFITSIO)e(b)m
+(ypasses)0 2790 y(the)i(in)m(ternal)h(IO)f(bu\013ers)f(and)g(simply)h
+(reads)g(or)g(writes)h(the)f(desired)g(b)m(ytes)g(directly)h(in)f(the)g
+(disk)g(\014le)g(with)0 2903 y(a)i(single)g(call)g(to)g(a)g(lo)m(w-lev)
+m(el)i(\014le)d(read)g(or)h(write)f(routine.)58 b(The)36
+b(minim)m(um)g(threshold)f(for)h(the)h(n)m(um)m(b)s(er)e(of)0
+3016 y(b)m(ytes)40 b(to)g(read)f(or)g(write)g(this)h(w)m(a)m(y)g(is)f
+(set)h(b)m(y)f(the)g(MINDIRECT)g(parameter)h(and)e(is)i(curren)m(tly)f
+(set)h(to)g(3)0 3129 y(FITS)28 b(blo)s(c)m(ks)g(=)g(8640)i(b)m(ytes.)41
+b(This)28 b(is)g(the)g(most)h(e\016cien)m(t)h(w)m(a)m(y)f(to)g(read)g
+(or)f(write)h(large)g(c)m(h)m(unks)f(of)g(data)i(and)0
+3242 y(can)37 b(ac)m(hiev)m(e)i(IO)d(transfer)g(rates)h(of)g(5)g({)g
+(10MB/s)i(or)d(greater.)61 b(Note)38 b(that)f(this)g(fast)g(direct)g
+(IO)f(pro)s(cess)g(is)0 3355 y(not)29 b(applicable)g(when)e(accessing)j
+(columns)f(of)f(data)h(in)f(a)h(FITS)f(table)h(b)s(ecause)g(the)f(b)m
+(ytes)h(are)g(generally)h(not)0 3468 y(con)m(tiguous)g(since)f(they)g
+(are)h(in)m(terlea)m(v)m(ed)h(b)m(y)e(the)g(other)g(columns)g(of)g
+(data)g(in)g(the)g(table.)41 b(This)28 b(explains)h(wh)m(y)0
+3581 y(the)i(sp)s(eed)e(for)h(accessing)i(FITS)e(tables)h(is)f
+(generally)i(slo)m(w)m(er)f(than)g(accessing)g(FITS)f(images.)0
+3741 y(Giv)m(en)i(this)g(bac)m(kground)f(information,)h(the)g(general)g
+(strategy)h(for)e(e\016cien)m(tly)i(accessing)g(FITS)e(\014les)g
+(should)0 3854 y(no)m(w)36 b(b)s(e)g(apparen)m(t:)52
+b(when)35 b(dealing)i(with)f(FITS)g(images,)j(read)d(or)g(write)g
+(large)i(c)m(h)m(unks)e(of)g(data)h(at)g(a)f(time)0 3967
+y(so)30 b(that)h(the)f(direct)h(IO)e(mec)m(hanism)h(will)h(b)s(e)e(in)m
+(v)m(ok)m(ed;)j(when)d(accessing)j(FITS)d(headers)h(or)g(FITS)f
+(tables,)i(on)0 4080 y(the)k(other)g(hand,)g(once)g(a)g(particular)h
+(FITS)e(blo)s(c)m(k)h(has)f(b)s(een)g(loading)i(in)m(to)g(one)f(of)g
+(the)f(IO)h(bu\013ers,)g(try)f(to)0 4193 y(access)39
+b(all)f(the)f(needed)g(information)h(in)f(that)h(blo)s(c)m(k)g(b)s
+(efore)f(it)h(gets)g(\015ushed)d(out)j(of)g(the)f(IO)g(bu\013er.)60
+b(It)38 b(is)0 4305 y(imp)s(ortan)m(t)31 b(to)h(a)m(v)m(oid)g(the)f
+(situation)h(where)f(the)g(same)g(FITS)f(blo)s(c)m(k)i(is)f(b)s(eing)f
+(read)h(then)g(\015ushed)e(from)h(a)h(IO)0 4418 y(bu\013er)e(m)m
+(ultiple)i(times.)0 4578 y(The)f(follo)m(wing)i(section)f(giv)m(es)h
+(more)e(sp)s(eci\014c)h(suggestions)g(for)f(optimizing)i(the)e(use)g
+(of)h(CFITSIO.)0 4881 y Fb(4.13.2)113 b(Optimization)38
+b(Strategies)0 5102 y Fi(1.)43 b(Because)32 b(the)f(data)g(in)g(FITS)f
+(\014les)h(is)g(alw)m(a)m(ys)h(stored)f(in)g("big-endian")h(b)m(yte)f
+(order,)g(where)f(the)h(\014rst)f(b)m(yte)0 5215 y(of)g(n)m(umeric)h(v)
+-5 b(alues)30 b(con)m(tains)i(the)e(most)h(signi\014can)m(t)g(bits)f
+(and)g(the)g(last)i(b)m(yte)e(con)m(tains)i(the)e(least)i(signi\014can)
+m(t)0 5328 y(bits,)e(CFITSIO)f(m)m(ust)h(sw)m(ap)g(the)g(order)f(of)h
+(the)h(b)m(ytes)f(when)f(reading)h(or)g(writing)g(FITS)g(\014les)g
+(when)f(running)0 5441 y(on)k(little-endian)i(mac)m(hines)f(\(e.g.,)i
+(Lin)m(ux)d(and)g(Microsoft)i(Windo)m(ws)e(op)s(erating)h(systems)g
+(running)d(on)j(PCs)0 5554 y(with)c(x86)h(CPUs\).)0 5714
+y(On)i(fairly)h(new)f(CPUs)g(that)i(supp)s(ort)d("SSSE3")h(mac)m(hine)h
+(instructions)g(\(e.g.,)i(starting)f(with)e(In)m(tel)i(Core)f(2)p
+eop end
+%%Page: 26 32
+TeXDict begin 26 31 bop 0 299 a Fi(26)1277 b Fg(CHAPTER)29
+b(4.)72 b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0
+555 y Fi(CPUs)21 b(in)h(2007,)j(and)d(in)f(AMD)i(CPUs)e(b)s(eginning)g
+(in)h(2011\))i(signi\014can)m(tly)f(faster)f(4-b)m(yte)h(and)e(8-b)m
+(yte)i(sw)m(apping)0 668 y(algorithms)k(are)g(a)m(v)-5
+b(ailable.)42 b(These)26 b(faster)h(b)m(yte)g(sw)m(apping)f(functions)g
+(are)h(not)g(used)e(b)m(y)i(default)f(in)g(CFITSIO)0
+781 y(\(b)s(ecause)c(of)f(the)h(p)s(oten)m(tial)g(co)s(de)g(p)s
+(ortablilit)m(y)g(issues\),)i(but)c(users)h(can)g(enable)h(them)f(on)h
+(supp)s(orted)d(platforms)0 894 y(b)m(y)38 b(adding)f(the)h
+(appropriate)f(compiler)i(\015ags)e(\(-mssse3)i(with)e(gcc)i(or)f(icc)g
+(on)g(lin)m(ux\))g(when)e(compiling)j(the)0 1007 y(sw)m(appro)s(c.c)30
+b(source)g(\014le,)g(whic)m(h)g(will)g(allo)m(w)i(the)e(compiler)g(to)h
+(generate)h(co)s(de)e(using)f(the)h(SSSE3)f(instruction)0
+1120 y(set.)41 b(A)28 b(con)m(v)m(enien)m(t)i(w)m(a)m(y)f(to)g(do)g
+(this)f(is)g(to)h(con\014gure)f(the)g(CFITSIO)f(library)h(with)g(the)g
+(follo)m(wing)i(command:)95 1386 y Fe(>)96 b(./configure)44
+b(--enable-ssse3)0 1652 y Fi(Note,)37 b(ho)m(w)m(ev)m(er,)h(that)d(a)g
+(binary)f(executable)j(\014le)e(that)g(is)g(created)h(using)e(these)h
+(faster)g(functions)g(will)g(only)0 1765 y(run)c(on)h(mac)m(hines)g
+(that)h(supp)s(ort)d(the)i(SSSE3)f(mac)m(hine)i(instructions.)45
+b(It)33 b(will)f(crash)g(on)g(mac)m(hines)g(that)h(do)0
+1878 y(not)e(supp)s(ort)d(them.)0 2038 y(F)-8 b(or)36
+b(faster)f(2-b)m(yte)i(sw)m(aps)e(on)g(virtually)g(all)h(x86-64)h(CPUs)
+e(\(ev)m(en)h(those)g(that)f(do)g(not)h(supp)s(ort)d(SSSE3\),)j(a)0
+2151 y(v)-5 b(arian)m(t)26 b(using)e(only)g(SSE2)g(instructions)h
+(exists.)39 b(SSE2)24 b(is)h(enabled)f(b)m(y)h(default)g(on)f(x86)p
+3066 2151 28 4 v 34 w(64)h(CPUs)f(with)h(64-bit)0 2264
+y(op)s(erating)30 b(systems)f(\(and)g(is)g(also)i(automatically)h
+(enabled)d(b)m(y)g(the)g({enable-ssse3)i(\015ag\).)41
+b(When)30 b(running)d(on)0 2377 y(x86)p 143 2377 V 34
+w(64)k(CPUs)g(with)f(32-bit)i(op)s(erating)g(systems,)f(these)g(faster)
+h(2-b)m(yte)g(sw)m(apping)f(algorithms)g(are)h(not)f(used)0
+2490 y(b)m(y)f(default)h(in)f(CFITSIO,)f(but)h(can)g(b)s(e)g(enabled)g
+(explicitly)i(with:)0 2756 y Fe(./configure)45 b(--enable-sse2)0
+3022 y Fi(Preliminary)f(testing)h(indicates)g(that)g(these)f(SSSE3)f
+(and)g(SSE2)g(based)h(b)m(yte-sw)m(apping)h(algorithms)g(can)0
+3135 y(b)s(o)s(ost)31 b(the)h(CFITSIO)e(p)s(erformance)h(when)f
+(reading)i(or)f(writing)h(FITS)f(images)h(b)m(y)g(20\045)g(-)g(30\045)g
+(or)f(more.)45 b(It)0 3248 y(is)36 b(imp)s(ortan)m(t)g(to)g(note,)i(ho)
+m(w)m(ev)m(er,)h(that)d(compiler)g(optimization)i(m)m(ust)e(b)s(e)f
+(turned)f(on)i(\(e.g.,)j(b)m(y)d(using)f(the)0 3361 y(-O1)f(or)g(-O2)g
+(\015ags)g(in)g(gcc\))h(when)e(building)g(programs)h(that)g(use)g
+(these)g(fast)g(b)m(yte-sw)m(apping)h(algorithms)f(in)0
+3474 y(order)d(to)h(reap)f(the)h(full)f(b)s(ene\014t)g(of)g(the)h
+(SSSE3)e(and)h(SSE2)g(instructions;)h(without)f(optimization,)j(the)e
+(co)s(de)0 3587 y(ma)m(y)f(actually)h(run)d(slo)m(w)m(er)i(than)f(when)
+g(using)g(more)g(traditional)i(b)m(yte-sw)m(apping)f(tec)m(hniques.)0
+3747 y(2.)54 b(When)34 b(dealing)h(with)g(a)g(FITS)e(primary)h(arra)m
+(y)h(or)g(IMA)m(GE)g(extension,)i(it)e(is)f(more)h(e\016cien)m(t)h(to)f
+(read)g(or)0 3860 y(write)c(large)g(c)m(h)m(unks)f(of)g(the)h(image)g
+(at)h(a)e(time)h(\(at)h(least)f(3)g(FITS)f(blo)s(c)m(ks)g(=)g(8640)i(b)
+m(ytes\))f(so)g(that)g(the)f(direct)0 3973 y(IO)j(mec)m(hanism)h(will)f
+(b)s(e)g(used)g(as)g(describ)s(ed)g(in)g(the)g(previous)g(section.)51
+b(Smaller)34 b(c)m(h)m(unks)f(of)g(data)h(are)g(read)0
+4086 y(or)d(written)g(via)h(the)f(IO)f(bu\013ers,)g(whic)m(h)h(is)g
+(somewhat)g(less)g(e\016cien)m(t)i(b)s(ecause)e(of)g(the)g(extra)h(cop)
+m(y)f(op)s(eration)0 4199 y(and)26 b(additional)h(b)s(o)s(okk)m(eeping)
+g(steps)g(that)g(are)g(required.)39 b(In)26 b(principle)g(it)h(is)g
+(more)f(e\016cien)m(t)i(to)g(read)e(or)h(write)0 4312
+y(as)i(big)g(an)g(arra)m(y)h(of)f(image)h(pixels)f(at)h(one)f(time)g
+(as)h(p)s(ossible,)f(ho)m(w)m(ev)m(er,)h(if)f(the)h(arra)m(y)f(b)s
+(ecomes)g(so)g(large)h(that)0 4425 y(the)i(op)s(erating)g(system)f
+(cannot)h(store)g(it)g(all)h(in)e(RAM,)h(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)h
+(sw)m(apping)f(of)g(virtual)h(memory)f(to)h(disk.)0 4698
+y(3.)51 b(When)33 b(dealing)i(with)e(FITS)g(tables,)j(the)e(most)g(imp)
+s(ortan)m(t)g(e\016ciency)g(factor)h(in)e(the)h(soft)m(w)m(are)h
+(design)f(is)0 4811 y(to)j(read)f(or)g(write)g(the)g(data)h(in)f(the)g
+(FITS)g(\014le)g(in)g(a)g(single)h(pass)f(through)f(the)h(\014le.)58
+b(An)36 b(example)h(of)f(p)s(o)s(or)0 4924 y(program)g(design)h(w)m
+(ould)f(b)s(e)g(to)h(read)g(a)f(large,)k(3-column)d(table)g(b)m(y)g
+(sequen)m(tially)h(reading)f(the)f(en)m(tire)i(\014rst)0
+5036 y(column,)25 b(then)f(going)h(bac)m(k)f(to)h(read)e(the)h(2nd)g
+(column,)h(and)e(\014nally)h(the)g(3rd)f(column;)j(this)e(ob)m(viously)
+g(requires)0 5149 y(3)h(passes)f(through)f(the)i(\014le)f(whic)m(h)g
+(could)h(triple)f(the)h(execution)g(time)g(of)g(an)f(I/O)g(limited)h
+(program.)38 b(F)-8 b(or)25 b(small)0 5262 y(tables)31
+b(this)f(is)h(not)f(imp)s(ortan)m(t,)h(but)f(when)f(reading)h(m)m
+(ulti-megab)m(yte)j(sized)e(tables)g(these)g(ine\016ciencies)h(can)0
+5375 y(b)s(ecome)d(signi\014can)m(t.)41 b(The)28 b(more)h(e\016cien)m
+(t)h(pro)s(cedure)d(in)i(this)f(case)i(is)e(to)i(read)e(or)h(write)g
+(only)f(as)h(man)m(y)g(ro)m(ws)0 5488 y(of)g(the)g(table)h(as)f(will)h
+(\014t)e(in)m(to)i(the)g(a)m(v)-5 b(ailable)31 b(in)m(ternal)f(I/O)f
+(bu\013ers,)f(then)h(access)h(all)g(the)f(necessary)g(columns)0
+5601 y(of)i(data)h(within)e(that)i(range)f(of)g(ro)m(ws.)43
+b(Then)29 b(after)j(the)f(program)g(is)g(completely)h(\014nished)e
+(with)g(the)i(data)f(in)0 5714 y(those)i(ro)m(ws)e(it)i(can)f(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)f(\014t)
+g(in)g(the)g(bu\013ers,)f(con)m(tin)m(uing)i(in)f(this)p
+eop end
+%%Page: 27 33
+TeXDict begin 27 32 bop 0 299 a Fg(4.13.)73 b(OPTIMIZING)29
+b(CODE)h(F)m(OR)h(MAXIMUM)g(PR)m(OCESSING)f(SPEED)971
+b Fi(27)0 555 y(w)m(a)m(y)28 b(un)m(til)f(the)f(en)m(tire)i(\014le)f
+(has)f(b)s(een)g(pro)s(cessed.)39 b(By)27 b(using)f(this)h(pro)s
+(cedure)e(of)i(accessing)h(all)g(the)e(columns)h(of)0
+668 y(a)j(table)g(in)f(parallel)h(rather)f(than)g(sequen)m(tially)-8
+b(,)32 b(eac)m(h)e(blo)s(c)m(k)g(of)g(the)f(FITS)g(\014le)g(will)g
+(only)h(b)s(e)e(read)i(or)f(written)0 781 y(once.)0 941
+y(The)g(optimal)h(n)m(um)m(b)s(er)e(of)i(ro)m(ws)f(to)i(read)e(or)g
+(write)h(at)g(one)g(time)g(in)f(a)h(giv)m(en)g(table)h(dep)s(ends)c(on)
+j(the)f(width)g(of)0 1054 y(the)j(table)h(ro)m(w,)g(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)j(in)e(FITSIO,)f(and)h(also)h(on)f(the)0 1167
+y(n)m(um)m(b)s(er)27 b(of)i(other)f(FITS)g(\014les)g(that)h(are)g(op)s
+(en)f(at)h(the)g(same)g(time)g(\(since)g(one)g(I/O)f(bu\013er)f(is)i
+(alw)m(a)m(ys)h(reserv)m(ed)0 1280 y(for)k(eac)m(h)h(op)s(en)f(FITS)f
+(\014le\).)53 b(F)-8 b(ortunately)g(,)37 b(a)e(FITSIO)e(routine)h(is)h
+(a)m(v)-5 b(ailable)36 b(that)f(will)f(return)g(the)g(optimal)0
+1393 y(n)m(um)m(b)s(er)e(of)i(ro)m(ws)g(for)g(a)g(giv)m(en)g(table:)49
+b(call)35 b(ftgrsz\(unit,)g(nro)m(ws,)f(status\).)52
+b(It)34 b(is)g(not)g(critical)h(to)g(use)e(exactly)0
+1506 y(the)f(v)-5 b(alue)32 b(of)f(nro)m(ws)g(returned)g(b)m(y)g(this)g
+(routine,)h(as)g(long)g(as)g(one)g(do)s(es)f(not)h(exceed)g(it.)45
+b(Using)32 b(a)g(v)m(ery)f(small)0 1619 y(v)-5 b(alue)32
+b(ho)m(w)m(ev)m(er)i(can)e(also)h(lead)f(to)h(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)g(n)m(um)m(b)s(er)0 1732 y(of)f(subroutine)e(calls.)0
+1892 y(The)36 b(optimal)h(n)m(um)m(b)s(er)f(of)g(ro)m(ws)h(returned)e
+(b)m(y)h(ftgrsz)h(is)g(v)-5 b(alid)37 b(only)f(as)h(long)g(as)g(the)f
+(application)i(program)0 2005 y(is)c(only)h(reading)g(or)f(writing)g
+(data)h(in)g(the)f(sp)s(eci\014ed)g(table.)54 b(An)m(y)34
+b(other)h(calls)g(to)g(access)h(data)f(in)f(the)h(table)0
+2118 y(header)26 b(w)m(ould)f(cause)i(additional)f(blo)s(c)m(ks)h(of)f
+(data)g(to)h(b)s(e)e(loaded)h(in)m(to)h(the)f(I/O)g(bu\013ers)f
+(displacing)h(data)g(from)0 2230 y(the)j(original)h(table,)g(and)e
+(should)f(b)s(e)h(a)m(v)m(oided)i(during)e(the)h(critical)h(p)s(erio)s
+(d)e(while)g(the)h(table)h(is)e(b)s(eing)g(read)h(or)0
+2343 y(written.)0 2503 y(4.)39 b(Use)24 b(binary)f(table)h(extensions)g
+(rather)f(than)h(ASCI)s(I)e(table)i(extensions)g(for)f(b)s(etter)h
+(e\016ciency)h(when)d(dealing)0 2616 y(with)37 b(tabular)h(data.)62
+b(The)37 b(I/O)g(to)h(ASCI)s(I)e(tables)i(is)g(slo)m(w)m(er)g(b)s
+(ecause)g(of)f(the)h(o)m(v)m(erhead)h(in)e(formatting)h(or)0
+2729 y(parsing)30 b(the)h(ASCI)s(I)f(data)h(\014elds,)g(and)f(b)s
+(ecause)h(ASCI)s(I)e(tables)i(are)g(ab)s(out)g(t)m(wice)h(as)f(large)h
+(as)f(binary)f(tables)0 2842 y(with)g(the)h(same)f(information)h(con)m
+(ten)m(t.)0 3002 y(5.)64 b(Design)39 b(soft)m(w)m(are)g(so)g(that)f(it)
+h(reads)f(the)g(FITS)f(header)h(k)m(eyw)m(ords)g(in)g(the)g(same)h
+(order)e(in)h(whic)m(h)g(they)0 3115 y(o)s(ccur)33 b(in)g(the)g
+(\014le.)49 b(When)32 b(reading)i(k)m(eyw)m(ords,)g(FITSIO)e(searc)m
+(hes)i(forw)m(ard)e(starting)i(from)e(the)i(p)s(osition)f(of)0
+3228 y(the)c(last)i(k)m(eyw)m(ord)e(that)h(w)m(as)g(read.)40
+b(If)29 b(it)g(reac)m(hes)i(the)e(end)g(of)g(the)h(header)f(without)g
+(\014nding)f(the)h(k)m(eyw)m(ord,)h(it)0 3341 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)h
+(the)g(searc)m(h)g(do)m(wn)f(to)h(the)g(p)s(osition)f(where)g(it)0
+3454 y(started.)41 b(In)30 b(practice,)i(as)e(long)h(as)g(the)f(en)m
+(tire)i(FITS)d(header)h(can)h(\014t)f(at)h(one)g(time)g(in)f(the)g(a)m
+(v)-5 b(ailable)33 b(in)m(ternal)0 3567 y(I/O)g(bu\013ers,)h(then)f
+(the)h(header)f(k)m(eyw)m(ord)h(access)h(will)e(b)s(e)g(v)m(ery)h(fast)
+g(and)f(it)h(mak)m(es)g(little)h(di\013erence)f(whic)m(h)0
+3680 y(order)c(they)g(are)h(accessed.)0 3840 y(6.)40
+b(Av)m(oid)29 b(the)e(use)h(of)f(scaling)i(\(b)m(y)f(using)f(the)h
+(BSCALE)e(and)h(BZER)m(O)h(or)f(TSCAL)g(and)g(TZER)m(O)f(k)m(eyw)m
+(ords\))0 3953 y(in)35 b(FITS)f(\014les)g(since)i(the)f(scaling)h(op)s
+(erations)f(add)f(to)i(the)f(pro)s(cessing)f(time)i(needed)e(to)i(read)
+f(or)g(write)g(the)0 4066 y(data.)60 b(In)36 b(some)i(cases)f(it)g(ma)m
+(y)h(b)s(e)e(more)h(e\016cien)m(t)h(to)f(temp)s(orarily)g(turn)f(o\013)
+h(the)g(scaling)h(\(using)e(ftpscl)h(or)0 4179 y(fttscl\))32
+b(and)d(then)h(read)h(or)f(write)h(the)f(ra)m(w)h(unscaled)f(v)-5
+b(alues)31 b(in)f(the)g(FITS)g(\014le.)0 4339 y(7.)40
+b(Av)m(oid)27 b(using)g(the)g('implicit)h(datat)m(yp)s(e)f(con)m(v)m
+(ersion')h(capabilit)m(y)h(in)d(FITSIO.)g(F)-8 b(or)28
+b(instance,)g(when)e(reading)0 4452 y(a)f(FITS)e(image)j(with)e(BITPIX)
+g(=)g(-32)i(\(32-bit)g(\015oating)f(p)s(oin)m(t)f(pixels\),)j(read)d
+(the)h(data)g(in)m(to)g(a)g(single)g(precision)0 4565
+y(\015oating)e(p)s(oin)m(t)e(data)i(arra)m(y)f(in)g(the)g(program.)37
+b(F)-8 b(orcing)23 b(FITSIO)e(to)h(con)m(v)m(ert)i(the)e(data)g(to)h(a)
+f(di\013eren)m(t)g(datat)m(yp)s(e)0 4678 y(can)31 b(signi\014can)m(tly)
+g(slo)m(w)g(the)g(program.)0 4838 y(8.)57 b(Where)36
+b(feasible,)i(design)e(FITS)f(binary)g(tables)h(using)f(v)m(ector)j
+(column)d(elemen)m(ts)i(so)f(that)g(the)g(data)h(are)0
+4951 y(written)30 b(as)g(a)g(con)m(tiguous)h(set)f(of)g(b)m(ytes,)g
+(rather)g(than)f(as)h(single)g(elemen)m(ts)h(in)f(m)m(ultiple)g(ro)m
+(ws.)41 b(F)-8 b(or)30 b(example,)0 5064 y(it)36 b(is)g(faster)g(to)g
+(access)h(the)f(data)h(in)e(a)h(table)h(that)f(con)m(tains)h(a)f
+(single)g(ro)m(w)g(and)f(2)h(columns)f(with)h(TF)m(ORM)0
+5176 y(k)m(eyw)m(ords)d(equal)h(to)g('10000E')h(and)e('10000J',)j(than)
+d(it)g(is)g(to)h(access)g(the)g(same)f(amoun)m(t)h(of)f(data)h(in)f(a)g
+(table)0 5289 y(with)40 b(10000)j(ro)m(ws)d(whic)m(h)h(has)f(columns)g
+(with)g(the)h(TF)m(ORM)g(k)m(eyw)m(ords)g(equal)g(to)g('1E')h(and)e
+('1J'.)h(In)f(the)0 5402 y(former)27 b(case)i(the)f(10000)i(\015oating)
+f(p)s(oin)m(t)f(v)-5 b(alues)28 b(in)g(the)g(\014rst)f(column)h(are)g
+(all)h(written)f(in)f(a)h(con)m(tiguous)h(blo)s(c)m(k)0
+5515 y(of)d(the)f(\014le)h(whic)m(h)f(can)h(b)s(e)f(read)g(or)g
+(written)h(quic)m(kly)-8 b(,)28 b(whereas)d(in)g(the)h(second)f(case)i
+(eac)m(h)g(\015oating)f(p)s(oin)m(t)f(v)-5 b(alue)0 5628
+y(in)34 b(the)g(\014rst)f(column)g(is)h(in)m(terlea)m(v)m(ed)j(with)c
+(the)h(in)m(teger)i(v)-5 b(alue)34 b(in)g(the)g(second)g(column)f(of)h
+(the)g(same)h(ro)m(w)f(so)p eop end
+%%Page: 28 34
+TeXDict begin 28 33 bop 0 299 a Fi(28)1277 b Fg(CHAPTER)29
+b(4.)72 b(FITSIO)29 b(CONVENTIONS)g(AND)i(GUIDELINES)0
+555 y Fi(CFITSIO)e(has)h(to)h(explicitly)h(mo)m(v)m(e)g(to)f(the)g(p)s
+(osition)f(of)h(eac)m(h)g(elemen)m(t)h(to)f(b)s(e)f(read)g(or)g
+(written.)0 715 y(9.)52 b(Av)m(oid)35 b(the)g(use)e(of)i(v)-5
+b(ariable)34 b(length)h(v)m(ector)h(columns)d(in)h(binary)g(tables,)i
+(since)e(an)m(y)h(reading)f(or)g(writing)0 828 y(of)f(these)g(data)g
+(requires)f(that)h(CFITSIO)f(\014rst)f(lo)s(ok)j(up)d(or)i(compute)g
+(the)f(starting)i(address)e(of)g(eac)m(h)i(ro)m(w)f(of)0
+941 y(data)e(in)f(the)h(heap.)40 b(In)30 b(practice,)i(this)e(is)g
+(probably)g(not)h(a)f(signi\014can)m(t)i(e\016ciency)f(issue.)0
+1101 y(10.)39 b(When)24 b(cop)m(ying)h(data)f(from)f(one)i(FITS)e
+(table)h(to)h(another,)g(it)g(is)f(faster)g(to)g(transfer)f(the)h(ra)m
+(w)g(b)m(ytes)h(instead)0 1214 y(of)h(reading)g(then)g(writing)g(eac)m
+(h)h(column)e(of)i(the)f(table.)40 b(The)25 b(FITSIO)g(subroutines)g
+(FTGTBS)g(and)h(FTPTBS)0 1327 y(\(for)i(ASCI)s(I)f(tables\),)j(and)d
+(FTGTBB)i(and)e(FTPTBB)i(\(for)f(binary)f(tables\))i(will)g(p)s(erform)
+d(lo)m(w-lev)m(el)31 b(reads)d(or)0 1440 y(writes)34
+b(of)h(an)m(y)f(con)m(tiguous)i(range)f(of)f(b)m(ytes)h(in)f(a)h(table)
+g(extension.)53 b(These)34 b(routines)g(can)h(b)s(e)e(used)h(to)h(read)
+0 1553 y(or)29 b(write)g(a)g(whole)g(ro)m(w)f(\(or)i(m)m(ultiple)f(ro)m
+(ws\))g(of)g(a)g(table)h(with)e(a)h(single)g(subroutine)f(call.)41
+b(These)29 b(routines)g(are)0 1666 y(fast)38 b(b)s(ecause)f(they)h(b)m
+(ypass)f(all)h(the)g(usual)f(data)h(scaling,)j(error)c(c)m(hec)m(king)i
+(and)e(mac)m(hine)h(dep)s(enden)m(t)e(data)0 1779 y(con)m(v)m(ersion)41
+b(that)g(is)e(normally)i(done)e(b)m(y)h(FITSIO,)f(and)g(they)h(allo)m
+(w)h(the)f(program)g(to)h(write)f(the)g(data)g(to)0 1892
+y(the)34 b(output)g(\014le)g(in)g(exactly)i(the)e(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)f(can)0 2005 y(b)s(e)f(somewhat)h(risky)f(b)s(ecause)g(no)g
+(v)-5 b(alidation)35 b(or)f(mac)m(hine)g(dep)s(enden)m(t)e(con)m(v)m
+(ersion)j(is)e(p)s(erformed)f(b)m(y)h(these)0 2118 y(routines.)40
+b(In)27 b(general)h(these)h(routines)e(are)h(only)g(recommended)f(for)h
+(optimizing)h(critical)g(pieces)g(of)f(co)s(de)g(and)0
+2230 y(should)e(only)i(b)s(e)f(used)f(b)m(y)i(programmers)e(who)h
+(thoroughly)h(understand)d(the)j(in)m(ternal)g(b)m(yte)g(structure)f
+(of)h(the)0 2343 y(FITS)i(tables)h(they)f(are)h(reading)g(or)f
+(writing.)0 2503 y(11.)41 b(Another)30 b(strategy)g(for)g(impro)m(ving)
+f(the)h(sp)s(eed)e(of)i(writing)g(a)f(FITS)g(table,)i(similar)f(to)g
+(the)f(previous)g(one,)0 2616 y(is)j(to)g(directly)h(construct)f(the)f
+(en)m(tire)i(b)m(yte)f(stream)g(for)g(a)g(whole)g(table)g(ro)m(w)g
+(\(or)g(m)m(ultiple)h(ro)m(ws\))f(within)f(the)0 2729
+y(application)k(program)f(and)g(then)f(write)i(it)f(to)h(the)f(FITS)f
+(\014le)i(with)e(ftptbb.)51 b(This)33 b(a)m(v)m(oids)j(all)f(the)f(o)m
+(v)m(erhead)0 2842 y(normally)g(presen)m(t)g(in)f(the)h(column-orien)m
+(ted)h(CFITSIO)d(write)i(routines.)51 b(This)33 b(tec)m(hnique)h
+(should)f(only)h(b)s(e)0 2955 y(used)26 b(for)h(critical)i
+(applications,)g(b)s(ecause)d(it)i(mak)m(es)g(the)f(co)s(de)g(more)g
+(di\016cult)g(to)g(understand)e(and)i(main)m(tain,)0
+3068 y(and)d(it)h(mak)m(es)h(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 3181 y(to)31 b(the)g(FITS)e
+(\014le?\).)0 3341 y(12.)53 b(Finally)-8 b(,)37 b(external)e(factors)h
+(suc)m(h)e(as)g(the)h(t)m(yp)s(e)f(of)h(magnetic)g(disk)f(con)m
+(troller)i(\(SCSI)d(or)i(IDE\),)g(the)f(size)0 3454 y(of)h(the)g(disk)g
+(cac)m(he,)j(the)d(a)m(v)m(erage)i(seek)f(sp)s(eed)e(of)h(the)g(disk,)h
+(the)f(amoun)m(t)h(of)f(disk)f(fragmen)m(tation,)k(and)d(the)0
+3567 y(amoun)m(t)29 b(of)g(RAM)f(a)m(v)-5 b(ailable)31
+b(on)e(the)f(system)h(can)g(all)g(ha)m(v)m(e)h(a)f(signi\014can)m(t)g
+(impact)h(on)e(o)m(v)m(erall)j(I/O)d(e\016ciency)-8 b(.)0
+3680 y(F)g(or)36 b(critical)h(applications,)g(a)f(system)f
+(administrator)g(should)f(review)h(the)h(prop)s(osed)d(system)j(hardw)m
+(are)e(to)0 3793 y(iden)m(tify)d(an)m(y)g(p)s(oten)m(tial)g(I/O)g(b)s
+(ottlenec)m(ks.)p eop end
+%%Page: 29 35
+TeXDict begin 29 34 bop 0 1225 a Ff(Chapter)65 b(5)0
+1687 y Fl(Basic)77 b(In)-6 b(terface)77 b(Routines)0
+2180 y Fi(This)27 b(section)h(de\014nes)f(a)h(basic)g(set)g(of)g
+(subroutines)e(that)i(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)h(op)s
+(erations)g(on)g(FITS)f(\014les.)39 b(New)25 b(users)f(should)g(start)h
+(with)g(these)g(subroutines)f(and)g(then,)0 2406 y(as)33
+b(needed,)h(explore)f(the)h(more)f(adv)-5 b(ance)33 b(routines)g
+(describ)s(ed)f(in)h(the)g(follo)m(wing)i(c)m(hapter)e(to)h(p)s(erform)
+e(more)0 2518 y(complex)f(or)f(sp)s(ecialized)i(op)s(erations.)0
+2679 y(A)e(righ)m(t)g(arro)m(w)g(sym)m(b)s(ol)f(\()p
+Fa(>)p Fi(\))h(is)g(used)f(to)h(separate)h(the)e(input)g(parameters)h
+(from)f(the)h(output)f(parameters)h(in)0 2791 y(the)i(de\014nition)f
+(of)g(eac)m(h)i(routine.)44 b(This)30 b(sym)m(b)s(ol)i(is)f(not)h
+(actually)h(part)e(of)h(the)f(calling)i(sequence.)45
+b(Note)32 b(that)0 2904 y(the)f(status)h(parameter)g(is)f(b)s(oth)g(an)
+g(input)f(and)h(an)g(output)g(parameter)h(and)e(m)m(ust)h(b)s(e)g
+(initialized)i(=)e(0)h(prior)0 3017 y(to)f(calling)h(the)f(FITSIO)e
+(subroutines.)0 3177 y(Refer)h(to)i(Chapter)d(9)i(for)f(the)h
+(de\014nition)f(of)g(all)i(the)e(parameters)h(used)e(b)m(y)i(these)g
+(in)m(terface)g(routines.)0 3525 y Fd(5.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)h(n)m(um)m(b)s(er)e(of)i(the)f
+(\014tsio)h(library)-8 b(.)39 b(The)25 b(v)m(ersion)h(n)m(um)m(b)s(er)e
+(will)i(b)s(e)e(incremen)m(ted)227 3886 y(with)30 b(eac)m(h)i(new)e
+(release)h(of)g(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)g(text)g(string)g
+(corresp)s(onding)e(to)i(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)f(string)f(con)m
+(tains)i(a)f(brief)f(description)g(of)g(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\))h(80-c)m
+(haracter)i(error)c(message)i(from)f(the)g(in)m(ternal)g(FITSIO)f(stac)
+m(k)i(of)f(error)227 5197 y(messages)29 b(and)f(shift)g(an)m(y)g
+(remaining)g(messages)h(on)f(the)g(stac)m(k)i(up)d(one)h(lev)m(el.)42
+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)28
+b(this)f(routine)g(rep)s(eatedly)g(to)h(get)h(eac)m(h)f(message)227
+5422 y(in)i(sequence.)41 b(The)30 b(error)g(stac)m(k)i(is)f(empt)m(y)f
+(when)g(a)g(blank)g(string)h(is)f(returned.)382 5694
+y Fe(FTGMSG\()46 b(>)h(errmsg\))1905 5942 y Fi(29)p eop
+end
+%%Page: 30 36
+TeXDict begin 30 35 bop 0 299 a Fi(30)1747 b Fg(CHAPTER)30
+b(5.)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)g(puts)g(an)g(in)m
+(visible)h(mark)m(er)f(on)g(the)h(CFITSIO)d(error)i(stac)m(k.)54
+b(The)33 b(FTCMRK)227 668 y(routine)41 b(can)g(then)g(b)s(e)f(used)g
+(to)h(delete)h(an)m(y)f(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)f(of)g(the)g
+(mark)m(er.)43 b(This)31 b(preserv)m(es)g(an)m(y)g(older)h(error)e
+(messages)i(on)f(the)h(stac)m(k.)44 b(FTCMSG)227 894
+y(simply)23 b(clears)g(the)g(en)m(tire)h(error)e(message)i(stac)m(k.)40
+b(These)23 b(routines)f(are)h(called)h(without)f(an)m(y)g(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)30 b(out)h(the)g(error)f
+(message)i(corresp)s(onding)e(to)h(the)g(input)f(status)h(v)-5
+b(alue)31 b(and)f(all)i(the)f(error)f(messages)227 1750
+y(on)g(the)h(FITSIO)e(stac)m(k)i(to)g(the)g(sp)s(eci\014ed)e(\014le)i
+(stream)f(\(stream)h(can)g(b)s(e)e(either)i(the)f(string)g('STDOUT')227
+1863 y(or)h('STDERR'\).)f(If)g(the)h(input)e(status)i(v)-5
+b(alue)31 b(=)f(0)h(then)f(this)g(routine)g(do)s(es)g(nothing.)334
+2121 y Fe(FTRPRT)46 b(\(stream,)g(>)h(status\))0 2380
+y Fh(6)81 b Fi(W)-8 b(rite)39 b(an)f(80-c)m(haracter)j(message)e(to)g
+(the)f(FITSIO)f(error)h(stac)m(k.)65 b(Application)39
+b(programs)f(should)f(not)227 2493 y(normally)31 b(write)f(to)i(the)e
+(stac)m(k,)i(but)e(there)g(ma)m(y)h(b)s(e)f(some)h(situations)g(where)f
+(this)g(is)h(desirable.)382 2751 y Fe(FTPMSG\(errmsg\))0
+3085 y Fd(5.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)i(FITS)d(\014le)i(with)f
+(readonly)h(or)f(readwrite)h(access.)58 b(This)34 b(routine)i(alw)m(a)m
+(ys)h(op)s(ens)e(the)227 3438 y(primary)30 b(arra)m(y)i(\(the)f
+(\014rst)f(HDU\))i(of)f(the)h(\014le,)f(and)f(do)s(es)h(not)g(mo)m(v)m
+(e)h(to)g(a)f(follo)m(wing)i(extension,)f(if)f(one)227
+3551 y(w)m(as)c(sp)s(eci\014ed)f(as)g(part)h(of)f(the)h(\014lename.)39
+b(Use)27 b(the)g(FTNOPN)f(routine)g(to)h(automatically)j(mo)m(v)m(e)e
+(to)f(the)227 3664 y(extension.)44 b(This)31 b(routine)g(will)h(also)g
+(op)s(en)f(IRAF)g(images)i(\(.imh)e(format)h(\014les\))g(and)e(ra)m(w)i
+(binary)e(data)227 3776 y(arra)m(ys)e(with)f(READONL)-8
+b(Y)28 b(access)h(b)m(y)e(\014rst)g(con)m(v)m(erting)i(them)e(on)g(the)
+h(\015y)f(in)m(to)h(virtual)g(FITS)f(images.)227 3889
+y(See)39 b(the)f(`Extended)g(File)h(Name)g(Syn)m(tax')f(c)m(hapter)h
+(for)f(more)g(details.)65 b(The)38 b(FTDK)m(OPEN)g(routine)227
+4002 y(simply)f(op)s(ens)g(the)h(sp)s(eci\014ed)f(\014le)h(without)f
+(trying)h(to)g(in)m(terpret)g(the)g(\014lename)g(using)f(the)h
+(extended)227 4115 y(\014lename)31 b(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)h(FITS)e(\014le)h(with)f(readonly)h(or)g(readwrite)g
+(access)h(and)f(mo)m(v)m(e)h(to)f(a)h(follo)m(wing)g(extension,)227
+4858 y(if)38 b(one)g(w)m(as)g(sp)s(eci\014ed)g(as)g(part)f(of)h(the)h
+(\014lename.)63 b(\(e.g.,)42 b('\014lename.\014ts+2')c(or)g
+('\014lename.\014ts[2]')i(will)227 4971 y(mo)m(v)m(e)e(to)g(the)e(3rd)g
+(HDU)i(in)e(the)h(\014le\).)60 b(Note)37 b(that)h(this)e(routine)h
+(di\013ers)f(from)g(FTOPEN)g(in)g(that)h(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)
+j(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)h
+(FITS)f(\014le)g(with)g(readonly)h(or)f(readwrite)h(access)g(and)f
+(then)g(mo)m(v)m(e)i(to)f(the)g(\014rst)e(HDU)227 5714
+y(con)m(taining)c(signi\014can)m(t)g(data,)g(if)e(a\))i(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)h(sp)s(eci\014ed)p eop end
+%%Page: 31 37
+TeXDict begin 31 36 bop 0 299 a Fg(5.2.)72 b(FILE)30
+b(I/O)h(R)m(OUTINES)2693 b Fi(31)227 555 y(as)31 b(part)g(of)g(the)g
+(\014lename,)h(and)e(b\))h(if)g(the)g(FITS)f(\014le)h(con)m(tains)h(a)g
+(n)m(ull)e(primary)g(arra)m(y)i(\(i.e.,)h(NAXIS)d(=)227
+668 y(0\).)41 b(In)26 b(this)i(case,)h(it)f(will)g(lo)s(ok)g(for)f(the)
+h(\014rst)e(IMA)m(GE)j(HDU)f(with)f(NAXIS)g(>)h(0,)g(or)g(the)f
+(\014rst)g(table)h(that)227 781 y(do)s(es)g(not)g(con)m(tain)g(the)g
+(strings)g(`GTI')g(\(Go)s(o)s(d)f(Time)h(In)m(terv)-5
+b(al\))29 b(or)f(`OBST)-8 b(ABLE')28 b(in)f(the)h(EXTNAME)227
+894 y(k)m(eyw)m(ord)37 b(v)-5 b(alue.)61 b(FTTOPN)36
+b(is)g(similar,)j(except)f(it)f(will)g(mo)m(v)m(e)i(to)e(the)g(\014rst)
+f(signi\014can)m(t)i(table)f(HDU)227 1007 y(\(skipping)26
+b(o)m(v)m(er)g(an)m(y)g(image)h(HDUs\))g(in)e(the)h(\014le)g(if)f(a)h
+(sp)s(eci\014c)g(HDU)g(name)g(or)g(n)m(um)m(b)s(er)e(is)i(not)f(sp)s
+(eci\014ed.)227 1120 y(FTIOPN)30 b(will)h(mo)m(v)m(e)h(to)f(the)f
+(\014rst)g(non-n)m(ull)g(image)i(HDU,)f(skipping)f(o)m(v)m(er)h(an)m(y)
+g(tables.)382 1376 y Fe(FTDOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))382 1489 y(FTTOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))382 1602 y(FTIOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))0 1858 y Fh(4)81 b Fi(Op)s(en)38 b(and)i(initialize)j
+(a)e(new)e(empt)m(y)i(FITS)f(\014le.)70 b(A)41 b(template)h(\014le)e
+(ma)m(y)h(also)g(b)s(e)f(sp)s(eci\014ed)g(to)h(de\014ne)227
+1971 y(the)34 b(structure)e(of)h(the)h(new)e(\014le)h(\(see)h(section)g
+(4.2.4\).)51 b(The)33 b(FTDKINIT)g(routine)g(simply)f(creates)j(the)227
+2084 y(sp)s(eci\014ed)30 b(\014le)g(without)h(trying)f(to)h(in)m
+(terpret)g(the)g(\014lename)f(using)g(the)h(extended)f(\014lename)h
+(syn)m(tax.)382 2340 y Fe(FTINIT\(unit,filename,blo)o(cks)o(ize,)41
+b(>)48 b(status\))382 2453 y(FTDKINIT\(unit,filename,b)o(loc)o(ksiz)o
+(e,)42 b(>)47 b(status\))0 2709 y Fh(5)81 b Fi(Close)31
+b(a)f(FITS)g(\014le)g(previously)g(op)s(ened)g(with)g(ftop)s(en)g(or)g
+(ftinit)382 2965 y Fe(FTCLOS\(unit,)44 b(>)k(status\))0
+3221 y Fh(6)81 b Fi(Mo)m(v)m(e)32 b(to)f(a)g(sp)s(eci\014ed)f
+(\(absolute\))h(HDU)g(in)g(the)f(FITS)g(\014le)g(\(nhdu)f(=)h(1)h(for)f
+(the)g(FITS)g(primary)f(arra)m(y\))382 3478 y Fe(FTMAHD\(unit,nhdu,)43
+b(>)k(hdutype,status\))0 3734 y Fh(7)81 b Fi(Create)30
+b(a)f(primary)f(arra)m(y)i(\(if)g(none)f(already)g(exists\),)i(or)e
+(insert)g(a)h(new)f(IMA)m(GE)h(extension)g(immediately)227
+3847 y(follo)m(wing)25 b(the)e(CHDU,)g(or)g(insert)g(a)g(new)g(Primary)
+f(Arra)m(y)h(at)h(the)f(b)s(eginning)f(of)h(the)g(\014le.)38
+b(An)m(y)23 b(follo)m(wing)227 3960 y(extensions)29 b(in)g(the)g
+(\014le)f(will)h(b)s(e)f(shifted)h(do)m(wn)f(to)h(mak)m(e)h(ro)s(om)e
+(for)h(the)g(new)f(extension.)40 b(If)29 b(the)g(CHDU)227
+4072 y(is)h(the)g(last)g(HDU)g(in)g(the)f(\014le)h(then)f(the)h(new)f
+(image)i(extension)f(will)g(simply)f(b)s(e)g(app)s(ended)f(to)i(the)g
+(end)227 4185 y(of)k(the)h(\014le.)52 b(One)33 b(can)h(force)h(a)g(new)
+e(primary)g(arra)m(y)i(to)g(b)s(e)e(inserted)h(at)h(the)f(b)s(eginning)
+f(of)h(the)h(FITS)227 4298 y(\014le)29 b(b)m(y)f(setting)i(status)e(=)h
+(-9)g(prior)e(to)j(calling)g(the)e(routine.)40 b(In)28
+b(this)g(case)i(the)e(existing)i(primary)d(arra)m(y)227
+4411 y(will)f(b)s(e)f(con)m(v)m(erted)i(to)g(an)e(IMA)m(GE)h
+(extension.)40 b(The)25 b(new)g(extension)i(\(or)f(primary)e(arra)m
+(y\))j(will)f(b)s(ecome)227 4524 y(the)32 b(CHDU.)f(The)g(FTI)s(IMGLL)f
+(routine)i(is)f(iden)m(tical)i(to)e(the)h(FTI)s(IMG)f(routine)g(except)
+h(that)f(the)h(4th)227 4637 y(parameter)25 b(\(the)g(length)g(of)f(eac)
+m(h)h(axis\))g(is)g(an)f(arra)m(y)h(of)f(64-bit)i(in)m(tegers)f(rather)
+f(than)g(an)g(arra)m(y)h(of)g(32-bit)227 4750 y(in)m(tegers.)382
+5006 y Fe(FTIIMG\(unit,bitpix,naxis)o(,na)o(xes,)41 b(>)48
+b(status\))382 5119 y(FTIIMGLL\(unit,bitpix,nax)o(is,)o(naxe)o(sll,)41
+b(>)47 b(status\))0 5375 y Fh(8)81 b Fi(Insert)30 b(a)i(new)f(ASCI)s(I)
+f(T)-8 b(ABLE)31 b(extension)h(immediately)h(follo)m(wing)f(the)g
+(CHDU.)g(An)m(y)f(follo)m(wing)i(exten-)227 5488 y(sions)26
+b(will)g(b)s(e)f(shifted)g(do)m(wn)g(to)h(mak)m(e)h(ro)s(om)e(for)h
+(the)f(new)g(extension.)40 b(If)25 b(there)h(are)g(no)g(other)f(follo)m
+(wing)227 5601 y(extensions)32 b(then)f(the)h(new)f(table)h(extension)g
+(will)g(simply)f(b)s(e)g(app)s(ended)f(to)i(the)f(end)g(of)h(the)f
+(\014le.)44 b(The)227 5714 y(new)33 b(extension)h(will)f(b)s(ecome)h
+(the)f(CHDU.)h(The)f(FTIT)-8 b(ABLL)33 b(routine)g(is)g(iden)m(tical)i
+(to)f(the)g(FTIT)-8 b(AB)p eop end
+%%Page: 32 38
+TeXDict begin 32 37 bop 0 299 a Fi(32)1747 b Fg(CHAPTER)30
+b(5.)111 b(BASIC)30 b(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)227
+555 y Fi(routine)36 b(except)g(that)g(the)f(2nd)g(and)g(3rd)g
+(parameters)g(\(that)i(giv)m(e)g(the)e(size)h(of)g(the)f(table\))i(are)
+f(64-bit)227 668 y(in)m(tegers)43 b(rather)f(than)f(32-bit)i(in)m
+(tegers.)76 b(Under)41 b(normal)g(circumstances,)46 b(the)c(nro)m(ws)f
+(and)g(nro)m(wsll)227 781 y(paramen)m(ters)f(should)e(ha)m(v)m(e)j(a)f
+(v)-5 b(alue)40 b(of)f(0;)45 b(CFITSIO)38 b(will)h(automatically)k(up)s
+(date)38 b(the)i(n)m(um)m(b)s(er)e(of)227 894 y(ro)m(ws)31
+b(as)f(data)h(is)g(written)f(to)h(the)g(table.)382 1158
+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 1271
+y(status\))382 1384 y(FTITABLL\(unit,rowlenll,n)o(row)o(sll,)o(tfie)o
+(lds)o(,tty)o(pe,t)o(bco)o(l,tf)o(orm,)o(tun)o(it,e)o(xtna)o(me,)f(>)
+716 1497 y(status\))0 1761 y Fh(9)81 b Fi(Insert)26 b(a)h(new)g(binary)
+f(table)h(extension)h(immediately)g(follo)m(wing)h(the)e(CHDU.)g(An)m
+(y)g(follo)m(wing)h(extensions)227 1874 y(will)39 b(b)s(e)f(shifted)g
+(do)m(wn)g(to)h(mak)m(e)g(ro)s(om)g(for)f(the)g(new)g(extension.)66
+b(If)38 b(there)h(are)f(no)h(other)f(follo)m(wing)227
+1987 y(extensions)f(then)g(the)f(new)g(bin)m(table)h(extension)h(will)f
+(simply)f(b)s(e)g(app)s(ended)e(to)k(the)e(end)g(of)h(the)g(\014le.)227
+2100 y(The)23 b(new)g(extension)h(will)f(b)s(ecome)h(the)f(CHDU.)h(The)
+f(FTIBINLL)g(routine)g(is)g(iden)m(tical)i(to)f(the)g(FTIBIN)227
+2213 y(routine)30 b(except)i(that)e(the)h(2nd)e(parameter)i(\(that)g
+(giv)m(es)g(the)g(length)f(of)h(the)f(table\))h(is)g(a)f(64-bit)i(in)m
+(teger)227 2325 y(rather)24 b(than)g(a)g(32-bit)h(in)m(teger.)40
+b(Under)23 b(normal)h(circumstances,)i(the)e(nro)m(ws)f(and)h(nro)m
+(wsll)g(paramen)m(ters)227 2438 y(should)31 b(ha)m(v)m(e)i(a)f(v)-5
+b(alue)32 b(of)f(0;)i(CFITSIO)d(will)i(automatically)j(up)s(date)30
+b(the)i(n)m(um)m(b)s(er)e(of)i(ro)m(ws)g(as)g(data)g(is)227
+2551 y(written)f(to)g(the)f(table.)382 2815 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\))382 2928
+y(FTIBINLL\(unit,nrowsll,tf)o(iel)o(ds,t)o(type)o(,tf)o(orm,)o(tuni)o
+(t,e)o(xtna)o(me,v)o(ari)o(dat)41 b(>)48 b(status\))0
+3380 y Fd(5.3)135 b(Keyw)l(ord)46 b(I/O)f(Routines)0
+3624 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)g(the)g(CHU.)382 3888 y Fe(FTPREC\(unit,card,)43
+b(>)k(status\))0 4152 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)g(datat)m(yp)s(e)h(in)m(to)g
+(the)f(CHU.)g(The)f(E)h(and)f(D)i(v)m(ersions)227 4265
+y(of)24 b(this)f(routine)g(ha)m(v)m(e)h(the)g(added)e(feature)i(that)g
+(if)f(the)g('decimals')i(parameter)f(is)f(negativ)m(e,)k(then)c(the)g
+('G')227 4378 y(displa)m(y)30 b(format)g(rather)f(then)g(the)h('E')f
+(format)h(will)g(b)s(e)f(used)f(when)h(constructing)h(the)f(k)m(eyw)m
+(ord)h(v)-5 b(alue,)227 4490 y(taking)27 b(the)g(absolute)g(v)-5
+b(alue)26 b(of)h('decimals')g(for)f(the)h(precision.)39
+b(This)26 b(will)g(suppress)e(trailing)k(zeros,)g(and)227
+4603 y(will)37 b(use)g(a)g(\014xed)f(format)h(rather)g(than)f(an)h(exp)
+s(onen)m(tial)g(format,)i(dep)s(ending)c(on)i(the)g(magnitude)g(of)227
+4716 y(the)31 b(v)-5 b(alue.)382 4980 y Fe(FTPKY[JKLS]\(unit,keyword)o
+(,ke)o(yval)o(,com)o(men)o(t,)42 b(>)47 b(status\))382
+5093 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 5357 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)e(the)h(header)g(is)g(at)227
+5470 y(k)m(ey)p 365 5470 28 4 v 34 w(no)42 b(=)f(1;)49
+b(if)42 b(k)m(ey)p 996 5470 V 34 w(no)g(=)f(0)i(then)e(this)h
+(subroutine)f(simple)h(mo)m(v)m(es)i(the)e(in)m(ternal)h(p)s(oin)m(ter)
+f(to)h(the)227 5583 y(b)s(eginning)35 b(of)h(the)g(header)f(so)h(that)g
+(subsequen)m(t)f(k)m(eyw)m(ord)h(op)s(erations)g(will)g(start)g(at)g
+(the)g(top)g(of)g(the)227 5696 y(header;)31 b(it)g(also)g(returns)e(a)i
+(blank)f(card)g(v)-5 b(alue)31 b(in)f(this)g(case.)p
+eop end
+%%Page: 33 39
+TeXDict begin 33 38 bop 0 299 a Fg(5.4.)72 b(D)m(A)-8
+b(T)g(A)32 b(I/O)f(R)m(OUTINES)2650 b Fi(33)382 555 y
+Fe(FTGREC\(unit,key_no,)42 b(>)48 b(card,status\))0 804
+y Fh(4)81 b Fi(Get)31 b(a)g(k)m(eyw)m(ord)g(v)-5 b(alue)30
+b(\(with)h(the)f(appropriate)h(datat)m(yp)s(e\))g(and)f(commen)m(t)i
+(from)e(the)g(CHU)382 1052 y Fe(FTGKY[EDJKLS]\(unit,keywo)o(rd,)41
+b(>)48 b(keyval,comment,status\))0 1301 y Fh(5)81 b Fi(Delete)32
+b(an)e(existing)i(k)m(eyw)m(ord)f(record.)382 1550 y
+Fe(FTDKEY\(unit,keyword,)42 b(>)48 b(status\))0 1881
+y Fd(5.4)135 b(Data)46 b(I/O)g(Routines)0 2132 y Fi(The)32
+b(follo)m(wing)i(routines)e(read)h(or)f(write)h(data)g(v)-5
+b(alues)33 b(in)f(the)h(curren)m(t)f(HDU)i(of)e(the)h(FITS)f(\014le.)47
+b(Automatic)0 2245 y(datat)m(yp)s(e)28 b(con)m(v)m(ersion)h(will)e(b)s
+(e)g(attempted)h(for)g(n)m(umerical)f(datat)m(yp)s(es)i(if)e(the)g(sp)s
+(eci\014ed)g(datat)m(yp)s(e)h(is)f(di\013eren)m(t)0 2357
+y(from)j(the)g(actual)i(datat)m(yp)s(e)g(of)e(the)h(FITS)e(arra)m(y)i
+(or)f(table)i(column.)0 2606 y Fh(1)81 b Fi(W)-8 b(rite)31
+b(elemen)m(ts)h(in)m(to)f(the)g(primary)e(data)j(arra)m(y)e(or)h(image)
+g(extension.)382 2855 y Fe(FTPPR[BIJKED]\(unit,group)o(,fp)o(ixel)o
+(,nel)o(eme)o(nts,)o(valu)o(es,)41 b(>)48 b(status\))0
+3103 y Fh(2)81 b Fi(Read)30 b(elemen)m(ts)j(from)d(the)h(primary)e
+(data)j(arra)m(y)f(or)g(image)h(extension.)42 b(Unde\014ned)29
+b(arra)m(y)j(elemen)m(ts)g(will)227 3216 y(b)s(e)f(returned)f(with)h(a)
+h(v)-5 b(alue)31 b(=)g(n)m(ullv)-5 b(al,)33 b(unless)d(n)m(ullv)-5
+b(al)32 b(=)f(0)h(in)f(whic)m(h)g(case)h(no)f(c)m(hec)m(ks)i(for)e
+(unde\014ned)227 3329 y(pixels)h(will)f(b)s(e)f(p)s(erformed.)42
+b(The)30 b(an)m(yf)i(parameter)f(is)g(set)h(to)g(true)f(\(=)g(.true.\))
+43 b(if)31 b(an)m(y)h(of)f(the)g(returned)227 3442 y(elemen)m(ts)h(w)m
+(ere)f(unde\014ned.)382 3691 y Fe(FTGPV[BIJKED]\(unit,group)o(,fp)o
+(ixel)o(,nel)o(eme)o(nts,)o(null)o(val)o(,)42 b(>)47
+b(values,anyf,status\))0 3939 y Fh(3)81 b Fi(W)-8 b(rite)36
+b(elemen)m(ts)h(in)m(to)f(an)f(ASCI)s(I)e(or)i(binary)g(table)h
+(column.)54 b(The)35 b(`felem')h(parameter)g(applies)f(only)g(to)227
+4052 y(v)m(ector)d(columns)e(in)g(binary)g(tables)h(and)f(is)g(ignored)
+h(when)e(writing)i(to)g(ASCI)s(I)d(tables.)382 4301 y
+Fe(FTPCL[SLBIJKEDCM]\(unit,c)o(oln)o(um,f)o(row,)o(fel)o(em,n)o(elem)o
+(ent)o(s,va)o(lues)o(,)42 b(>)47 b(status\))0 4549 y
+Fh(4)81 b Fi(Read)22 b(elemen)m(ts)h(from)e(an)g(ASCI)s(I)g(or)g
+(binary)g(table)i(column.)38 b(Unde\014ned)20 b(arra)m(y)i(elemen)m(ts)
+h(will)f(b)s(e)f(returned)227 4662 y(with)32 b(a)h(v)-5
+b(alue)33 b(=)f(n)m(ullv)-5 b(al,)34 b(unless)e(n)m(ullv)-5
+b(al)32 b(=)h(0)f(\(or)h(=)f(')h(')f(for)g(ftgcvs\))i(in)e(whic)m(h)g
+(case)i(no)e(c)m(hec)m(king)i(for)227 4775 y(unde\014ned)23
+b(v)-5 b(alues)25 b(will)g(b)s(e)g(p)s(erformed.)37 b(The)24
+b(ANYF)i(parameter)f(is)g(set)h(to)f(true)g(if)g(an)m(y)g(of)g(the)g
+(returned)227 4888 y(elemen)m(ts)32 b(are)f(unde\014ned.)227
+5036 y(An)m(y)d(column,)h(regardless)f(of)g(it's)h(in)m(trinsic)f
+(datat)m(yp)s(e,)i(ma)m(y)e(b)s(e)f(read)h(as)g(a)h(string.)40
+b(It)28 b(should)e(b)s(e)i(noted)227 5149 y(ho)m(w)m(ev)m(er)k(that)f
+(reading)f(a)h(n)m(umeric)f(column)g(as)h(a)g(string)f(is)g(10)i(-)e
+(100)i(times)f(slo)m(w)m(er)g(than)f(reading)h(the)227
+5262 y(same)36 b(column)f(as)h(a)g(n)m(um)m(b)s(er)e(due)g(to)j(the)e
+(large)i(o)m(v)m(erhead)f(in)f(constructing)h(the)g(formatted)g
+(strings.)227 5375 y(The)i(displa)m(y)g(format)g(of)g(the)g(returned)f
+(strings)g(will)h(b)s(e)g(determined)f(b)m(y)h(the)g(TDISPn)f(k)m(eyw)m
+(ord,)j(if)227 5488 y(it)d(exists,)h(otherwise)f(b)m(y)f(the)g(datat)m
+(yp)s(e)h(of)f(the)h(column.)57 b(The)36 b(length)g(of)h(the)f
+(returned)f(strings)h(can)227 5601 y(b)s(e)29 b(determined)f(with)h
+(the)g(ftgcdw)g(routine.)40 b(The)28 b(follo)m(wing)j(TDISPn)c(displa)m
+(y)j(formats)f(are)g(curren)m(tly)227 5714 y(supp)s(orted:)p
+eop end
+%%Page: 34 40
+TeXDict begin 34 39 bop 0 299 a Fi(34)1747 b Fg(CHAPTER)30
+b(5.)111 b(BASIC)30 b(INTERF)-10 b(A)m(CE)30 b(R)m(OUTINES)418
+555 y Fe(Iw.m)142 b(Integer)418 668 y(Ow.m)g(Octal)47
+b(integer)418 781 y(Zw.m)142 b(Hexadecimal)45 b(integer)418
+894 y(Fw.d)142 b(Fixed)47 b(floating)e(point)418 1007
+y(Ew.d)142 b(Exponential)45 b(floating)h(point)418 1120
+y(Dw.d)142 b(Exponential)45 b(floating)h(point)418 1233
+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 1483 y Fi(where)24 b(w)h(is)f(the)h(width)f
+(in)g(c)m(haracters)i(of)f(the)g(displa)m(y)m(ed)g(v)-5
+b(alues,)27 b(m)d(is)h(the)f(minim)m(um)g(n)m(um)m(b)s(er)g(of)g
+(digits)227 1595 y(displa)m(y)m(ed,)31 b(and)e(d)h(is)f(the)i(n)m(um)m
+(b)s(er)d(of)i(digits)g(to)h(the)f(righ)m(t)h(of)f(the)g(decimal.)41
+b(The)29 b(.m)h(\014eld)g(is)g(optional.)382 1855 y Fe
+(FTGCV[SBIJKEDCM]\(unit,co)o(lnu)o(m,fr)o(ow,f)o(ele)o(m,ne)o(leme)o
+(nts)o(,nul)o(lval)o(,)42 b(>)1098 1968 y(values,anyf,status\))0
+2228 y Fh(5)81 b Fi(Get)42 b(the)g(table)h(column)e(n)m(um)m(b)s(er)g
+(and)g(full)g(name)h(of)g(the)f(column)h(whose)f(name)h(matc)m(hes)h
+(the)f(input)227 2341 y(template)35 b(string.)48 b(See)33
+b(the)h(`Adv)-5 b(anced)33 b(In)m(terface)h(Routines')f(c)m(hapter)h
+(for)f(a)g(full)g(description)g(of)g(this)227 2454 y(routine.)382
+2714 y Fe(FTGCNN\(unit,casesen,colt)o(emp)o(late)o(,)42
+b(>)47 b(colname,colnum,status\))p eop end
+%%Page: 35 41
+TeXDict begin 35 40 bop 0 1225 a Ff(Chapter)65 b(6)0
+1687 y Fl(Adv)-13 b(anced)78 b(In)-6 b(terface)77 b(Subroutines)0
+2180 y Fi(This)31 b(c)m(hapter)h(de\014nes)f(all)h(the)g(a)m(v)-5
+b(ailable)34 b(subroutines)d(in)g(the)h(FITSIO)e(user)h(in)m(terface.)
+46 b(F)-8 b(or)33 b(completeness,)0 2293 y(the)43 b(basic)g
+(subroutines)e(describ)s(ed)g(in)i(the)f(previous)h(c)m(hapter)g(are)g
+(also)g(rep)s(eated)g(here.)77 b(A)43 b(righ)m(t)g(arro)m(w)0
+2406 y(sym)m(b)s(ol)29 b(is)f(used)g(here)h(to)g(separate)h(the)f
+(input)f(parameters)h(from)f(the)h(output)g(parameters)g(in)f(the)h
+(de\014nition)0 2518 y(of)k(eac)m(h)h(subroutine.)47
+b(This)32 b(sym)m(b)s(ol)h(is)g(not)g(actually)i(part)d(of)h(the)h
+(calling)g(sequence.)49 b(An)32 b(alphab)s(etical)i(list)0
+2631 y(and)c(de\014nition)g(of)g(all)i(the)e(parameters)h(is)f(giv)m
+(en)i(at)f(the)f(end)g(of)h(this)f(section.)0 2961 y
+Fd(6.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)25 b(an)i(existing)h(FITS)f(\014le)g(with)g
+(readonly)g(or)g(readwrite)g(access.)41 b(The)27 b(FTDK)m(OPEN)g
+(routine)g(simply)227 3310 y(op)s(ens)32 b(the)g(sp)s(eci\014ed)g
+(\014le)h(without)f(trying)h(to)g(in)m(terpret)g(the)f(\014lename)h
+(using)f(the)g(extended)h(\014lename)227 3423 y(syn)m(tax.)41
+b(FTDOPN)28 b(op)s(ens)e(the)i(\014le)g(and)f(also)i(mo)m(v)m(es)g(to)g
+(the)f(\014rst)f(HDU)h(con)m(taining)h(signi\014can)m(t)g(data,)227
+3536 y(if)35 b(no)h(sp)s(eci\014c)f(HDU)h(is)f(sp)s(eci\014ed)f(as)i
+(part)f(of)g(the)h(\014lename.)55 b(FTTOPN)35 b(and)f(FTIOPN)h(are)h
+(similar)227 3649 y(except)26 b(that)f(they)g(will)g(mo)m(v)m(e)h(to)g
+(the)f(\014rst)f(table)h(HDU)h(or)e(image)i(HDU,)g(resp)s(ectiv)m(ely)
+-8 b(,)28 b(if)c(a)h(HDU)h(name)227 3762 y(or)31 b(n)m(um)m(b)s(er)e
+(is)h(not)h(sp)s(eci\014ed)e(as)i(part)f(of)h(the)f(\014lename.)382
+3996 y Fe(FTOPEN\(unit,filename,rwm)o(ode)o(,)42 b(>)47
+b(blocksize,status\))382 4108 y(FTDKOPEN\(unit,filename,r)o(wmo)o(de,)
+41 b(>)48 b(blocksize,status\))382 4334 y(FTDOPN\(unit,filename,rwm)o
+(ode)o(,)42 b(>)47 b(status\))382 4447 y(FTTOPN\(unit,filename,rwm)o
+(ode)o(,)42 b(>)47 b(status\))382 4560 y(FTIOPN\(unit,filename,rwm)o
+(ode)o(,)42 b(>)47 b(status\))0 4794 y Fh(2)81 b Fi(Op)s(en)24
+b(an)i(existing)h(FITS)e(\014le)h(with)f(readonly)h(or)g(readwrite)g
+(access)h(and)f(mo)m(v)m(e)h(to)f(a)h(follo)m(wing)g(extension,)227
+4907 y(if)38 b(one)g(w)m(as)g(sp)s(eci\014ed)g(as)g(part)f(of)h(the)h
+(\014lename.)63 b(\(e.g.,)42 b('\014lename.\014ts+2')c(or)g
+('\014lename.\014ts[2]')i(will)227 5020 y(mo)m(v)m(e)e(to)g(the)e(3rd)g
+(HDU)i(in)e(the)h(\014le\).)60 b(Note)37 b(that)h(this)e(routine)h
+(di\013ers)f(from)g(FTOPEN)g(in)g(that)h(it)227 5133
+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)
+j(argumen)m(t.)382 5367 y Fe(FTNOPN\(unit,filename,rwm)o(ode)o(,)42
+b(>)47 b(status\))0 5601 y Fh(3)81 b Fi(Reop)s(en)38
+b(a)i(FITS)e(\014le)i(that)f(w)m(as)h(previously)f(op)s(ened)f(with)h
+(FTOPEN,)g(FTNOPN,)g(or)h(FTINIT.)e(The)227 5714 y(newunit)f(n)m(um)m
+(b)s(er)f(ma)m(y)j(then)e(b)s(e)g(treated)i(as)f(a)g(separate)g
+(\014le,)i(and)d(one)h(ma)m(y)h(sim)m(ultaneously)f(read)1905
+5942 y(35)p eop end
+%%Page: 36 42
+TeXDict begin 36 41 bop 0 299 a Fi(36)1319 b Fg(CHAPTER)29
+b(6.)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(or)36 b(write)g(to)g(2)g(\(or)g(more\))g
+(di\013eren)m(t)g(extensions)g(in)f(the)h(same)g(\014le.)56
+b(The)35 b(FTOPEN)g(and)g(FTNOPN)227 668 y(routines)f(\(ab)s(o)m(v)m
+(e\))h(automatically)h(detects)f(cases)g(where)e(a)g(previously)h(op)s
+(ened)e(\014le)i(is)g(b)s(eing)f(op)s(ened)227 781 y(again,)c(and)e
+(then)g(in)m(ternally)h(call)g(FTREOPEN,)f(so)h(programs)e(should)h
+(rarely)g(need)g(to)h(explicitly)h(call)227 894 y(this)i(routine.)334
+1136 y Fe(FTREOPEN\(unit,)44 b(>)j(newunit,)f(status\))0
+1377 y Fh(4)81 b Fi(Op)s(en)24 b(and)g(initialize)k(a)e(new)f(empt)m(y)
+g(FITS)g(\014le.)39 b(The)25 b(FTDKINIT)g(routine)g(simply)g(creates)i
+(the)f(sp)s(eci\014ed)227 1490 y(\014le)31 b(without)f(trying)h(to)g
+(in)m(terpret)f(the)h(\014lename)g(using)e(the)i(extended)f(\014lename)
+h(syn)m(tax.)334 1732 y Fe(FTINIT\(unit,filename,bloc)o(ksi)o(ze,)41
+b(>)48 b(status\))334 1845 y(FTDKINIT\(unit,filename,bl)o(ock)o(size)o
+(,)42 b(>)47 b(status\))0 2087 y Fh(5)81 b Fi(Create)24
+b(a)g(new)f(FITS)g(\014le,)i(using)e(a)h(template)h(\014le)e(to)i
+(de\014ne)d(its)i(initial)h(size)g(and)e(structure.)37
+b(The)24 b(template)227 2199 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)j(\014le.)64 b(If)38
+b(the)h(input)e(template)j(\014le)e(name)h(is)227 2312
+y(blank,)28 b(then)f(this)g(routine)g(b)s(eha)m(v)m(es)h(the)f(same)h
+(as)f(FTINIT.)g(The)f(curren)m(tly)i(supp)s(orted)d(format)i(of)h(the)
+227 2425 y(ASCI)s(I)c(template)j(\014le)f(is)f(describ)s(ed)g(under)f
+(the)i(\014ts)p 2037 2425 28 4 v 32 w(parse)p 2277 2425
+V 33 w(template)g(routine)g(\(in)g(the)f(general)i(Utilities)227
+2538 y(section\),)32 b(but)e(this)g(ma)m(y)h(c)m(hange)h(sligh)m(tly)g
+(later)f(releases)g(of)g(CFITSIO.)334 2780 y Fe(FTTPLT\(unit,)45
+b(filename,)g(tplfilename,)f(>)k(status\))0 3022 y Fh(6)81
+b Fi(Flush)33 b(in)m(ternal)h(bu\013ers)f(of)h(data)g(to)g(the)g
+(output)g(FITS)f(\014le)h(previously)f(op)s(ened)g(with)g(ftop)s(en)h
+(or)f(ftinit.)227 3135 y(The)j(routine)h(usually)f(nev)m(er)h(needs)f
+(to)i(b)s(e)e(called,)j(but)d(doing)h(so)g(will)g(ensure)f(that)h(if)f
+(the)h(program)227 3247 y(subsequen)m(tly)30 b(ab)s(orts,)g(then)h(the)
+f(FITS)g(\014le)g(will)h(ha)m(v)m(e)h(at)f(least)g(b)s(een)f(closed)h
+(prop)s(erly)-8 b(.)382 3489 y Fe(FTFLUS\(unit,)44 b(>)k(status\))0
+3731 y Fh(7)81 b Fi(Close)31 b(a)f(FITS)g(\014le)g(previously)g(op)s
+(ened)g(with)g(ftop)s(en)g(or)g(ftinit)382 3973 y Fe(FTCLOS\(unit,)44
+b(>)k(status\))0 4214 y Fh(8)81 b Fi(Close)34 b(and)f(DELETE)g(a)h
+(FITS)f(\014le)h(previously)f(op)s(ened)g(with)g(ftop)s(en)g(or)h
+(ftinit.)51 b(This)33 b(routine)g(ma)m(y)i(b)s(e)227
+4327 y(useful)29 b(in)h(cases)g(where)g(a)g(FITS)f(\014le)g(is)h
+(created,)h(but)e(an)h(error)f(o)s(ccurs)h(whic)m(h)f(prev)m(en)m(ts)i
+(the)e(complete)227 4440 y(\014le)i(from)f(b)s(eing)g(written.)382
+4682 y Fe(FTDELT\(unit,)44 b(>)k(status\))0 4924 y Fh(9)81
+b Fi(Get)31 b(the)g(v)-5 b(alue)31 b(of)f(an)g(un)m(used)g(I/O)g(unit)g
+(n)m(um)m(b)s(er)f(whic)m(h)h(ma)m(y)h(then)f(b)s(e)g(used)g(as)g
+(input)g(to)h(FTOPEN)f(or)227 5036 y(FTINIT.)36 b(This)f(routine)h
+(searc)m(hes)h(for)f(the)g(\014rst)f(un)m(used)g(unit)g(n)m(um)m(b)s
+(er)g(in)g(the)i(range)f(from)f(with)h(99)227 5149 y(do)m(wn)d(to)h
+(50.)50 b(This)32 b(routine)h(just)g(k)m(eeps)h(an)f(in)m(ternal)h
+(list)f(of)h(the)f(allo)s(cated)i(unit)e(n)m(um)m(b)s(ers)f(and)g(do)s
+(es)227 5262 y(not)26 b(ph)m(ysically)g(c)m(hec)m(k)g(that)g(the)g(F)-8
+b(ortran)25 b(unit)g(is)g(a)m(v)-5 b(ailable)28 b(\(to)e(b)s(e)f
+(compatible)h(with)f(the)g(SPP)f(v)m(ersion)227 5375
+y(of)35 b(FITSIO\).)g(Th)m(us)f(users)g(m)m(ust)h(not)g(indep)s(enden)m
+(tly)f(allo)s(cate)j(an)m(y)f(unit)e(n)m(um)m(b)s(ers)g(in)h(the)g
+(range)g(50)227 5488 y(-)42 b(99)g(if)f(this)g(routine)g(is)g(also)h
+(to)g(b)s(e)f(used)f(in)h(the)g(same)h(program.)73 b(This)40
+b(routine)h(is)g(pro)m(vided)g(for)227 5601 y(con)m(v)m(enience)34
+b(only)-8 b(,)32 b(and)e(it)i(is)f(not)h(required)e(that)i(the)f(unit)g
+(n)m(um)m(b)s(ers)f(used)g(b)m(y)h(FITSIO)f(b)s(e)h(allo)s(cated)227
+5714 y(b)m(y)g(this)f(routine.)p eop end
+%%Page: 37 43
+TeXDict begin 37 42 bop 0 299 a Fg(6.1.)72 b(FITS)30
+b(FILE)g(OPEN)g(AND)h(CLOSE)e(SUBR)m(OUTINES:)1561 b
+Fi(37)382 555 y Fe(FTGIOU\()46 b(>)h(iounit,)f(status\))0
+807 y Fh(10)g Fi(F)-8 b(ree)34 b(\(deallo)s(cate\))i(an)d(I/O)g(unit)f
+(n)m(um)m(b)s(er)g(whic)m(h)g(w)m(as)h(previously)g(allo)s(cated)i
+(with)e(FTGIOU.)g(All)g(pre-)227 919 y(viously)28 b(allo)s(cated)i
+(unit)d(n)m(um)m(b)s(ers)f(ma)m(y)i(b)s(e)f(deallo)s(cated)j(at)e(once)
+h(b)m(y)e(calling)i(FTFIOU)f(with)f(iounit)h(=)227 1032
+y(-1.)382 1284 y Fe(FTFIOU\(iounit,)44 b(>)j(status\))0
+1535 y Fh(11)f Fi(Return)30 b(the)h(F)-8 b(ortran)31
+b(unit)g(n)m(um)m(b)s(er)e(that)i(corresp)s(onds)f(to)h(the)g(C)g
+(\014ts\014le)f(p)s(oin)m(ter)h(v)-5 b(alue,)32 b(or)e(vice)i(v)m
+(ersa.)227 1648 y(These)37 b(2)h(C)f(routines)g(ma)m(y)g(b)s(e)g
+(useful)f(in)h(mixed)g(language)i(programs)e(where)f(b)s(oth)h(C)g(and)
+f(F)-8 b(ortran)227 1761 y(subroutines)25 b(need)g(to)i(access)g(the)f
+(same)g(\014le.)40 b(F)-8 b(or)26 b(example,)i(if)e(a)g(FITS)f(\014le)h
+(is)g(op)s(ened)f(with)g(unit)g(12)i(b)m(y)227 1874 y(a)k(F)-8
+b(ortran)31 b(subroutine,)f(then)g(a)h(C)f(routine)h(within)f(the)g
+(same)h(program)g(could)f(get)i(the)e(\014t\014le)h(p)s(oin)m(ter)227
+1987 y(v)-5 b(alue)39 b(to)f(access)h(the)f(same)h(\014le)f(b)m(y)f
+(calling)j('fptr)d(=)h(CUnit2FITS\(12\)'.)64 b(These)38
+b(routines)g(return)f(a)227 2100 y(v)-5 b(alue)31 b(of)g(zero)g(if)f
+(an)g(error)g(o)s(ccurs.)286 2351 y Fe(int)334 b(CFITS2Unit\(fitsfile)
+42 b(*ptr\);)286 2464 y(fitsfile*)k(CUnit2FITS\(int)e(unit\);)0
+2715 y Fh(11)i Fi(P)m(arse)32 b(the)g(input)e(\014lename)i(and)f
+(return)f(the)i(HDU)g(n)m(um)m(b)s(er)e(that)i(w)m(ould)f(b)s(e)g(mo)m
+(v)m(ed)i(to)f(if)f(the)h(\014le)f(w)m(ere)227 2828 y(op)s(ened)i(with)
+g(FTNOPN.)g(The)f(returned)g(HDU)i(n)m(um)m(b)s(er)e(b)s(egins)h(with)g
+(1)g(for)g(the)g(primary)g(arra)m(y)-8 b(,)35 b(so)227
+2941 y(for)d(example,)g(if)g(the)g(input)f(\014lename)g(=)h(`m)m
+(y\014le.\014ts[2]')h(then)e(hdun)m(um)e(=)j(3)g(will)g(b)s(e)f
+(returned.)43 b(FIT-)227 3054 y(SIO)35 b(do)s(es)h(not)g(op)s(en)g(the)
+g(\014le)g(to)h(c)m(hec)m(k)h(if)e(the)g(extension)h(actually)h(exists)
+e(if)h(an)e(extension)i(n)m(um)m(b)s(er)227 3167 y(is)43
+b(sp)s(eci\014ed.)75 b(If)42 b(an)g(extension)h(*name*)g(is)f(included)
+g(in)g(the)g(\014le)g(name)h(sp)s(eci\014cation)g(\(e.g.)77
+b(`m)m(y-)227 3280 y(\014le.\014ts[EVENTS]')30 b(then)f(this)h(routine)
+g(will)g(ha)m(v)m(e)h(to)f(op)s(en)f(the)h(FITS)f(\014le)h(and)f(lo)s
+(ok)h(for)g(the)g(p)s(osition)227 3393 y(of)38 b(the)h(named)e
+(extension,)k(then)d(close)h(\014le)f(again.)64 b(This)38
+b(is)g(not)g(p)s(ossible)f(if)h(the)g(\014le)g(is)g(b)s(eing)g(read)227
+3506 y(from)e(the)g(stdin)f(stream,)j(and)d(an)h(error)f(will)h(b)s(e)g
+(returned)e(in)i(this)g(case.)58 b(If)35 b(the)h(\014lename)g(do)s(es)g
+(not)227 3619 y(sp)s(ecify)29 b(an)g(explicit)h(extension)g(\(e.g.)42
+b('m)m(y\014le.\014ts'\))30 b(then)f(hdun)m(um)e(=)h(-99)j(will)e(b)s
+(e)g(returned,)f(whic)m(h)h(is)227 3731 y(functionally)34
+b(equiv)-5 b(alen)m(t)35 b(to)g(hdun)m(um)c(=)i(1.)50
+b(This)33 b(routine)g(is)h(mainly)g(used)e(for)i(bac)m(kw)m(ard)g
+(compati-)227 3844 y(bilit)m(y)g(in)e(the)g(fto)s(ols)h(soft)m(w)m(are)
+h(pac)m(k)-5 b(age)34 b(and)e(is)g(not)g(recommended)g(for)g(general)i
+(use.)46 b(It)32 b(is)h(generally)227 3957 y(b)s(etter)i(and)g(more)g
+(e\016cien)m(t)h(to)g(\014rst)e(op)s(en)g(the)h(FITS)f(\014le)h(with)g
+(FTNOPN,)g(then)g(use)f(FTGHDN)i(to)227 4070 y(determine)30
+b(whic)m(h)g(HDU)g(in)f(the)h(\014le)g(has)g(b)s(een)f(op)s(ened,)g
+(rather)g(than)h(calling)h(FTEXTN)f(follo)m(w)m(ed)h(b)m(y)227
+4183 y(a)g(call)h(to)f(FTNOPN.)382 4434 y Fe(FTEXTN\(filename,)43
+b(>)48 b(nhdu,)e(status\))0 4686 y Fh(12)g Fi(Return)30
+b(the)g(name)h(of)f(the)h(op)s(ened)e(FITS)h(\014le.)382
+4937 y Fe(FTFLNM\(unit,)44 b(>)k(filename,)d(status\))0
+5188 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)g(\(READONL)-8 b(Y)32 b(=)e(0,)h(READ)m(WRITE)g(=)f
+(1\).)382 5440 y Fe(FTFLMD\(unit,)44 b(>)k(iomode,)e(status\))0
+5691 y Fh(14)g Fi(Return)30 b(the)g(\014le)h(t)m(yp)s(e)f(of)h(the)f
+(op)s(ened)g(FITS)g(\014le)g(\(e.g.)42 b('\014le://',)32
+b('ftp://',)g(etc.\).)p eop end
+%%Page: 38 44
+TeXDict begin 38 43 bop 0 299 a Fi(38)1319 b Fg(CHAPTER)29
+b(6.)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(FTURLT\(unit,)44 b(>)k(urltype,)d
+(status\))0 819 y Fh(15)h Fi(P)m(arse)27 b(the)f(input)f(\014lename)i
+(or)f(URL)g(in)m(to)h(its)g(comp)s(onen)m(t)f(parts:)39
+b(the)26 b(\014le)g(t)m(yp)s(e)h(\(\014le://,)h(ftp://,)g(h)m(ttp://,)
+227 932 y(etc\),)34 b(the)e(base)g(input)e(\014le)i(name,)g(the)g(name)
+g(of)g(the)g(output)f(\014le)h(that)g(the)g(input)f(\014le)g(is)h(to)g
+(b)s(e)f(copied)227 1045 y(to)38 b(prior)e(to)h(op)s(ening,)h(the)f
+(HDU)g(or)f(extension)i(sp)s(eci\014cation,)h(the)e(\014ltering)f(sp)s
+(eci\014er,)i(the)f(binning)227 1157 y(sp)s(eci\014er,)e(and)e(the)i
+(column)f(sp)s(eci\014er.)51 b(Blank)34 b(strings)g(will)h(b)s(e)e
+(returned)g(for)h(an)m(y)g(comp)s(onen)m(ts)g(that)227
+1270 y(are)d(not)g(presen)m(t)f(in)g(the)h(input)e(\014le)i(name.)334
+1534 y Fe(FTIURL\(filename,)43 b(>)48 b(filetype,)d(infile,)h(outfile,)
+g(extspec,)f(filter,)716 1647 y(binspec,)g(colspec,)h(status\))0
+1910 y Fh(16)g Fi(P)m(arse)e(the)g(input)f(\014le)h(name)f(and)g
+(return)g(the)h(ro)s(ot)g(\014le)f(name.)81 b(The)43
+b(ro)s(ot)h(name)g(includes)f(the)h(\014le)227 2023 y(t)m(yp)s(e)35
+b(if)g(sp)s(eci\014ed,)h(\(e.g.)56 b('ftp://')37 b(or)e('h)m(ttp://'\))
+i(and)d(the)h(full)g(path)g(name,)h(to)g(the)f(exten)m(t)i(that)e(it)h
+(is)227 2136 y(sp)s(eci\014ed)26 b(in)f(the)i(input)e(\014lename.)39
+b(It)26 b(do)s(es)g(not)g(include)g(the)g(HDU)h(name)f(or)g(n)m(um)m(b)
+s(er,)g(or)g(an)m(y)h(\014ltering)227 2249 y(sp)s(eci\014cations.)334
+2513 y Fe(FTRTNM\(filename,)43 b(>)48 b(rootname,)d(status\))0
+2776 y Fh(16)h Fi(T)-8 b(est)36 b(if)g(the)g(input)f(\014le)h(or)f(a)i
+(compressed)e(v)m(ersion)h(of)g(the)g(\014le)g(\(with)g(a)g(.gz,)i(.Z,)
+e(.z,)i(or)e(.zip)g(extension\))227 2889 y(exists)j(on)f(disk.)63
+b(The)37 b(returned)g(v)-5 b(alue)38 b(of)g(the)h('exists')g(parameter)
+f(will)g(ha)m(v)m(e)i(1)e(of)g(the)g(4)g(follo)m(wing)227
+3002 y(v)-5 b(alues:)370 3257 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
+3370 y(1:)95 b(the)47 b(disk)g(file)g(does)f(exist)370
+3483 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 3596 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 3709 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
+3973 y(FTEXIST\(filename,)d(>)48 b(exists,)e(status\);)0
+4311 y Fd(6.2)135 b(HDU-Lev)l(el)47 b(Op)t(erations)0
+4562 y Fi(When)30 b(a)h(FITS)f(\014le)g(is)h(\014rst)e(op)s(ened)h(or)g
+(created,)i(the)f(in)m(ternal)g(bu\013ers)e(in)h(FITSIO)f
+(automatically)34 b(p)s(oin)m(t)c(to)0 4675 y(the)g(\014rst)g(HDU)h(in)
+f(the)g(\014le.)41 b(The)29 b(follo)m(wing)j(routines)e(ma)m(y)h(b)s(e)
+e(used)h(to)h(mo)m(v)m(e)g(to)g(another)f(HDU)h(in)f(the)h(\014le.)0
+4788 y(Note)j(that)f(the)g(HDU)g(n)m(um)m(b)s(ering)f(con)m(v)m(en)m
+(tion)i(used)e(in)g(FITSIO)g(denotes)h(the)f(primary)g(arra)m(y)h(as)g
+(the)g(\014rst)0 4901 y(HDU,)e(the)g(\014rst)f(extension)h(in)f(a)g
+(FITS)g(\014le)g(is)h(the)f(second)h(HDU,)g(and)f(so)h(on.)0
+5164 y Fh(1)81 b Fi(Mo)m(v)m(e)32 b(to)f(a)g(sp)s(eci\014ed)f
+(\(absolute\))h(HDU)g(in)g(the)f(FITS)g(\014le)g(\(nhdu)f(=)h(1)h(for)f
+(the)g(FITS)g(primary)f(arra)m(y\))382 5428 y Fe(FTMAHD\(unit,nhdu,)43
+b(>)k(hdutype,status\))0 5691 y Fh(2)81 b Fi(Mo)m(v)m(e)32
+b(to)f(a)g(new)f(\(existing\))i(HDU)f(forw)m(ard)f(or)g(bac)m(kw)m
+(ards)h(relativ)m(e)h(to)f(the)g(CHDU)p eop end
+%%Page: 39 45
+TeXDict begin 39 44 bop 0 299 a Fg(6.2.)72 b(HDU-LEVEL)31
+b(OPERA)-8 b(TIONS)2414 b Fi(39)382 555 y Fe(FTMRHD\(unit,nmove,)43
+b(>)k(hdutype,status\))0 788 y Fh(3)81 b Fi(Mo)m(v)m(e)22
+b(to)f(the)f(\(\014rst\))h(HDU)g(whic)m(h)f(has)g(the)g(sp)s(eci\014ed)
+g(extension)h(t)m(yp)s(e)f(and)g(EXTNAME)g(\(or)h(HDUNAME\))227
+901 y(and)34 b(EXTVER)g(k)m(eyw)m(ord)h(v)-5 b(alues.)53
+b(The)34 b(hdut)m(yp)s(e)f(parameter)i(ma)m(y)g(ha)m(v)m(e)g(a)g(v)-5
+b(alue)35 b(of)f(IMA)m(GE)p 3665 901 28 4 v 34 w(HDU)227
+1014 y(\(0\),)43 b(ASCI)s(I)p 669 1014 V 31 w(TBL)c(\(1\),)j(BINAR)-8
+b(Y)p 1468 1014 V 34 w(TBL)39 b(\(2\),)j(or)d(ANY)p 2234
+1014 V 34 w(HDU)g(\(-1\))i(where)d(ANY)p 3173 1014 V
+34 w(HDU)h(means)g(that)227 1127 y(only)30 b(the)g(extname)h(and)e
+(extv)m(er)i(v)-5 b(alues)30 b(will)g(b)s(e)f(used)g(to)i(lo)s(cate)g
+(the)f(correct)h(extension.)42 b(If)29 b(the)h(input)227
+1240 y(v)-5 b(alue)27 b(of)f(extv)m(er)h(is)f(0)g(then)g(the)g(EXTVER)g
+(k)m(eyw)m(ord)g(is)g(ignored)g(and)g(the)g(\014rst)f(HDU)i(with)e(a)i
+(matc)m(hing)227 1353 y(EXTNAME)g(\(or)g(HDUNAME\))h(k)m(eyw)m(ord)f
+(will)g(b)s(e)f(found.)38 b(If)26 b(no)h(matc)m(hing)h(HDU)f(is)g
+(found)e(in)h(the)h(\014le)227 1466 y(then)i(the)g(curren)m(t)g(HDU)h
+(will)f(remain)g(unc)m(hanged)g(and)g(a)g(status)g(=)g(BAD)p
+2884 1466 V 34 w(HDU)p 3123 1466 V 33 w(NUM)h(\(301\))h(will)f(b)s(e)
+227 1578 y(returned.)382 1811 y Fe(FTMNHD\(unit,)44 b(hdutype,)i
+(extname,)f(extver,)h(>)i(status\))0 2044 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)f
+(the)h(FITS)e(\014le)i(\(primary)f(arra)m(y)g(=)g(1\))382
+2277 y Fe(FTGHDN\(unit,)44 b(>)k(nhdu\))0 2510 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)e
+(the)h(FITS)f(\014le.)71 b(The)41 b(p)s(ossible)f(v)-5
+b(alues)41 b(for)f(hdut)m(yp)s(e)g(are)227 2623 y(IMA)m(GE)p
+546 2623 V 34 w(HDU)31 b(\(0\),)h(ASCI)s(I)p 1242 2623
+V 31 w(TBL)e(\(1\),)i(or)e(BINAR)-8 b(Y)p 2133 2623 V
+34 w(TBL)30 b(\(2\).)382 2856 y Fe(FTGHDT\(unit,)44 b(>)k(hdutype,)d
+(status\))0 3089 y Fh(6)81 b Fi(Return)29 b(the)i(total)h(n)m(um)m(b)s
+(er)d(of)i(HDUs)f(in)h(the)f(FITS)g(\014le.)41 b(The)29
+b(CHDU)i(remains)f(unc)m(hanged.)382 3322 y Fe(FTTHDU\(unit,)44
+b(>)k(hdunum,)e(status\))0 3554 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)h(the)e(last)
+h(extension)g(that)g(has)f(b)s(een)f(previously)h(ac-)227
+3667 y(cessed)41 b(b)m(y)f(the)g(program.)70 b(This)40
+b(will)g(o)m(v)m(erwrite)i(an)m(y)f(extensions)g(in)e(an)i(existing)g
+(FITS)e(\014le)i(if)f(the)227 3780 y(program)31 b(has)g(not)g(already)h
+(mo)m(v)m(ed)g(to)f(that)h(\(or)f(a)h(later\))g(extension)g(using)e
+(the)h(FTMAHD)h(or)f(FTM-)227 3893 y(RHD)24 b(routines.)38
+b(F)-8 b(or)25 b(example,)g(if)f(an)f(existing)h(FITS)f(\014le)g(con)m
+(tains)i(a)f(primary)e(arra)m(y)i(and)f(5)g(extensions)227
+4006 y(and)31 b(a)h(program)f(\(1\))h(op)s(ens)f(the)g(FITS)g(\014le,)h
+(\(2\))g(mo)m(v)m(es)h(to)f(extension)g(4,)g(\(3\))g(mo)m(v)m(es)h(bac)
+m(k)f(to)g(the)f(pri-)227 4119 y(mary)36 b(arra)m(y)-8
+b(,)38 b(and)e(\(4\))h(then)e(calls)i(FTCRHD,)f(then)g(the)g(new)g
+(extension)g(will)g(b)s(e)g(written)f(follo)m(wing)227
+4232 y(the)c(4th)f(extension,)i(o)m(v)m(erwriting)g(the)e(existing)h
+(5th)g(extension.)382 4465 y Fe(FTCRHD\(unit,)44 b(>)k(status\))0
+4698 y Fh(8)81 b Fi(Create)30 b(a)f(primary)f(arra)m(y)i(\(if)g(none)f
+(already)g(exists\),)i(or)e(insert)g(a)h(new)f(IMA)m(GE)h(extension)g
+(immediately)227 4811 y(follo)m(wing)25 b(the)e(CHDU,)g(or)g(insert)g
+(a)g(new)g(Primary)f(Arra)m(y)h(at)h(the)f(b)s(eginning)f(of)h(the)g
+(\014le.)38 b(An)m(y)23 b(follo)m(wing)227 4924 y(extensions)29
+b(in)g(the)g(\014le)f(will)h(b)s(e)f(shifted)h(do)m(wn)f(to)h(mak)m(e)h
+(ro)s(om)e(for)h(the)g(new)f(extension.)40 b(If)29 b(the)g(CHDU)227
+5036 y(is)h(the)g(last)g(HDU)g(in)g(the)f(\014le)h(then)f(the)h(new)f
+(image)i(extension)f(will)g(simply)f(b)s(e)g(app)s(ended)f(to)i(the)g
+(end)227 5149 y(of)k(the)h(\014le.)52 b(One)33 b(can)h(force)h(a)g(new)
+e(primary)g(arra)m(y)i(to)g(b)s(e)e(inserted)h(at)h(the)f(b)s(eginning)
+f(of)h(the)h(FITS)227 5262 y(\014le)29 b(b)m(y)f(setting)i(status)e(=)h
+(-9)g(prior)e(to)j(calling)g(the)e(routine.)40 b(In)28
+b(this)g(case)i(the)e(existing)i(primary)d(arra)m(y)227
+5375 y(will)f(b)s(e)f(con)m(v)m(erted)i(to)g(an)e(IMA)m(GE)h
+(extension.)40 b(The)25 b(new)g(extension)i(\(or)f(primary)e(arra)m
+(y\))j(will)f(b)s(ecome)227 5488 y(the)32 b(CHDU.)f(The)g(FTI)s(IMGLL)f
+(routine)i(is)f(iden)m(tical)i(to)e(the)h(FTI)s(IMG)f(routine)g(except)
+h(that)f(the)h(4th)227 5601 y(parameter)25 b(\(the)g(length)g(of)f(eac)
+m(h)h(axis\))g(is)g(an)f(arra)m(y)h(of)f(64-bit)i(in)m(tegers)f(rather)
+f(than)g(an)g(arra)m(y)h(of)g(32-bit)227 5714 y(in)m(tegers.)p
+eop end
+%%Page: 40 46
+TeXDict begin 40 45 bop 0 299 a Fi(40)1319 b Fg(CHAPTER)29
+b(6.)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(FTIIMG\(unit,bitpix,naxis)o(,na)o(xes,)41
+b(>)48 b(status\))382 668 y(FTIIMGLL\(unit,bitpix,nax)o(is,)o(naxe)o
+(sll,)41 b(>)47 b(status\))0 921 y Fh(9)81 b Fi(Insert)30
+b(a)i(new)f(ASCI)s(I)f(T)-8 b(ABLE)31 b(extension)h(immediately)h
+(follo)m(wing)f(the)g(CHDU.)g(An)m(y)f(follo)m(wing)i(exten-)227
+1034 y(sions)26 b(will)g(b)s(e)f(shifted)g(do)m(wn)g(to)h(mak)m(e)h(ro)
+s(om)e(for)h(the)f(new)g(extension.)40 b(If)25 b(there)h(are)g(no)g
+(other)f(follo)m(wing)227 1147 y(extensions)32 b(then)f(the)h(new)f
+(table)h(extension)g(will)g(simply)f(b)s(e)g(app)s(ended)f(to)i(the)f
+(end)g(of)h(the)f(\014le.)44 b(The)227 1260 y(new)33
+b(extension)h(will)f(b)s(ecome)h(the)f(CHDU.)h(The)f(FTIT)-8
+b(ABLL)33 b(routine)g(is)g(iden)m(tical)i(to)f(the)g(FTIT)-8
+b(AB)227 1373 y(routine)36 b(except)g(that)g(the)f(2nd)g(and)g(3rd)g
+(parameters)g(\(that)i(giv)m(e)g(the)e(size)h(of)g(the)f(table\))i(are)
+f(64-bit)227 1486 y(in)m(tegers)c(rather)e(than)g(32-bit)i(in)m
+(tegers.)382 1739 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 1852 y(status\))382 1965 y(FTITABLL\(unit,rowlenll,n)o(row)o
+(sll,)o(tfie)o(lds)o(,tty)o(pe,t)o(bco)o(l,tf)o(orm,)o(tun)o(it,e)o
+(xtna)o(me,)f(>)716 2077 y(status\))0 2331 y Fh(10)46
+b Fi(Insert)25 b(a)h(new)f(binary)f(table)j(extension)f(immediately)g
+(follo)m(wing)h(the)f(CHDU.)g(An)m(y)g(follo)m(wing)g(extensions)227
+2443 y(will)39 b(b)s(e)f(shifted)g(do)m(wn)g(to)h(mak)m(e)g(ro)s(om)g
+(for)f(the)g(new)g(extension.)66 b(If)38 b(there)h(are)f(no)h(other)f
+(follo)m(wing)227 2556 y(extensions)f(then)g(the)f(new)g(bin)m(table)h
+(extension)h(will)f(simply)f(b)s(e)g(app)s(ended)e(to)k(the)e(end)g(of)
+h(the)g(\014le.)227 2669 y(The)23 b(new)g(extension)h(will)f(b)s(ecome)
+h(the)f(CHDU.)h(The)f(FTIBINLL)g(routine)g(is)g(iden)m(tical)i(to)f
+(the)g(FTIBIN)227 2782 y(routine)30 b(except)i(that)e(the)h(2nd)e
+(parameter)i(\(that)g(giv)m(es)g(the)g(length)f(of)h(the)f(table\))h
+(is)g(a)f(64-bit)i(in)m(teger)227 2895 y(rather)f(than)f(a)g(32-bit)i
+(in)m(teger.)382 3148 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\))382 3261 y(FTIBINLL\(unit,nrowsll,tf)o(iel)o(ds,t)o
+(type)o(,tf)o(orm,)o(tuni)o(t,e)o(xtna)o(me,v)o(ari)o(dat)41
+b(>)48 b(status\))0 3627 y Fh(11)e Fi(Resize)26 b(an)e(image)i(b)m(y)e
+(mo)s(di\014ng)f(the)i(size,)i(dimensions,)e(and/or)f(datat)m(yp)s(e)h
+(of)g(the)g(curren)m(t)f(primary)f(arra)m(y)227 3740
+y(or)29 b(image)i(extension.)40 b(If)29 b(the)g(new)g(image,)i(as)e(sp)
+s(eci\014ed)f(b)m(y)h(the)g(input)f(argumen)m(ts,)i(is)f(larger)h(than)
+f(the)227 3853 y(curren)m(t)34 b(existing)h(image)g(in)f(the)g(FITS)f
+(\014le)h(then)f(zero)i(\014ll)f(data)h(will)f(b)s(e)f(inserted)h(at)g
+(the)g(end)g(of)g(the)227 3966 y(curren)m(t)25 b(image)h(and)e(an)m(y)i
+(follo)m(wing)g(extensions)g(will)f(b)s(e)f(mo)m(v)m(ed)i(further)e
+(bac)m(k)h(in)g(the)g(\014le.)39 b(Similarly)-8 b(,)27
+b(if)227 4079 y(the)h(new)e(image)j(is)e(smaller)h(than)f(the)g(curren)
+m(t)g(image)h(then)f(an)m(y)h(follo)m(wing)h(extensions)e(will)h(b)s(e)
+e(shifted)227 4192 y(up)32 b(to)m(w)m(ards)i(the)g(b)s(eginning)e(of)h
+(the)h(FITS)e(\014le)h(and)g(the)g(image)h(data)g(will)g(b)s(e)e
+(truncated)h(to)h(the)f(new)227 4304 y(size.)41 b(This)25
+b(routine)h(rewrites)h(the)f(BITPIX,)h(NAXIS,)f(and)g(NAXISn)g(k)m(eyw)
+m(ords)g(with)g(the)h(appropriate)227 4417 y(v)-5 b(alues)37
+b(for)f(new)h(image.)60 b(The)36 b(FTRSIMLL)g(routine)g(is)h(iden)m
+(tical)h(to)g(the)e(FTRSIM)g(routine)h(except)227 4530
+y(that)30 b(the)g(4th)g(parameter)g(\(the)g(length)g(of)f(eac)m(h)i
+(axis\))f(is)g(an)f(arra)m(y)h(of)g(64-bit)h(in)m(tegers)f(rather)g
+(than)f(an)227 4643 y(arra)m(y)i(of)g(32-bit)g(in)m(tegers.)382
+4896 y Fe(FTRSIM\(unit,bitpix,naxis)o(,na)o(xes,)o(stat)o(us\))382
+5009 y(FTRSIMLL\(unit,bitpix,nax)o(is,)o(naxe)o(sll,)o(sta)o(tus\))0
+5262 y Fh(12)46 b Fi(Delete)34 b(the)f(CHDU)g(in)f(the)g(FITS)f
+(\014le.)47 b(An)m(y)32 b(follo)m(wing)i(HDUs)f(will)g(b)s(e)e(shifted)
+h(forw)m(ard)g(in)g(the)g(\014le,)h(to)227 5375 y(\014ll)38
+b(in)f(the)g(gap)h(created)g(b)m(y)g(the)f(deleted)h(HDU.)h(In)d(the)i
+(case)g(of)g(deleting)g(the)g(primary)e(arra)m(y)i(\(the)227
+5488 y(\014rst)30 b(HDU)h(in)f(the)h(\014le\))g(then)f(the)h(curren)m
+(t)f(primary)f(arra)m(y)i(will)g(b)s(e)f(replace)h(b)m(y)g(a)g(n)m(ull)
+f(primary)f(arra)m(y)227 5601 y(con)m(taining)k(the)f(minim)m(um)e(set)
+i(of)g(required)e(k)m(eyw)m(ords)i(and)e(no)i(data.)44
+b(If)31 b(there)g(are)h(more)f(extensions)227 5714 y(in)f(the)g(\014le)
+g(follo)m(wing)i(the)e(one)g(that)h(is)f(deleted,)h(then)f(the)g(the)g
+(CHDU)h(will)f(b)s(e)g(rede\014ned)e(to)j(p)s(oin)m(t)f(to)p
+eop end
+%%Page: 41 47
+TeXDict begin 41 46 bop 0 299 a Fg(6.3.)72 b(DEFINE)31
+b(OR)f(REDEFINE)h(THE)f(STR)m(UCTURE)f(OF)h(THE)g(CHDU)1042
+b Fi(41)227 555 y(the)27 b(follo)m(wing)h(extension.)41
+b(If)26 b(there)h(are)g(no)g(follo)m(wing)h(extensions)f(then)g(the)g
+(CHDU)g(will)g(b)s(e)f(rede\014ned)227 668 y(to)35 b(p)s(oin)m(t)f(to)h
+(the)f(previous)f(HDU.)i(The)e(output)h(HDUTYPE)g(parameter)h
+(indicates)f(the)h(t)m(yp)s(e)f(of)g(the)227 781 y(new)c(CHDU)h(after)g
+(the)f(previous)g(CHDU)h(has)f(b)s(een)g(deleted.)382
+1001 y Fe(FTDHDU\(unit,)44 b(>)k(hdutype,status\))0 1222
+y Fh(13)e Fi(Cop)m(y)36 b(all)h(or)f(part)g(of)g(the)g(input)f(FITS)g
+(\014le)h(and)g(app)s(end)e(it)i(to)h(the)f(end)g(of)g(the)g(output)g
+(FITS)f(\014le.)57 b(If)227 1335 y('previous')39 b(\(an)g(in)m(teger)h
+(parameter\))g(is)f(not)g(equal)g(to)h(0,)h(then)e(an)m(y)g(HDUs)g
+(preceding)g(the)g(curren)m(t)227 1448 y(HDU)f(in)e(the)h(input)e
+(\014le)i(will)g(b)s(e)f(copied)h(to)g(the)g(output)f(\014le.)60
+b(Similarly)-8 b(,)39 b('curren)m(t')e(and)f('follo)m(wing')227
+1561 y(determine)j(whether)f(the)h(curren)m(t)g(HDU,)h(and/or)e(an)m(y)
+i(follo)m(wing)g(HDUs)f(in)g(the)g(input)f(\014le)g(will)i(b)s(e)227
+1674 y(copied)32 b(to)g(the)g(output)f(\014le.)43 b(If)31
+b(all)h(3)g(parameters)g(are)g(not)f(equal)h(to)g(zero,)h(then)e(the)g
+(en)m(tire)h(input)f(\014le)227 1786 y(will)g(b)s(e)e(copied.)41
+b(On)30 b(return,)f(the)h(curren)m(t)g(HDU)h(in)f(the)g(input)f(\014le)
+h(will)h(b)s(e)e(unc)m(hanged,)h(and)g(the)g(last)227
+1899 y(copied)h(HDU)g(will)g(b)s(e)f(the)g(curren)m(t)g(HDU)i(in)e(the)
+g(output)g(\014le.)382 2120 y Fe(FTCPFL\(iunit,)44 b(ounit,)i
+(previous,)f(current,)h(following,)f(>)i(status\))0 2340
+y Fh(14)f Fi(Cop)m(y)35 b(the)f(en)m(tire)i(CHDU)f(from)f(the)g(FITS)g
+(\014le)h(asso)s(ciated)h(with)e(IUNIT)g(to)i(the)e(CHDU)h(of)g(the)g
+(FITS)227 2453 y(\014le)g(asso)s(ciated)h(with)e(OUNIT.)g(The)g(output)
+g(HDU)h(m)m(ust)f(b)s(e)g(empt)m(y)h(and)e(not)i(already)g(con)m(tain)h
+(an)m(y)227 2566 y(k)m(eyw)m(ords.)41 b(Space)29 b(will)g(b)s(e)g
+(reserv)m(ed)g(for)g(MOREKEYS)f(additional)h(k)m(eyw)m(ords)h(in)e(the)
+i(output)e(header)227 2679 y(if)j(there)f(is)h(not)f(already)h(enough)f
+(space.)382 2899 y Fe(FTCOPY\(iunit,ounit,morek)o(eys)o(,)42
+b(>)47 b(status\))0 3120 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)g(with)
+f(in)m(unit)g(to)h(the)f(CHDU)h(asso-)227 3233 y(ciated)f(with)e
+(outunit.)39 b(If)25 b(the)g(curren)m(t)h(output)f(HDU)h(is)f(not)h
+(completely)h(empt)m(y)-8 b(,)27 b(then)e(the)h(CHDU)g(will)227
+3346 y(b)s(e)e(closed)i(and)e(a)i(new)e(HDU)h(will)h(b)s(e)e(app)s
+(ended)f(to)j(the)f(output)f(\014le.)39 b(This)24 b(routine)h(will)g
+(automatically)227 3459 y(transform)31 b(the)g(necessary)h(k)m(eyw)m
+(ords)f(when)g(cop)m(ying)h(a)f(primary)g(arra)m(y)h(to)f(and)g(image)i
+(extension,)f(or)227 3572 y(an)27 b(image)h(extension)f(to)g(a)h
+(primary)d(arra)m(y)-8 b(.)41 b(An)26 b(empt)m(y)h(output)f(data)i
+(unit)e(will)h(b)s(e)f(created)i(\(all)g(v)-5 b(alues)227
+3684 y(=)30 b(0\).)382 3905 y Fe(FTCPHD\(inunit,)44 b(outunit,)h(>)j
+(status\))0 4125 y Fh(16)e Fi(Cop)m(y)d(just)g(the)g(data)h(from)f(the)
+g(CHDU)h(asso)s(ciated)g(with)f(IUNIT)g(to)h(the)f(CHDU)h(asso)s
+(ciated)g(with)227 4238 y(OUNIT.)26 b(This)f(will)h(o)m(v)m(erwrite)h
+(an)m(y)f(data)g(previously)g(in)f(the)h(OUNIT)f(CHDU.)h(This)f(lo)m(w)
+i(lev)m(el)g(routine)227 4351 y(is)g(used)e(b)m(y)i(FTCOPY,)f(but)g(it)
+g(ma)m(y)i(also)f(b)s(e)f(useful)f(in)i(certain)g(application)h
+(programs)e(whic)m(h)g(w)m(an)m(t)h(to)227 4464 y(cop)m(y)j(the)f(data)
+h(from)f(one)g(FITS)f(\014le)h(to)h(another)f(but)g(also)h(w)m(an)m(t)g
+(to)g(mo)s(dify)e(the)h(header)g(k)m(eyw)m(ords)g(in)227
+4577 y(the)j(pro)s(cess.)44 b(all)33 b(the)f(required)f(header)g(k)m
+(eyw)m(ords)h(m)m(ust)g(b)s(e)f(written)h(to)g(the)g(OUNIT)f(CHDU)h(b)s
+(efore)227 4690 y(calling)g(this)e(routine)382 4910 y
+Fe(FTCPDT\(iunit,ounit,)42 b(>)48 b(status\))0 5238 y
+Fd(6.3)135 b(De\014ne)45 b(or)g(Rede\014ne)h(the)f(structure)g(of)g
+(the)g(CHDU)0 5488 y Fi(It)32 b(should)f(rarely)h(b)s(e)g(necessary)g
+(to)h(call)g(the)f(subroutines)f(in)g(this)h(section.)47
+b(FITSIO)30 b(in)m(ternally)j(calls)g(these)0 5601 y(routines)h(whenev)
+m(er)g(necessary)-8 b(,)36 b(so)e(an)m(y)g(calls)h(to)g(these)f
+(routines)g(b)m(y)g(application)h(programs)f(will)g(lik)m(ely)i(b)s(e)0
+5714 y(redundan)m(t.)p eop end
+%%Page: 42 48
+TeXDict begin 42 47 bop 0 299 a Fi(42)1319 b Fg(CHAPTER)29
+b(6.)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(1)81 b Fi(This)36 b(routine)h(forces)h
+(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 668 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)f(can)h(initialize)227
+781 y(the)36 b(in)m(ternal)g(bu\013ers)e(that)i(describ)s(e)f(the)h
+(HDU)g(structure.)55 b(This)35 b(routine)h(ma)m(y)g(b)s(e)e(used)h
+(instead)h(of)227 894 y(the)j(more)g(complicated)i(calls)f(to)f(ftp)s
+(def,)h(ftadef)f(or)g(ftb)s(def.)65 b(This)38 b(routine)h(is)g(also)h
+(v)m(ery)f(useful)f(for)227 1007 y(reinitializing)e(the)e(structure)g
+(of)g(an)f(HDU,)i(if)f(the)g(n)m(um)m(b)s(er)e(of)i(ro)m(ws)g(in)g(a)g
+(table,)i(as)e(sp)s(eci\014ed)f(b)m(y)h(the)227 1120
+y(NAXIS2)d(k)m(eyw)m(ord,)g(has)f(b)s(een)g(mo)s(di\014ed)f(from)h(its)
+h(initial)g(v)-5 b(alue.)382 1361 y Fe(FTRDEF\(unit,)44
+b(>)k(status\))141 b(\(DEPRECATED\))0 1602 y Fh(2)81
+b Fi(De\014ne)27 b(the)g(structure)g(of)g(the)g(primary)f(arra)m(y)i
+(or)f(IMA)m(GE)h(extension.)40 b(When)27 b(writing)g(GR)m(OUP)m(ed)h
+(FITS)227 1715 y(\014les)43 b(that)h(b)m(y)e(con)m(v)m(en)m(tion)k(set)
+d(the)g(NAXIS1)g(k)m(eyw)m(ord)h(equal)f(to)h(0,)i(ftp)s(def)c(m)m(ust)
+h(b)s(e)f(called)i(with)227 1828 y(naxes\(1\))27 b(=)e(1,)i(NOT)e(0,)i
+(otherwise)f(FITSIO)e(will)i(rep)s(ort)f(an)g(error)g(status=308)i
+(when)d(trying)i(to)g(write)227 1941 y(data)31 b(to)g(a)g(group.)40
+b(Note:)i(it)31 b(is)g(usually)f(simpler)g(to)h(call)h(FTRDEF)e(rather)
+h(than)f(this)g(routine.)382 2182 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 2424 y Fh(3)81 b Fi(De\014ne)32 b(the)h(structure)f
+(of)g(an)h(ASCI)s(I)e(table)i(\(T)-8 b(ABLE\))33 b(extension.)48
+b(Note:)e(it)33 b(is)f(usually)g(simpler)g(to)i(call)227
+2537 y(FTRDEF)d(rather)f(than)h(this)f(routine.)382 2778
+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 3019 y Fh(4)81 b
+Fi(De\014ne)35 b(the)h(structure)f(of)g(a)h(binary)f(table)h(\(BINT)-8
+b(ABLE\))37 b(extension.)56 b(Note:)d(it)36 b(is)f(usually)g(simpler)g
+(to)227 3132 y(call)d(FTRDEF)f(rather)f(than)g(this)g(routine.)382
+3373 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\))0 3615 y Fh(5)81 b
+Fi(De\014ne)34 b(the)g(size)h(of)f(the)g(Curren)m(t)f(Data)i(Unit,)h(o)
+m(v)m(erriding)e(the)g(length)h(of)f(the)g(data)h(unit)e(as)h
+(previously)227 3728 y(de\014ned)e(b)m(y)h(ftp)s(def,)g(ftadef,)i(or)e
+(ftb)s(def.)48 b(This)33 b(is)g(useful)f(if)i(one)f(do)s(es)g(not)h
+(kno)m(w)f(the)g(total)i(size)f(of)g(the)227 3841 y(data)f(unit)f(un)m
+(til)h(after)f(the)h(data)g(ha)m(v)m(e)g(b)s(een)f(written.)46
+b(The)32 b(size)h(\(in)f(b)m(ytes\))h(of)g(an)f(ASCI)s(I)f(or)h(Binary)
+227 3954 y(table)27 b(is)f(giv)m(en)g(b)m(y)g(NAXIS1)g(*)g(NAXIS2.)40
+b(\(Note)27 b(that)f(to)h(determine)f(the)f(v)-5 b(alue)27
+b(of)f(NAXIS1)f(it)i(is)f(often)227 4066 y(more)32 b(con)m(v)m(enien)m
+(t)h(to)f(read)f(the)g(v)-5 b(alue)32 b(of)f(the)h(NAXIS1)f(k)m(eyw)m
+(ord)h(from)e(the)i(output)e(\014le,)i(rather)f(than)227
+4179 y(computing)f(the)g(ro)m(w)g(length)h(directly)f(from)f(all)i(the)
+f(TF)m(ORM)h(k)m(eyw)m(ord)f(v)-5 b(alues\).)41 b(Note:)h(it)30
+b(is)g(usually)227 4292 y(simpler)g(to)h(call)h(FTRDEF)f(rather)f(than)
+g(this)g(routine.)382 4534 y Fe(FTDDEF\(unit,bytlen,)42
+b(>)48 b(status\))e(\(DEPRECATED\))0 4775 y Fh(6)81 b
+Fi(De\014ne)22 b(the)g(zero)i(indexed)d(b)m(yte)i(o\013set)g(of)g(the)f
+('heap')h(measured)e(from)h(the)h(start)g(of)f(the)g(binary)g(table)h
+(data.)227 4888 y(By)30 b(default)g(the)f(heap)h(is)f(assumed)g(to)h
+(start)g(immediately)h(follo)m(wing)g(the)f(regular)f(table)i(data,)f
+(i.e.,)h(at)227 5001 y(lo)s(cation)38 b(NAXIS1)f(x)g(NAXIS2.)59
+b(This)36 b(routine)g(is)h(only)f(relev)-5 b(an)m(t)38
+b(for)e(binary)g(tables)h(whic)m(h)g(con)m(tain)227 5114
+y(v)-5 b(ariable)36 b(length)g(arra)m(y)f(columns)g(\(with)h(TF)m(ORMn)
+f(=)f('Pt'\).)57 b(This)34 b(subroutine)g(also)i(automatically)227
+5227 y(writes)23 b(the)g(v)-5 b(alue)23 b(of)g(theap)g(to)h(a)f(k)m
+(eyw)m(ord)g(in)g(the)g(extension)g(header.)38 b(This)22
+b(subroutine)g(m)m(ust)h(b)s(e)f(called)227 5339 y(after)27
+b(the)f(required)f(k)m(eyw)m(ords)i(ha)m(v)m(e)g(b)s(een)e(written)h
+(\(with)g(ftph)m(bn\))f(and)h(after)g(the)h(table)g(structure)e(has)227
+5452 y(b)s(een)30 b(de\014ned)f(\(with)h(ftb)s(def)7
+b(\))30 b(but)g(b)s(efore)g(an)m(y)g(data)h(is)g(written)f(to)h(the)g
+(table.)382 5694 y Fe(FTPTHP\(unit,theap,)43 b(>)k(status\))p
+eop end
+%%Page: 43 49
+TeXDict begin 43 48 bop 0 299 a Fg(6.4.)72 b(FITS)30
+b(HEADER)h(I/O)f(SUBR)m(OUTINES)2086 b Fi(43)0 555 y
+Fd(6.4)135 b(FITS)44 b(Header)i(I/O)f(Subroutines)0 809
+y Fb(6.4.1)112 b(Header)38 b(Space)h(and)f(P)m(osition)f(Routines)0
+1019 y Fh(1)81 b Fi(Reserv)m(e)37 b(space)g(in)f(the)h(CHU)f(for)h
+(MOREKEYS)e(more)i(header)f(k)m(eyw)m(ords.)59 b(This)36
+b(subroutine)f(ma)m(y)j(b)s(e)227 1132 y(called)e(to)g(reserv)m(e)g
+(space)f(for)g(k)m(eyw)m(ords)g(whic)m(h)g(are)g(to)h(b)s(e)e(written)h
+(at)g(a)h(later)g(time,)h(after)e(the)g(data)227 1245
+y(unit)h(or)g(subsequen)m(t)f(extensions)h(ha)m(v)m(e)h(b)s(een)e
+(written)h(to)h(the)f(FITS)f(\014le.)58 b(If)35 b(this)h(subroutine)f
+(is)h(not)227 1358 y(explicitly)29 b(called,)g(then)e(the)g(initial)i
+(size)e(of)h(the)f(FITS)f(header)h(will)h(b)s(e)e(limited)i(to)g(the)f
+(space)h(a)m(v)-5 b(ailable)227 1471 y(at)24 b(the)g(time)g(that)g(the)
+g(\014rst)f(data)h(is)g(written)f(to)h(the)g(asso)s(ciated)h(data)f
+(unit.)38 b(FITSIO)22 b(has)i(the)f(abilit)m(y)i(to)227
+1584 y(dynamically)g(add)e(more)h(space)h(to)g(the)f(header)g(if)g
+(needed,)h(ho)m(w)m(ev)m(er)g(it)g(is)f(more)g(e\016cien)m(t)h(to)g
+(preallo)s(cate)227 1697 y(the)31 b(required)e(space)i(if)g(the)f(size)
+h(is)g(kno)m(wn)f(in)g(adv)-5 b(ance.)382 1958 y Fe
+(FTHDEF\(unit,morekeys,)42 b(>)47 b(status\))0 2219 y
+Fh(2)81 b Fi(Return)23 b(the)i(n)m(um)m(b)s(er)e(of)h(existing)i(k)m
+(eyw)m(ords)e(in)h(the)f(CHU)g(\(NOT)h(including)f(the)g(END)h(k)m(eyw)
+m(ord)g(whic)m(h)f(is)227 2332 y(not)g(considered)f(a)g(real)h(k)m(eyw)
+m(ord\))g(and)f(the)g(remaining)h(space)f(a)m(v)-5 b(ailable)26
+b(to)e(write)f(additional)i(k)m(eyw)m(ords)227 2445 y(in)39
+b(the)h(CHU.)f(\(returns)f(KEYSADD)i(=)f(-1)h(if)f(the)g(header)g(has)g
+(not)h(y)m(et)g(b)s(een)e(closed\).)69 b(Note)40 b(that)227
+2558 y(FITSIO)23 b(will)i(attempt)g(to)g(dynamically)g(add)e(space)i
+(for)f(more)g(k)m(eyw)m(ords)h(if)f(required)f(when)g(app)s(ending)227
+2671 y(new)30 b(k)m(eyw)m(ords)h(to)g(a)g(header.)382
+2932 y Fe(FTGHSP\(iunit,)44 b(>)j(keysexist,keysadd,status\))0
+3194 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)f(the)g(header)g(and)g(the)g(curren)m(t)h(p)s(osition)f(in)g
+(the)g(header.)68 b(This)227 3307 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)g(b)s(e)f(read)g
+(next)h(\(or)g(one)g(greater)g(than)g(the)227 3420 y(p)s(osition)29
+b(of)f(the)h(last)g(k)m(eyw)m(ord)g(that)g(w)m(as)f(read)g(or)h
+(written\).)40 b(A)29 b(v)-5 b(alue)28 b(of)h(1)g(is)f(returned)f(if)h
+(the)h(p)s(oin)m(ter)227 3533 y(is)i(p)s(ositioned)f(at)h(the)g(b)s
+(eginning)e(of)i(the)g(header.)382 3794 y Fe(FTGHPS\(iunit,)44
+b(>)j(keysexist,key_no,status\))0 4086 y Fb(6.4.2)112
+b(Read)38 b(or)f(W)-9 b(rite)37 b(Standard)i(Header)e(Routines)0
+4306 y Fi(These)31 b(subroutines)e(pro)m(vide)i(a)g(simple)g(metho)s(d)
+f(of)h(reading)g(or)g(writing)g(most)g(of)g(the)g(k)m(eyw)m(ord)g(v)-5
+b(alues)31 b(that)0 4419 y(are)d(normally)g(required)f(in)h(a)g(FITS)f
+(\014les.)40 b(These)27 b(subroutines)g(are)h(pro)m(vided)f(for)h(con)m
+(v)m(enience)h(only)f(and)g(are)0 4532 y(not)36 b(required)e(to)i(b)s
+(e)f(used.)55 b(If)35 b(preferred,)h(users)e(ma)m(y)i(call)h(the)f(lo)m
+(w)m(er-lev)m(el)i(subroutines)c(describ)s(ed)h(in)g(the)0
+4644 y(previous)30 b(section)i(to)g(individually)f(read)f(or)h(write)g
+(the)g(required)f(k)m(eyw)m(ords.)43 b(Note)32 b(that)g(in)e(most)i
+(cases,)g(the)0 4757 y(required)26 b(k)m(eyw)m(ords)h(suc)m(h)g(as)g
+(NAXIS,)f(TFIELD,)h(TTYPEn,)g(etc,)i(whic)m(h)d(de\014ne)g(the)h
+(structure)f(of)h(the)g(HDU)0 4870 y(m)m(ust)j(b)s(e)g(written)g(to)i
+(the)e(header)g(b)s(efore)g(an)m(y)h(data)g(can)g(b)s(e)e(written)i(to)
+g(the)g(image)g(or)g(table.)0 5132 y Fh(1)81 b Fi(Put)37
+b(the)i(primary)e(header)h(or)g(IMA)m(GE)h(extension)f(k)m(eyw)m(ords)h
+(in)m(to)g(the)f(CHU.)g(There)g(are)g(2)h(a)m(v)-5 b(ailable)227
+5245 y(routines:)39 b(The)27 b(simpler)f(FTPHPS)h(routine)g(is)g(equiv)
+-5 b(alen)m(t)29 b(to)e(calling)i(ftphpr)c(with)i(the)g(default)h(v)-5
+b(alues)227 5357 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 5470 y(and)23 b(EXTEND)h(k)m(eyw)m(ords)g(are)h(not)f
+(required)f(in)g(the)h(primary)f(header)g(and)h(are)g(only)g(written)g
+(if)f(p)s(coun)m(t)227 5583 y(is)31 b(not)g(equal)h(to)g(zero,)g(gcoun)
+m(t)g(is)f(not)g(equal)g(to)h(zero)g(or)f(one,)g(and)g(if)g(extend)g
+(is)g(TR)m(UE,)g(resp)s(ectiv)m(ely)-8 b(.)227 5696 y(When)30
+b(writing)h(to)g(an)f(IMA)m(GE)i(extension,)f(the)f(SIMPLE)g(and)g
+(EXTEND)g(parameters)h(are)g(ignored.)p eop end
+%%Page: 44 50
+TeXDict begin 44 49 bop 0 299 a Fi(44)1319 b Fg(CHAPTER)29
+b(6.)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(FTPHPS\(unit,bitpix,naxis)o(,na)o(xes,)41
+b(>)48 b(status\))382 781 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 1082 y Fh(2)81 b Fi(Get)44 b(primary)e(header)h(or)
+h(IMA)m(GE)g(extension)g(k)m(eyw)m(ords)g(from)f(the)g(CHU.)h(When)f
+(reading)g(from)g(an)227 1195 y(IMA)m(GE)32 b(extension)f(the)f(SIMPLE)
+g(and)f(EXTEND)i(parameters)g(are)f(ignored.)382 1495
+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 1608 y(status\))0
+1909 y Fh(3)81 b Fi(Put)34 b(the)h(ASCI)s(I)f(table)i(header)f(k)m(eyw)
+m(ords)g(in)m(to)h(the)f(CHU.)h(The)e(optional)i(TUNITn)e(and)h
+(EXTNAME)227 2021 y(k)m(eyw)m(ords)c(are)g(written)f(only)h(if)f(the)h
+(input)e(string)h(v)-5 b(alues)31 b(are)g(not)f(blank.)382
+2322 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
+2435 y(status\))0 2736 y Fh(4)81 b Fi(Get)31 b(the)g(ASCI)s(I)d(table)k
+(header)e(k)m(eyw)m(ords)h(from)e(the)i(CHU)382 3036
+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 3149 y(extname,status\))0
+3450 y Fh(5)81 b Fi(Put)34 b(the)h(binary)f(table)i(header)e(k)m(eyw)m
+(ords)i(in)m(to)f(the)g(CHU.)g(The)g(optional)h(TUNITn)e(and)g(EXTNAME)
+227 3563 y(k)m(eyw)m(ords)i(are)g(written)f(only)g(if)h(the)f(input)f
+(string)i(v)-5 b(alues)35 b(are)h(not)f(blank.)55 b(The)35
+b(p)s(coun)m(t)g(parameter,)227 3675 y(whic)m(h)f(sp)s(eci\014es)g(the)
+h(size)g(of)g(the)f(v)-5 b(ariable)35 b(length)g(arra)m(y)g(heap,)g
+(should)f(initially)h(=)f(0;)j(FITSIO)d(will)227 3788
+y(automatically)27 b(up)s(date)c(the)h(PCOUNT)f(k)m(eyw)m(ord)h(v)-5
+b(alue)24 b(if)g(an)m(y)g(v)-5 b(ariable)25 b(length)f(arra)m(y)h(data)
+f(is)g(written)227 3901 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)30 b(for)g(v)-5
+b(ariable)30 b(length)g(v)m(ector)h(columns)e(should)g(ha)m(v)m(e)i
+(the)227 4014 y(form)c('Pt\(len\)')j(or)d('1Pt\(len\)')j(where)d(`t')h
+(is)g(the)g(data)g(t)m(yp)s(e)g(co)s(de)f(letter)i(\(A,I,J,E,D,)g
+(etc.\))42 b(and)27 b(`len')h(is)227 4127 y(an)g(in)m(teger)i(sp)s
+(ecifying)e(the)g(maxim)m(um)g(length)g(of)h(the)f(v)m(ectors)h(in)f
+(that)h(column)f(\(len)g(m)m(ust)g(b)s(e)g(greater)227
+4240 y(than)j(or)h(equal)f(to)i(the)e(longest)i(v)m(ector)f(in)f(the)h
+(column\).)44 b(If)30 b(`len')i(is)g(not)f(sp)s(eci\014ed)g(when)f(the)
+i(table)g(is)227 4353 y(created)27 b(\(e.g.,)i(the)d(input)f(TF)m(ORMn)
+h(v)-5 b(alue)26 b(is)g(just)f('1Pt'\))j(then)d(FITSIO)g(will)h(scan)g
+(the)g(column)g(when)227 4466 y(the)k(table)g(is)f(\014rst)g(closed)h
+(and)f(will)g(app)s(end)f(the)h(maxim)m(um)h(length)f(to)h(the)g(TF)m
+(ORM)f(k)m(eyw)m(ord)h(v)-5 b(alue.)227 4579 y(Note)28
+b(that)e(if)g(the)g(table)h(is)f(subsequen)m(tly)g(mo)s(di\014ed)f(to)i
+(increase)f(the)h(maxim)m(um)f(length)g(of)g(the)g(v)m(ectors)227
+4692 y(then)k(the)h(mo)s(difying)f(program)g(is)g(resp)s(onsible)g(for)
+g(also)h(up)s(dating)e(the)i(TF)m(ORM)g(k)m(eyw)m(ord)g(v)-5
+b(alue.)382 4992 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 5293 y Fh(6)81 b Fi(Get)31 b(the)g(binary)e(table)i
+(header)g(k)m(eyw)m(ords)f(from)g(the)h(CHU)382 5593
+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 5706 y(status\))p
+eop end
+%%Page: 45 51
+TeXDict begin 45 50 bop 0 299 a Fg(6.4.)72 b(FITS)30
+b(HEADER)h(I/O)f(SUBR)m(OUTINES)2086 b Fi(45)0 555 y
+Fb(6.4.3)112 b(W)-9 b(rite)37 b(Keyw)m(ord)g(Subroutines)0
+764 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)g(the)g(CHU.)382 1020 y Fe(FTPREC\(unit,card,)43
+b(>)k(status\))0 1276 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)h(the)g(CHU.)f(Multiple)h(COMMENT)f
+(k)m(eyw)m(ords)g(will)h(b)s(e)227 1389 y(written)31
+b(if)f(the)h(input)e(commen)m(t)i(string)g(is)f(longer)h(than)f(72)i(c)
+m(haracters.)382 1645 y Fe(FTPCOM\(unit,comment,)42 b(>)48
+b(status\))0 1901 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)h(the)f(CHU.)g(Multiple)h(HISTOR)-8
+b(Y)24 b(k)m(eyw)m(ords)h(will)h(b)s(e)e(written)227
+2014 y(if)31 b(the)f(input)g(history)g(string)g(is)h(longer)g(than)f
+(72)h(c)m(haracters.)382 2270 y Fe(FTPHIS\(unit,history,)42
+b(>)48 b(status\))0 2526 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)g(the)f(CHU.)h(The)f(k)m
+(eyw)m(ord)g(v)-5 b(alue)37 b(will)g(con)m(tain)h(the)e(curren)m(t)227
+2639 y(system)c(date)g(as)g(a)f(c)m(haracter)i(string)f(in)f
+('dd/mm/yy')g(format.)44 b(If)31 b(a)h(D)m(A)-8 b(TE)32
+b(k)m(eyw)m(ord)g(already)g(exists)227 2752 y(in)j(the)g(header,)i
+(then)d(this)h(subroutine)f(will)i(simply)e(up)s(date)h(the)g(k)m(eyw)m
+(ord)g(v)-5 b(alue)36 b(in-place)g(with)f(the)227 2865
+y(curren)m(t)30 b(date.)382 3121 y Fe(FTPDAT\(unit,)44
+b(>)k(status\))0 3377 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)h(datat)m(yp)s(e)g(in)m(to)h
+(the)e(CHU.)h(Note)h(that)f(FTPKYS)f(will)227 3490 y(only)33
+b(write)g(string)f(v)-5 b(alues)33 b(up)e(to)j(68)f(c)m(haracters)h(in)
+e(length;)i(longer)f(strings)g(will)f(b)s(e)g(truncated.)47
+b(The)227 3603 y(FTPKLS)27 b(routine)h(can)h(b)s(e)f(used)f(to)i(write)
+f(longer)h(strings,)g(using)e(a)i(non-standard)e(FITS)h(con)m(v)m(en)m
+(tion.)227 3716 y(The)23 b(E)h(and)f(D)h(v)m(ersions)g(of)g(this)f
+(routine)h(ha)m(v)m(e)h(the)f(added)f(feature)h(that)g(if)g(the)g
+('decimals')h(parameter)f(is)227 3829 y(negativ)m(e,)i(then)20
+b(the)i('G')g(displa)m(y)f(format)g(rather)g(then)g(the)g('E')h(format)
+f(will)h(b)s(e)e(used)g(when)g(constructing)227 3942
+y(the)25 b(k)m(eyw)m(ord)f(v)-5 b(alue,)26 b(taking)f(the)g(absolute)g
+(v)-5 b(alue)24 b(of)h('decimals')g(for)f(the)g(precision.)39
+b(This)23 b(will)i(suppress)227 4055 y(trailing)35 b(zeros,)h(and)d
+(will)i(use)e(a)i(\014xed)e(format)h(rather)g(than)f(an)h(exp)s(onen)m
+(tial)h(format,)h(dep)s(ending)c(on)227 4168 y(the)f(magnitude)f(of)h
+(the)f(v)-5 b(alue.)382 4424 y Fe(FTPKY[JKLS]\(unit,keyword)o(,ke)o
+(yval)o(,com)o(men)o(t,)42 b(>)47 b(status\))382 4537
+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 4793 y Fh(6)81 b Fi(Put)33
+b(\(app)s(end\))h(a)g(string)g(v)-5 b(alued)34 b(k)m(eyw)m(ord)h(in)m
+(to)g(the)g(CHU)f(whic)m(h)g(ma)m(y)g(b)s(e)g(longer)h(than)e(68)i(c)m
+(haracters)227 4906 y(in)j(length.)64 b(This)37 b(uses)h(the)g(Long)g
+(String)g(Keyw)m(ord)g(con)m(v)m(en)m(tion)i(that)e(is)g(describ)s(ed)f
+(in)h(the)g("Usage)227 5019 y(Guidelines)33 b(and)e(Suggestions")j
+(section)f(of)g(this)f(do)s(cumen)m(t.)46 b(Since)33
+b(this)f(uses)g(a)g(non-standard)g(FITS)227 5132 y(con)m(v)m(en)m(tion)
+38 b(to)d(enco)s(de)h(the)f(long)h(k)m(eyw)m(ord)f(string,)i(programs)d
+(whic)m(h)h(use)g(this)g(routine)g(should)f(also)227
+5245 y(call)e(the)e(FTPLSW)g(routine)h(to)g(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
+5357 y(that)36 b(this)f(con)m(v)m(en)m(tion)j(is)d(b)s(eing)g(used.)55
+b(FTPLSW)35 b(also)h(writes)g(a)f(k)m(eyw)m(ord)h(called)h(LONGSTRN)d
+(to)227 5470 y(record)c(the)h(v)m(ersion)f(of)h(the)f(longstring)h(con)
+m(v)m(en)m(tion)h(that)f(has)f(b)s(een)g(used,)f(in)h(case)h(a)g(new)f
+(con)m(v)m(en)m(tion)227 5583 y(is)f(adopted)g(at)g(some)g(p)s(oin)m(t)
+f(in)h(the)f(future.)40 b(If)28 b(the)g(LONGSTRN)g(k)m(eyw)m(ord)h(is)g
+(already)g(presen)m(t)f(in)h(the)227 5696 y(header,)i(then)f(FTPLSW)g
+(will)g(simply)g(return)g(and)f(will)i(not)g(write)f(duplicate)h(k)m
+(eyw)m(ords.)p eop end
+%%Page: 46 52
+TeXDict begin 46 51 bop 0 299 a Fi(46)1319 b Fg(CHAPTER)29
+b(6.)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(FTPKLS\(unit,keyword,keyv)o(al,)o(comm)o
+(ent,)41 b(>)47 b(status\))382 668 y(FTPLSW\(unit,)d(>)k(status\))0
+889 y Fh(7)81 b Fi(Put)30 b(\(app)s(end\))g(a)h(new)f(k)m(eyw)m(ord)h
+(with)f(an)h(unde\014ned,)e(or)h(n)m(ull,)h(v)-5 b(alue)31
+b(in)m(to)h(the)f(CHU.)g(The)f(v)-5 b(alue)31 b(string)227
+1002 y(of)g(the)f(k)m(eyw)m(ord)h(is)g(left)g(blank)f(in)g(this)g
+(case.)382 1223 y Fe(FTPKYU\(unit,keyword,comm)o(ent)o(,)42
+b(>)47 b(status\))0 1445 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)h(the)g
+(CHU.)f(One)f(ma)m(y)i(app)s(end)d(the)j(same)227 1558
+y(commen)m(t)37 b(to)g(ev)m(ery)g(k)m(eyw)m(ord)g(\(and)f(eliminate)h
+(the)g(need)f(to)h(ha)m(v)m(e)g(an)f(arra)m(y)h(of)f(iden)m(tical)i
+(commen)m(t)227 1670 y(strings,)g(one)e(for)g(eac)m(h)h(k)m(eyw)m
+(ord\))g(b)m(y)f(including)g(the)g(amp)s(ersand)e(c)m(haracter)k(as)e
+(the)h(last)g(non-blank)227 1783 y(c)m(haracter)g(in)e(the)h
+(\(\014rst\))f(COMMENTS)f(string)h(parameter.)56 b(This)35
+b(same)g(string)h(will)f(then)g(b)s(e)g(used)227 1896
+y(for)30 b(the)g(commen)m(t)h(\014eld)f(in)f(all)i(the)f(k)m(eyw)m
+(ords.)41 b(\(Note)32 b(that)e(the)g(SPP)f(v)m(ersion)i(of)f(these)g
+(routines)g(only)227 2009 y(supp)s(orts)f(a)i(single)g(commen)m(t)g
+(string\).)382 2230 y Fe(FTPKN[JKLS]\(unit,keyroot)o(,st)o(artn)o(o,no)
+o(_ke)o(ys,k)o(eyva)o(ls,)o(comm)o(ents)o(,)42 b(>)47
+b(status\))382 2343 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 2456 y(status\))0 2677 y Fh(9)81 b Fi(Cop)m(y)21
+b(an)h(indexed)f(k)m(eyw)m(ord)i(from)e(one)h(HDU)h(to)f(another,)i(mo)
+s(difying)e(the)g(index)f(n)m(um)m(b)s(er)f(of)i(the)g(k)m(eyw)m(ord)
+227 2790 y(name)37 b(in)f(the)g(pro)s(cess.)58 b(F)-8
+b(or)37 b(example,)i(this)d(routine)h(could)f(read)g(the)h(TLMIN3)f(k)m
+(eyw)m(ord)h(from)f(the)227 2903 y(input)28 b(HDU)h(\(b)m(y)f(giving)h
+(k)m(eyro)s(ot)h(=)d("TLMIN")i(and)f(inn)m(um)f(=)h(3\))h(and)f(write)g
+(it)h(to)g(the)f(output)g(HDU)227 3016 y(with)36 b(the)g(k)m(eyw)m(ord)
+h(name)f(TLMIN4)g(\(b)m(y)g(setting)i(outn)m(um)d(=)h(4\).)58
+b(If)36 b(the)g(input)f(k)m(eyw)m(ord)i(do)s(es)f(not)227
+3129 y(exist,)c(then)e(this)g(routine)g(simply)g(returns)f(without)i
+(indicating)g(an)f(error.)382 3350 y Fe(FTCPKY\(inunit,)44
+b(outunit,)h(innum,)h(outnum,)g(keyroot,)g(>)h(status\))0
+3571 y Fh(10)f Fi(Put)33 b(\(app)s(end\))f(a)h('triple)h(precision')g
+(k)m(eyw)m(ord)f(in)m(to)h(the)g(CHU)f(in)g(F28.16)i(format.)49
+b(The)33 b(\015oating)h(p)s(oin)m(t)227 3684 y(k)m(eyw)m(ord)c(v)-5
+b(alue)30 b(is)f(constructed)h(b)m(y)f(concatenating)j(the)d(input)g
+(in)m(teger)i(v)-5 b(alue)29 b(with)g(the)h(input)e(double)227
+3797 y(precision)22 b(fraction)h(v)-5 b(alue)23 b(\(whic)m(h)f(m)m(ust)
+g(ha)m(v)m(e)h(a)f(v)-5 b(alue)23 b(b)s(et)m(w)m(een)g(0.0)g(and)e
+(1.0\).)40 b(The)21 b(FTGKYT)h(routine)227 3910 y(should)35
+b(b)s(e)h(used)f(to)i(read)f(this)f(k)m(eyw)m(ord)i(v)-5
+b(alue,)38 b(b)s(ecause)e(the)g(other)h(k)m(eyw)m(ord)f(reading)g
+(subroutines)227 4023 y(will)31 b(not)g(preserv)m(e)f(the)h(full)f
+(precision)g(of)h(the)f(v)-5 b(alue.)382 4244 y Fe
+(FTPKYT\(unit,keyword,intv)o(al,)o(dblv)o(al,c)o(omm)o(ent,)41
+b(>)48 b(status\))0 4466 y Fh(11)e Fi(W)-8 b(rite)36
+b(k)m(eyw)m(ords)g(to)f(the)h(CHDU)f(that)h(are)f(de\014ned)f(in)g(an)h
+(ASCI)s(I)f(template)i(\014le.)55 b(The)34 b(format)i(of)f(the)227
+4578 y(template)d(\014le)f(is)f(describ)s(ed)f(under)g(the)i(ftgthd)f
+(routine)g(b)s(elo)m(w.)382 4800 y Fe(FTPKTP\(unit,)44
+b(filename,)i(>)h(status\))0 5021 y Fh(12)f Fi(App)s(end)28
+b(the)i(ph)m(ysical)g(units)g(string)g(to)g(an)g(existing)h(k)m(eyw)m
+(ord.)41 b(This)29 b(routine)h(uses)f(a)h(lo)s(cal)i(con)m(v)m(en)m
+(tion,)227 5134 y(sho)m(wn)g(in)g(the)h(follo)m(wing)h(example,)g(in)e
+(whic)m(h)g(the)h(k)m(eyw)m(ord)g(units)f(are)h(enclosed)g(in)f(square)
+g(brac)m(k)m(ets)227 5247 y(in)e(the)h(b)s(eginning)f(of)g(the)h(k)m
+(eyw)m(ord)g(commen)m(t)g(\014eld.)239 5468 y Fe(VELOCITY=)809
+b(12.3)46 b(/)i([km/s])e(orbital)g(speed)382 5694 y
+(FTPUNT\(unit,keyword,unit)o(s,)41 b(>)48 b(status\))p
+eop end
+%%Page: 47 53
+TeXDict begin 47 52 bop 0 299 a Fg(6.4.)72 b(FITS)30
+b(HEADER)h(I/O)f(SUBR)m(OUTINES)2086 b Fi(47)0 555 y
+Fb(6.4.4)112 b(Insert)38 b(Keyw)m(ord)f(Subroutines)0
+762 y Fh(1)81 b Fi(Insert)26 b(a)h(new)f(k)m(eyw)m(ord)h(record)g(in)m
+(to)g(the)g(CHU)g(at)g(the)g(sp)s(eci\014ed)f(p)s(osition)h(\(i.e.,)i
+(immediately)f(preceding)227 875 y(the)34 b(\(k)m(eyno\)th)g(k)m(eyw)m
+(ord)g(in)f(the)h(header.\))49 b(This)33 b('insert)g(record')h
+(subroutine)e(is)h(somewhat)h(less)g(e\016-)227 988 y(cien)m(t)28
+b(then)f(the)g('app)s(end)e(record')i(subroutine)f(\(FTPREC\))g
+(describ)s(ed)g(ab)s(o)m(v)m(e)i(b)s(ecause)f(the)g(remaining)227
+1101 y(k)m(eyw)m(ords)k(in)f(the)h(header)f(ha)m(v)m(e)h(to)g(b)s(e)f
+(shifted)g(do)m(wn)g(one)h(slot.)382 1349 y Fe
+(FTIREC\(unit,key_no,card,)41 b(>)47 b(status\))0 1598
+y Fh(2)81 b Fi(Insert)36 b(a)h(new)f(k)m(eyw)m(ord)i(in)m(to)g(the)f
+(CHU.)g(The)f(new)g(k)m(eyw)m(ord)i(is)f(inserted)f(immediately)i
+(follo)m(wing)h(the)227 1711 y(last)27 b(k)m(eyw)m(ord)g(that)f(has)g
+(b)s(een)g(read)g(from)f(the)h(header.)40 b(The)25 b(FTIKLS)g
+(subroutine)g(w)m(orks)h(the)g(same)h(as)227 1824 y(the)h(FTIKYS)e
+(subroutine,)h(except)i(it)f(also)g(supp)s(orts)e(long)i(string)f(v)-5
+b(alues)28 b(greater)g(than)f(68)h(c)m(haracters)227
+1937 y(in)36 b(length.)59 b(These)36 b('insert)g(k)m(eyw)m(ord')h
+(subroutines)e(are)i(somewhat)g(less)f(e\016cien)m(t)i(then)e(the)g
+('app)s(end)227 2049 y(k)m(eyw)m(ord')30 b(subroutines)e(describ)s(ed)g
+(ab)s(o)m(v)m(e)i(b)s(ecause)f(the)g(remaining)h(k)m(eyw)m(ords)f(in)g
+(the)g(header)g(ha)m(v)m(e)h(to)227 2162 y(b)s(e)g(shifted)g(do)m(wn)g
+(one)h(slot.)382 2411 y Fe(FTIKEY\(unit,)44 b(card,)j(>)g(status\))382
+2524 y(FTIKY[JKLS]\(unit,keyword)o(,ke)o(yval)o(,com)o(men)o(t,)42
+b(>)47 b(status\))382 2637 y(FTIKLS\(unit,keyword,keyv)o(al,)o(comm)o
+(ent,)41 b(>)47 b(status\))382 2750 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
+2998 y Fh(3)81 b Fi(Insert)32 b(a)i(new)f(k)m(eyw)m(ord)h(with)f(an)h
+(unde\014ned,)e(or)h(n)m(ull,)h(v)-5 b(alue)34 b(in)m(to)h(the)e(CHU.)h
+(The)f(v)-5 b(alue)34 b(string)f(of)h(the)227 3111 y(k)m(eyw)m(ord)d
+(is)g(left)g(blank)f(in)g(this)g(case.)382 3359 y Fe
+(FTIKYU\(unit,keyword,comm)o(ent)o(,)42 b(>)47 b(status\))0
+3648 y Fb(6.4.5)112 b(Read)38 b(Keyw)m(ord)g(Subroutines)0
+3867 y Fi(These)29 b(routines)f(return)g(the)h(v)-5 b(alue)29
+b(of)g(the)g(sp)s(eci\014ed)f(k)m(eyw)m(ord\(s\).)41
+b(Wild)30 b(card)e(c)m(haracters)i(\(*,)h(?,)e(or)g(#\))f(ma)m(y)0
+3980 y(b)s(e)f(used)h(when)f(sp)s(ecifying)h(the)g(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)28 b(matc)m(h)h(an)m(y)g(single)f(c)m(haracter)0
+4093 y(at)38 b(that)g(p)s(osition)f(in)g(the)h(k)m(eyw)m(ord)g(name)f
+(and)g(a)g('*')i(will)e(matc)m(h)h(an)m(y)g(length)g(\(including)f
+(zero\))h(string)g(of)0 4206 y(c)m(haracters.)65 b(The)37
+b('#')h(c)m(haracter)h(will)f(matc)m(h)h(an)m(y)f(consecutiv)m(e)i
+(string)e(of)g(decimal)h(digits)f(\(0)h(-)f(9\).)64 b(Note)0
+4319 y(that)30 b(when)f(a)g(wild)g(card)h(is)f(used)g(in)g(the)h(input)
+e(k)m(eyw)m(ord)i(name,)g(the)g(routine)f(will)h(only)g(searc)m(h)g
+(for)f(a)h(matc)m(h)0 4432 y(from)h(the)h(curren)m(t)g(header)g(p)s
+(osition)g(to)g(the)h(end)e(of)h(the)g(header.)45 b(It)32
+b(will)g(not)g(resume)g(the)g(searc)m(h)g(from)g(the)0
+4545 y(top)i(of)h(the)f(header)g(bac)m(k)h(to)g(the)f(original)h
+(header)f(p)s(osition)g(as)h(is)f(done)g(when)f(no)h(wildcards)f(are)i
+(included)0 4657 y(in)f(the)g(k)m(eyw)m(ord)h(name.)52
+b(If)33 b(the)h(desired)g(k)m(eyw)m(ord)h(string)f(is)g(8-c)m
+(haracters)i(long)f(\(the)f(maxim)m(um)g(length)h(of)0
+4770 y(a)h(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)g(c)m(haracter)h(of)f(the)f(input)g
+(name)h(to)g(force)0 4883 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)f(searc)m(h)g(for)g(the)g(next)0 4996 y(COMMENT)37
+b(k)m(eyw)m(ord\).)64 b(The)37 b(\013grec)i(routine)f(ma)m(y)g(b)s(e)f
+(used)g(to)i(set)f(the)g(starting)g(p)s(osition)g(when)f(doing)0
+5109 y(wild)30 b(card)g(searc)m(hes.)0 5357 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)e(the)h(header)g(is)g
+(at)227 5470 y(k)m(ey)p 365 5470 28 4 v 34 w(no)42 b(=)f(1;)49
+b(if)42 b(k)m(ey)p 996 5470 V 34 w(no)g(=)f(0)i(then)e(this)h
+(subroutine)f(simple)h(mo)m(v)m(es)i(the)e(in)m(ternal)h(p)s(oin)m(ter)
+f(to)h(the)227 5583 y(b)s(eginning)35 b(of)h(the)g(header)f(so)h(that)g
+(subsequen)m(t)f(k)m(eyw)m(ord)h(op)s(erations)g(will)g(start)g(at)g
+(the)g(top)g(of)g(the)227 5696 y(header;)31 b(it)g(also)g(returns)e(a)i
+(blank)f(card)g(v)-5 b(alue)31 b(in)f(this)g(case.)p
+eop end
+%%Page: 48 54
+TeXDict begin 48 53 bop 0 299 a Fi(48)1319 b Fg(CHAPTER)29
+b(6.)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(FTGREC\(unit,key_no,)42
+b(>)48 b(card,status\))0 817 y Fh(2)81 b Fi(Get)31 b(the)g(name,)f(v)-5
+b(alue)31 b(\(as)g(a)g(string\),)g(and)f(commen)m(t)i(of)e(the)h(n)m
+(th)f(k)m(eyw)m(ord)h(in)f(CHU.)h(This)f(routine)g(also)227
+930 y(c)m(hec)m(ks)h(that)f(the)g(returned)e(k)m(eyw)m(ord)i(name)f
+(\(KEYW)m(ORD\))i(con)m(tains)g(only)e(legal)i(ASCI)s(I)d(c)m
+(haracters.)227 1043 y(Call)j(FTGREC)f(and)g(FTPSV)m(C)g(to)h(b)m
+(ypass)f(this)g(error)g(c)m(hec)m(k.)382 1305 y Fe
+(FTGKYN\(unit,key_no,)42 b(>)48 b(keyword,value,comment,st)o(atu)o(s\))
+0 1568 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 1830 y Fe
+(FTGCRD\(unit,keyword,)42 b(>)48 b(card,status\))0 2092
+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)g(in)g('inclist')i(but)d(do)s
+(es)h(not)g(matc)m(h)i(an)m(y)227 2205 y(of)32 b(the)f(strings)g(in)g
+('exclist'.)45 b(The)30 b(strings)h(in)g(inclist)h(and)f(exclist)h(ma)m
+(y)g(con)m(tain)h(wild)d(card)h(c)m(haracters)227 2318
+y(\(*,)38 b(?,)e(and)e(#\))i(as)f(describ)s(ed)f(at)i(the)f(b)s
+(eginning)f(of)i(this)f(section.)56 b(This)34 b(routine)h(searc)m(hes)h
+(from)f(the)227 2431 y(curren)m(t)28 b(header)f(p)s(osition)h(to)g(the)
+g(end)f(of)h(the)g(header,)g(only)-8 b(,)29 b(and)e(do)s(es)g(not)h
+(con)m(tin)m(ue)h(the)f(searc)m(h)g(from)227 2544 y(the)41
+b(top)g(of)g(the)g(header)g(bac)m(k)h(to)f(the)g(original)h(p)s
+(osition.)73 b(The)40 b(curren)m(t)h(header)f(p)s(osition)h(ma)m(y)h(b)
+s(e)227 2657 y(reset)33 b(with)e(the)h(ftgrec)h(routine.)44
+b(Note)33 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)g(to)h(b)s(e)227 2769 y(excluded.)41
+b(This)29 b(routine)i(returns)e(status)i(=)f(202)h(if)g(a)f(matc)m
+(hing)i(k)m(eyw)m(ord)f(is)f(not)h(found.)382 3032 y
+Fe(FTGNXK\(unit,inclist,ninc)o(,ex)o(clis)o(t,ne)o(xc,)41
+b(>)48 b(card,status\))0 3294 y Fh(5)81 b Fi(Get)30 b(the)g(literal)i
+(k)m(eyw)m(ord)e(v)-5 b(alue)30 b(as)g(a)g(c)m(haracter)i(string.)40
+b(Regardless)31 b(of)f(the)g(datat)m(yp)s(e)g(of)g(the)g(k)m(eyw)m
+(ord,)227 3407 y(this)37 b(routine)g(simply)g(returns)f(the)h(string)g
+(of)g(c)m(haracters)i(in)d(the)i(v)-5 b(alue)37 b(\014eld)g(of)g(the)g
+(k)m(eyw)m(ord)h(along)227 3520 y(with)30 b(the)h(commen)m(t)g
+(\014eld.)382 3782 y Fe(FTGKEY\(unit,keyword,)42 b(>)48
+b(value,comment,status\))0 4044 y Fh(6)81 b Fi(Get)31
+b(a)g(k)m(eyw)m(ord)g(v)-5 b(alue)30 b(\(with)h(the)f(appropriate)h
+(datat)m(yp)s(e\))g(and)f(commen)m(t)i(from)e(the)g(CHU)382
+4306 y Fe(FTGKY[EDJKLS]\(unit,keywo)o(rd,)41 b(>)48 b
+(keyval,comment,status\))0 4568 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.)38 b(These)24 b(routines)f(do)g(not)h(supp)s(ort)e(wild)h
+(card)g(c)m(haracters)227 4681 y(in)30 b(the)h(ro)s(ot)g(name.)382
+4943 y Fe(FTGKN[EDJKLS]\(unit,keyro)o(ot,)o(star)o(tno,)o(max)o(_key)o
+(s,)42 b(>)47 b(keyvals,nfound,status\))0 5206 y Fh(8)81
+b Fi(Get)27 b(the)f(v)-5 b(alue)26 b(of)h(a)f(\015oating)h(p)s(oin)m(t)
+f(k)m(eyw)m(ord,)i(returning)d(the)h(in)m(teger)h(and)f(fractional)h
+(parts)f(of)g(the)g(v)-5 b(alue)227 5319 y(in)32 b(separate)g
+(subroutine)f(argumen)m(ts.)45 b(This)31 b(subroutine)f(ma)m(y)j(b)s(e)
+e(used)g(to)h(read)g(an)m(y)g(k)m(eyw)m(ord)g(but)f(is)227
+5431 y(esp)s(ecially)h(useful)d(for)i(reading)f(the)h('triple)g
+(precision')f(k)m(eyw)m(ords)h(written)g(b)m(y)f(FTPKYT.)382
+5694 y Fe(FTGKYT\(unit,keyword,)42 b(>)48 b(intval,dblval,comment,s)o
+(tat)o(us\))p eop end
+%%Page: 49 55
+TeXDict begin 49 54 bop 0 299 a Fg(6.4.)72 b(FITS)30
+b(HEADER)h(I/O)f(SUBR)m(OUTINES)2086 b Fi(49)0 555 y
+Fh(9)81 b Fi(Get)24 b(the)g(ph)m(ysical)h(units)e(string)g(in)h(an)f
+(existing)i(k)m(eyw)m(ord.)39 b(This)23 b(routine)h(uses)f(a)h(lo)s
+(cal)h(con)m(v)m(en)m(tion,)j(sho)m(wn)227 668 y(in)33
+b(the)h(follo)m(wing)g(example,)h(in)e(whic)m(h)g(the)g(k)m(eyw)m(ord)h
+(units)f(are)g(enclosed)h(in)f(square)g(brac)m(k)m(ets)i(in)e(the)227
+781 y(b)s(eginning)h(of)h(the)g(k)m(eyw)m(ord)g(commen)m(t)h(\014eld.)
+53 b(A)35 b(blank)g(string)f(is)h(returned)f(if)g(no)h(units)f(are)h
+(de\014ned)227 894 y(for)30 b(the)h(k)m(eyw)m(ord.)191
+1132 y Fe(VELOCITY=)809 b(12.3)46 b(/)i([km/s])e(orbital)g(speed)382
+1358 y(FTGUNT\(unit,keyword,)c(>)48 b(units,status\))0
+1645 y Fb(6.4.6)112 b(Mo)s(dify)39 b(Keyw)m(ord)e(Subroutines)0
+1864 y Fi(Wild)32 b(card)f(c)m(haracters,)j(as)e(describ)s(ed)e(in)h
+(the)h(Read)g(Keyw)m(ord)f(section,)i(ab)s(o)m(v)m(e,)g(ma)m(y)g(b)s(e)
+d(used)h(when)g(sp)s(eci-)0 1977 y(fying)f(the)h(name)f(of)h(the)f(k)m
+(eyw)m(ord)h(to)g(b)s(e)f(mo)s(di\014ed.)0 2215 y Fh(1)81
+b Fi(Mo)s(dify)30 b(\(o)m(v)m(erwrite\))i(the)f(n)m(th)f(80-c)m
+(haracter)j(header)d(record)h(in)f(the)g(CHU)382 2453
+y Fe(FTMREC\(unit,key_no,card,)41 b(>)47 b(status\))0
+2692 y Fh(2)81 b Fi(Mo)s(dify)37 b(\(o)m(v)m(erwrite\))j(the)e(80-c)m
+(haracter)j(header)c(record)h(for)f(the)h(named)f(k)m(eyw)m(ord)h(in)g
+(the)g(CHU.)g(This)227 2805 y(can)31 b(b)s(e)f(used)f(to)i(o)m(v)m
+(erwrite)h(the)f(name)f(of)h(the)f(k)m(eyw)m(ord)h(as)g(w)m(ell)g(as)g
+(its)g(v)-5 b(alue)30 b(and)g(commen)m(t)i(\014elds.)382
+3043 y Fe(FTMCRD\(unit,keyword,card)o(,)42 b(>)47 b(status\))0
+3281 y Fh(3)81 b Fi(Mo)s(dify)33 b(\(o)m(v)m(erwrite\))k(the)d(name)g
+(of)h(an)f(existing)h(k)m(eyw)m(ord)f(in)g(the)h(CHU)f(preserving)f
+(the)i(curren)m(t)e(v)-5 b(alue)227 3394 y(and)30 b(commen)m(t)h
+(\014elds.)382 3632 y Fe(FTMNAM\(unit,oldkey,keywo)o(rd,)41
+b(>)48 b(status\))0 3870 y Fh(4)81 b Fi(Mo)s(dify)30
+b(\(o)m(v)m(erwrite\))i(the)f(commen)m(t)g(\014eld)f(of)h(an)f
+(existing)h(k)m(eyw)m(ord)g(in)f(the)h(CHU)382 4108 y
+Fe(FTMCOM\(unit,keyword,comm)o(ent)o(,)42 b(>)47 b(status\))0
+4347 y Fh(5)81 b Fi(Mo)s(dify)24 b(the)h(v)-5 b(alue)25
+b(and)f(commen)m(t)i(\014elds)e(of)h(an)f(existing)i(k)m(eyw)m(ord)f
+(in)f(the)h(CHU.)g(The)f(FTMKLS)g(subrou-)227 4459 y(tine)35
+b(w)m(orks)e(the)h(same)h(as)f(the)g(FTMKYS)f(subroutine,)h(except)h
+(it)g(also)f(supp)s(orts)e(long)j(string)f(v)-5 b(alues)227
+4572 y(greater)38 b(than)f(68)h(c)m(haracters)g(in)f(length.)60
+b(Optionally)-8 b(,)40 b(one)d(ma)m(y)h(mo)s(dify)e(only)h(the)g(v)-5
+b(alue)37 b(\014eld)g(and)227 4685 y(lea)m(v)m(e)32 b(the)d(commen)m(t)
+i(\014eld)e(unc)m(hanged)g(b)m(y)g(setting)h(the)g(input)e(COMMENT)h
+(parameter)h(equal)g(to)g(the)227 4798 y(amp)s(ersand)f(c)m(haracter)k
+(\(&\).)42 b(The)30 b(E)g(and)g(D)h(v)m(ersions)g(of)g(this)g(routine)f
+(ha)m(v)m(e)i(the)f(added)f(feature)h(that)227 4911 y(if)26
+b(the)h('decimals')g(parameter)g(is)f(negativ)m(e,)k(then)c(the)g('G')h
+(displa)m(y)f(format)h(rather)f(then)g(the)g('E')h(format)227
+5024 y(will)i(b)s(e)f(used)f(when)h(constructing)h(the)f(k)m(eyw)m(ord)
+h(v)-5 b(alue,)30 b(taking)f(the)g(absolute)g(v)-5 b(alue)29
+b(of)f('decimals')i(for)227 5137 y(the)37 b(precision.)60
+b(This)35 b(will)i(suppress)e(trailing)i(zeros,)i(and)d(will)h(use)g(a)
+g(\014xed)e(format)i(rather)g(than)f(an)227 5250 y(exp)s(onen)m(tial)c
+(format,)f(dep)s(ending)d(on)j(the)f(magnitude)h(of)f(the)h(v)-5
+b(alue.)382 5488 y Fe(FTMKY[JKLS]\(unit,keyword)o(,ke)o(yval)o(,com)o
+(men)o(t,)42 b(>)47 b(status\))382 5601 y(FTMKLS\(unit,keyword,keyv)o
+(al,)o(comm)o(ent,)41 b(>)47 b(status\))382 5714 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\))p eop end
+%%Page: 50 56
+TeXDict begin 50 55 bop 0 299 a Fi(50)1319 b Fg(CHAPTER)29
+b(6.)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(Mo)s(dify)22 b(the)g(v)-5
+b(alue)23 b(of)f(an)g(existing)i(k)m(eyw)m(ord)e(to)h(b)s(e)f
+(unde\014ned,)g(or)g(n)m(ull.)38 b(The)22 b(v)-5 b(alue)22
+b(string)h(of)f(the)g(k)m(eyw)m(ord)227 668 y(is)30 b(set)h(to)g
+(blank.)40 b(Optionally)-8 b(,)31 b(one)f(ma)m(y)h(lea)m(v)m(e)h(the)f
+(commen)m(t)g(\014eld)e(unc)m(hanged)h(b)m(y)g(setting)h(the)f(input)
+227 781 y(COMMENT)g(parameter)h(equal)g(to)g(the)g(amp)s(ersand)e(c)m
+(haracter)j(\(&\).)382 1034 y Fe(FTMKYU\(unit,keyword,comm)o(ent)o(,)42
+b(>)47 b(status\))0 1324 y Fb(6.4.7)112 b(Up)s(date)39
+b(Keyw)m(ord)e(Subroutines)0 1532 y Fh(1)81 b Fi(Up)s(date)36
+b(an)g(80-c)m(haracter)j(record)d(in)g(the)h(CHU.)f(If)g(the)g(sp)s
+(eci\014ed)g(k)m(eyw)m(ord)h(already)f(exists)h(then)f(that)227
+1645 y(header)j(record)f(will)h(b)s(e)f(replaced)i(with)e(the)h(input)f
+(CARD)g(string.)66 b(If)38 b(it)i(do)s(es)e(not)h(exist)g(then)g(the)
+227 1758 y(new)f(record)g(will)g(b)s(e)f(added)h(to)g(the)g(header.)64
+b(The)37 b(FTUKLS)g(subroutine)g(w)m(orks)h(the)g(same)h(as)f(the)227
+1870 y(FTUKYS)28 b(subroutine,)g(except)i(it)f(also)h(supp)s(orts)c
+(long)j(string)g(v)-5 b(alues)29 b(greater)h(than)e(68)h(c)m(haracters)
+h(in)227 1983 y(length.)382 2237 y Fe(FTUCRD\(unit,keyword,card)o(,)42
+b(>)47 b(status\))0 2490 y Fh(2)81 b Fi(Up)s(date)44
+b(the)i(v)-5 b(alue)45 b(and)g(commen)m(t)h(\014elds)e(of)h(a)h(k)m
+(eyw)m(ord)f(in)g(the)g(CHU.)h(The)e(sp)s(eci\014ed)g(k)m(eyw)m(ord)i
+(is)227 2603 y(mo)s(di\014ed)38 b(if)g(it)h(already)g(exists)g(\(b)m(y)
+g(calling)h(FTMKYx\))f(otherwise)f(a)h(new)f(k)m(eyw)m(ord)h(is)g
+(created)g(b)m(y)227 2716 y(calling)f(FTPKYx.)58 b(The)36
+b(E)g(and)f(D)i(v)m(ersions)f(of)h(this)f(routine)g(ha)m(v)m(e)h(the)g
+(added)e(feature)i(that)g(if)f(the)227 2828 y('decimals')c(parameter)g
+(is)f(negativ)m(e,)i(then)d(the)h('G')h(displa)m(y)f(format)g(rather)g
+(then)f(the)h('E')g(format)h(will)227 2941 y(b)s(e)41
+b(used)f(when)h(constructing)h(the)f(k)m(eyw)m(ord)h(v)-5
+b(alue,)45 b(taking)d(the)f(absolute)h(v)-5 b(alue)42
+b(of)g('decimals')g(for)227 3054 y(the)37 b(precision.)60
+b(This)35 b(will)i(suppress)e(trailing)i(zeros,)i(and)d(will)h(use)g(a)
+g(\014xed)e(format)i(rather)g(than)f(an)227 3167 y(exp)s(onen)m(tial)c
+(format,)f(dep)s(ending)d(on)j(the)f(magnitude)h(of)f(the)h(v)-5
+b(alue.)382 3420 y Fe(FTUKY[JKLS]\(unit,keyword)o(,ke)o(yval)o(,com)o
+(men)o(t,)42 b(>)47 b(status\))382 3533 y(FTUKLS\(unit,keyword,keyv)o
+(al,)o(comm)o(ent,)41 b(>)47 b(status\))382 3646 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 3899 y Fh(3)81 b Fi(Up)s(date)23
+b(the)g(v)-5 b(alue)24 b(of)g(an)f(existing)i(k)m(eyw)m(ord)f(to)g(b)s
+(e)f(unde\014ned,)f(or)i(n)m(ull,)h(or)e(insert)h(a)f(new)g
+(unde\014ned-v)-5 b(alue)227 4012 y(k)m(eyw)m(ord)30
+b(if)f(it)h(do)s(esn't)f(already)h(exist.)41 b(The)29
+b(v)-5 b(alue)30 b(string)f(of)g(the)h(k)m(eyw)m(ord)f(is)h(left)g
+(blank)f(in)f(this)i(case.)382 4265 y Fe(FTUKYU\(unit,keyword,comm)o
+(ent)o(,)42 b(>)47 b(status\))0 4555 y Fb(6.4.8)112 b(Delete)38
+b(Keyw)m(ord)f(Subroutines)0 4763 y Fh(1)81 b Fi(Delete)32
+b(an)e(existing)h(k)m(eyw)m(ord)g(record.)40 b(The)30
+b(space)h(previously)f(o)s(ccupied)g(b)m(y)g(the)g(k)m(eyw)m(ord)h(is)f
+(reclaimed)227 4876 y(b)m(y)c(mo)m(ving)h(all)g(the)f(follo)m(wing)i
+(header)e(records)g(up)f(one)h(ro)m(w)h(in)e(the)i(header.)39
+b(The)25 b(\014rst)h(routine)g(deletes)227 4989 y(a)34
+b(k)m(eyw)m(ord)f(at)h(a)g(sp)s(eci\014ed)e(p)s(osition)h(in)g(the)g
+(header)g(\(the)h(\014rst)e(k)m(eyw)m(ord)i(is)f(at)h(p)s(osition)f
+(1\),)i(whereas)227 5102 y(the)d(second)g(routine)g(deletes)h(a)f(sp)s
+(eci\014cally)g(named)f(k)m(eyw)m(ord.)46 b(Wild)32 b(card)f(c)m
+(haracters,)j(as)e(describ)s(ed)227 5215 y(in)f(the)g(Read)g(Keyw)m
+(ord)f(section,)i(ab)s(o)m(v)m(e,)g(ma)m(y)g(b)s(e)e(used)g(when)f(sp)s
+(ecifying)i(the)g(name)g(of)g(the)f(k)m(eyw)m(ord)227
+5328 y(to)h(b)s(e)f(deleted)h(\(b)s(e)f(careful!\).)382
+5581 y Fe(FTDREC\(unit,key_no,)42 b(>)48 b(status\))382
+5694 y(FTDKEY\(unit,keyword,)42 b(>)48 b(status\))p eop
+end
+%%Page: 51 57
+TeXDict begin 51 56 bop 0 299 a Fg(6.5.)72 b(D)m(A)-8
+b(T)g(A)32 b(SCALING)e(AND)h(UNDEFINED)h(PIXEL)e(P)-8
+b(ARAMETERS)1083 b Fi(51)0 555 y Fd(6.5)135 b(Data)46
+b(Scaling)g(and)e(Unde\014ned)h(Pixel)h(P)l(arameters)0
+805 y Fi(These)24 b(subroutines)f(de\014ne)h(or)h(mo)s(dify)e(the)i(in)
+m(ternal)g(parameters)g(used)f(b)m(y)g(FITSIO)g(to)h(either)g(scale)h
+(the)e(data)0 918 y(or)33 b(to)i(represen)m(t)e(unde\014ned)e(pixels.)
+50 b(Generally)35 b(FITSIO)d(will)i(scale)g(the)g(data)g(according)g
+(to)g(the)g(v)-5 b(alues)34 b(of)0 1031 y(the)e(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)f(ma)m(y)0 1144 y(b)s(e)h(used)h(to)h(o)m(v)
+m(erride)g(the)f(k)m(eyw)m(ord)h(v)-5 b(alues.)49 b(This)32
+b(ma)m(y)i(b)s(e)f(useful)f(when)g(one)i(w)m(an)m(ts)f(to)h(read)f(or)g
+(write)h(the)0 1257 y(ra)m(w)c(unscaled)f(v)-5 b(alues)29
+b(in)h(the)f(FITS)g(\014le.)40 b(Similarly)-8 b(,)31
+b(FITSIO)d(generally)j(uses)e(the)g(v)-5 b(alue)30 b(of)g(the)f(BLANK)h
+(or)0 1370 y(TNULLn)35 b(k)m(eyw)m(ord)h(to)g(signify)f(an)h
+(unde\014ned)d(pixel,)k(but)e(these)h(routines)g(ma)m(y)g(b)s(e)e(used)
+h(to)h(o)m(v)m(erride)h(this)0 1483 y(v)-5 b(alue.)41
+b(These)30 b(subroutines)f(do)i(not)f(create)i(or)f(mo)s(dify)e(the)i
+(corresp)s(onding)e(header)h(k)m(eyw)m(ord)h(v)-5 b(alues.)0
+1727 y Fh(1)81 b Fi(Reset)26 b(the)g(scaling)g(factors)g(in)f(the)h
+(primary)f(arra)m(y)h(or)f(image)i(extension;)h(do)s(es)d(not)g(c)m
+(hange)i(the)f(BSCALE)227 1840 y(and)i(BZER)m(O)g(k)m(eyw)m(ord)h(v)-5
+b(alues)28 b(and)g(only)g(a\013ects)i(the)e(automatic)j(scaling)e(p)s
+(erformed)e(when)g(the)h(data)227 1953 y(elemen)m(ts)f(are)f
+(written/read)g(to/from)g(the)g(FITS)f(\014le.)39 b(When)25
+b(reading)h(from)f(a)h(FITS)f(\014le)g(the)h(returned)227
+2066 y(data)i(v)-5 b(alue)28 b(=)f(\(the)h(v)-5 b(alue)28
+b(giv)m(en)h(in)e(the)g(FITS)g(arra)m(y\))h(*)g(BSCALE)f(+)g(BZER)m(O.)
+g(The)g(in)m(v)m(erse)i(form)m(ula)227 2179 y(is)34 b(used)f(when)g
+(writing)h(data)h(v)-5 b(alues)34 b(to)g(the)g(FITS)g(\014le.)51
+b(\(NOTE:)34 b(BSCALE)f(and)g(BZER)m(O)h(m)m(ust)g(b)s(e)227
+2292 y(declared)d(as)g(Double)g(Precision)g(v)-5 b(ariables\).)382
+2536 y Fe(FTPSCL\(unit,bscale,bzero)o(,)42 b(>)47 b(status\))0
+2780 y Fh(2)81 b Fi(Reset)39 b(the)f(scaling)i(parameters)e(for)h(a)f
+(table)h(column;)k(do)s(es)38 b(not)g(c)m(hange)i(the)e(TSCALn)f(or)h
+(TZER)m(On)227 2893 y(k)m(eyw)m(ord)29 b(v)-5 b(alues)29
+b(and)e(only)i(a\013ects)g(the)g(automatic)h(scaling)f(p)s(erformed)e
+(when)g(the)i(data)g(elemen)m(ts)h(are)227 3006 y(written/read)i
+(to/from)g(the)g(FITS)f(\014le.)44 b(When)31 b(reading)g(from)g(a)h
+(FITS)f(\014le)g(the)h(returned)e(data)i(v)-5 b(alue)227
+3119 y(=)40 b(\(the)h(v)-5 b(alue)40 b(giv)m(en)h(in)f(the)g(FITS)g
+(arra)m(y\))g(*)h(TSCAL)e(+)g(TZER)m(O.)h(The)f(in)m(v)m(erse)i(form)m
+(ula)g(is)f(used)227 3232 y(when)33 b(writing)h(data)h(v)-5
+b(alues)35 b(to)f(the)h(FITS)e(\014le.)52 b(\(NOTE:)34
+b(TSCAL)f(and)g(TZER)m(O)g(m)m(ust)h(b)s(e)f(declared)227
+3345 y(as)e(Double)g(Precision)g(v)-5 b(ariables\).)382
+3589 y Fe(FTTSCL\(unit,colnum,tscal)o(,tz)o(ero,)41 b(>)48
+b(status\))0 3833 y Fh(3)81 b Fi(De\014ne)36 b(the)g(in)m(teger)i(v)-5
+b(alue)36 b(to)h(b)s(e)e(used)h(to)h(signify)f(unde\014ned)e(pixels)i
+(in)g(the)g(primary)f(arra)m(y)i(or)f(image)227 3946
+y(extension.)59 b(This)35 b(is)h(only)g(used)g(if)g(BITPIX)g(=)f(8,)j
+(16,)h(32.)59 b(or)36 b(64)h(This)e(do)s(es)h(not)g(create)i(or)e(c)m
+(hange)227 4059 y(the)27 b(v)-5 b(alue)28 b(of)f(the)g(BLANK)g(k)m(eyw)
+m(ord)h(in)e(the)i(header.)39 b(FTPNULLL)27 b(is)g(iden)m(tical)h(to)g
+(FTPNUL)f(except)227 4172 y(that)k(the)g(blank)f(v)-5
+b(alue)31 b(is)f(a)h(64-bit)g(in)m(teger)h(instead)f(of)f(a)h(32-bit)h
+(in)m(teger.)382 4416 y Fe(FTPNUL\(unit,blank,)43 b(>)k(status\))382
+4529 y(FTPNULLL\(unit,blankll,)42 b(>)47 b(status\))0
+4774 y Fh(4)81 b Fi(De\014ne)36 b(the)g(string)g(to)g(b)s(e)f(used)g
+(to)i(signify)f(unde\014ned)e(pixels)i(in)f(a)h(column)g(in)g(an)f
+(ASCI)s(I)g(table.)58 b(This)227 4887 y(do)s(es)30 b(not)h(create)h(or)
+e(c)m(hange)i(the)e(v)-5 b(alue)31 b(of)g(the)f(TNULLn)g(k)m(eyw)m
+(ord.)382 5131 y Fe(FTSNUL\(unit,colnum,snull)41 b(>)47
+b(status\))0 5375 y Fh(5)81 b Fi(De\014ne)34 b(the)h(v)-5
+b(alue)34 b(to)h(b)s(e)f(used)g(to)h(signify)f(unde\014ned)e(pixels)j
+(in)f(an)g(in)m(teger)i(column)e(in)g(a)g(binary)g(table)227
+5488 y(\(where)42 b(TF)m(ORMn)f(=)g('B',)i('I',)f('J',)f(or)h('K'\).)g
+(This)f(do)s(es)g(not)h(create)h(or)e(c)m(hange)i(the)e(v)-5
+b(alue)42 b(of)g(the)227 5601 y(TNULLn)d(k)m(eyw)m(ord.)71
+b(FTTNULLL)39 b(is)i(iden)m(tical)h(to)e(FTTNUL)g(except)h(that)g(the)f
+(tn)m(ull)h(v)-5 b(alue)40 b(is)h(a)227 5714 y(64-bit)32
+b(in)m(teger)g(instead)e(of)h(a)g(32-bit)g(in)m(teger.)p
+eop end
+%%Page: 52 58
+TeXDict begin 52 57 bop 0 299 a Fi(52)1319 b Fg(CHAPTER)29
+b(6.)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(FTTNUL\(unit,colnum,tnull)41
+b(>)47 b(status\))382 668 y(FTTNULLL\(unit,colnum,tnu)o(lll)o(l)42
+b(>)47 b(status\))0 1001 y Fd(6.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 1251
+y Fi(These)26 b(subroutines)f(put)h(or)h(get)g(data)h(v)-5
+b(alues)26 b(in)h(the)f(primary)g(data)h(arra)m(y)g(\(i.e.,)i(the)e
+(\014rst)f(HDU)h(in)f(the)h(FITS)0 1364 y(\014le\))35
+b(or)g(an)f(IMA)m(GE)i(extension.)54 b(The)34 b(data)i(arra)m(y)f(is)f
+(represen)m(ted)h(as)g(a)g(single)g(one-dimensional)h(arra)m(y)f(of)0
+1477 y(pixels)h(regardless)h(of)f(the)g(actual)h(dimensionalit)m(y)g
+(of)g(the)f(arra)m(y)-8 b(,)38 b(and)e(the)g(FPIXEL)g(parameter)g(giv)m
+(es)i(the)0 1590 y(p)s(osition)28 b(within)e(this)i(1-D)g(arra)m(y)g
+(of)g(the)g(\014rst)e(pixel)i(to)g(read)g(or)f(write.)40
+b(Automatic)29 b(data)f(t)m(yp)s(e)g(con)m(v)m(ersion)h(is)0
+1703 y(p)s(erformed)g(for)i(n)m(umeric)g(data)g(\(except)i(for)d
+(complex)i(data)f(t)m(yp)s(es\))h(if)f(the)g(data)g(t)m(yp)s(e)g(of)g
+(the)g(primary)f(arra)m(y)0 1816 y(\(de\014ned)e(b)m(y)g(the)h(BITPIX)f
+(k)m(eyw)m(ord\))h(di\013ers)g(from)f(the)g(data)i(t)m(yp)s(e)e(of)h
+(the)g(arra)m(y)g(in)f(the)h(calling)h(subroutine.)0
+1929 y(The)41 b(data)i(v)-5 b(alues)42 b(are)g(also)h(scaled)f(b)m(y)g
+(the)g(BSCALE)f(and)g(BZER)m(O)h(header)f(v)-5 b(alues)42
+b(as)g(they)g(are)g(b)s(eing)0 2042 y(written)32 b(or)g(read)g(from)g
+(the)g(FITS)g(arra)m(y)-8 b(.)47 b(The)31 b(ftpscl)i(subroutine)e(MUST)
+g(b)s(e)h(called)h(to)g(de\014ne)e(the)i(scaling)0 2155
+y(parameters)h(when)e(writing)i(data)g(to)g(the)g(FITS)f(arra)m(y)h(or)
+f(to)h(o)m(v)m(erride)h(the)f(default)f(scaling)i(v)-5
+b(alue)34 b(giv)m(en)g(in)0 2267 y(the)d(header)f(when)f(reading)i(the)
+f(FITS)g(arra)m(y)-8 b(.)0 2428 y(Tw)m(o)41 b(sets)f(of)h(subroutines)e
+(are)i(pro)m(vided)f(to)h(read)g(the)f(data)i(arra)m(y)f(whic)m(h)f
+(di\013er)g(in)g(the)h(w)m(a)m(y)g(unde\014ned)0 2541
+y(pixels)35 b(are)h(handled.)55 b(The)35 b(\014rst)f(set)i(of)g
+(routines)f(\(FTGPVx\))h(simply)f(return)f(an)h(arra)m(y)h(of)g(data)g
+(elemen)m(ts)0 2653 y(in)c(whic)m(h)g(unde\014ned)e(pixels)i(are)h(set)
+f(equal)h(to)g(a)g(v)-5 b(alue)32 b(sp)s(eci\014ed)g(b)m(y)g(the)g
+(user)g(in)g(the)g('n)m(ullv)-5 b(al')33 b(parameter.)0
+2766 y(An)h(additional)i(feature)f(of)f(these)h(subroutines)f(is)g
+(that)i(if)e(the)h(user)f(sets)h(n)m(ullv)-5 b(al)35
+b(=)f(0,)i(then)f(no)f(c)m(hec)m(ks)i(for)0 2879 y(unde\014ned)d
+(pixels)j(will)g(b)s(e)e(p)s(erformed,)i(th)m(us)f(increasing)h(the)g
+(sp)s(eed)e(of)i(the)g(program.)55 b(The)35 b(second)h(set)g(of)0
+2992 y(routines)31 b(\(FTGPFx\))i(returns)d(the)i(data)g(elemen)m(t)h
+(arra)m(y)f(and,)f(in)h(addition,)g(a)g(logical)i(arra)m(y)e(whic)m(h)f
+(de\014nes)0 3105 y(whether)40 b(the)g(corresp)s(onding)f(data)i(pixel)
+g(is)f(unde\014ned.)69 b(The)39 b(latter)j(set)f(of)f(subroutines)f(ma)
+m(y)i(b)s(e)f(more)0 3218 y(con)m(v)m(enien)m(t)33 b(to)g(use)e(in)g
+(some)g(circumstances,)i(ho)m(w)m(ev)m(er,)g(it)f(requires)f(an)g
+(additional)h(arra)m(y)g(of)g(logical)i(v)-5 b(alues)0
+3331 y(whic)m(h)36 b(can)g(b)s(e)g(un)m(wieldy)f(when)h(w)m(orking)g
+(with)g(large)h(data)g(arra)m(ys.)58 b(Also)37 b(for)f(programmer)g
+(con)m(v)m(enience,)0 3444 y(sets)j(of)g(subroutines)f(to)h(directly)h
+(read)e(or)h(write)g(2)g(and)g(3)g(dimensional)g(arra)m(ys)g(ha)m(v)m
+(e)h(b)s(een)e(pro)m(vided,)j(as)0 3557 y(w)m(ell)31
+b(as)f(a)g(set)g(of)g(subroutines)e(to)i(read)g(or)g(write)f(an)m(y)h
+(con)m(tiguous)h(rectangular)g(subset)e(of)h(pixels)g(within)f(the)0
+3670 y(n-dimensional)h(arra)m(y)-8 b(.)0 3925 y Fh(1)81
+b Fi(Get)39 b(the)g(data)h(t)m(yp)s(e)e(of)h(the)g(image)h(\(=)f
+(BITPIX)f(v)-5 b(alue\).)67 b(P)m(ossible)39 b(returned)f(v)-5
+b(alues)39 b(are:)58 b(8,)41 b(16,)h(32,)227 4038 y(64,)36
+b(-32,)h(or)d(-64)h(corresp)s(onding)e(to)h(unsigned)f(b)m(yte,)j
+(signed)e(2-b)m(yte)h(in)m(teger,)i(signed)d(4-b)m(yte)h(in)m(teger,)
+227 4151 y(signed)c(8-b)m(yte)g(in)m(teger,)h(real,)g(and)d(double.)227
+4300 y(The)d(second)f(subroutine)g(is)h(similar)g(to)g(FTGIDT,)h
+(except)f(that)h(if)f(the)f(image)j(pixel)e(v)-5 b(alues)26
+b(are)g(scaled,)227 4413 y(with)h(non-default)g(v)-5
+b(alues)27 b(for)g(the)h(BZER)m(O)f(and)f(BSCALE)g(k)m(eyw)m(ords,)j
+(then)e(this)g(routine)g(will)g(return)227 4526 y(the)32
+b('equiv)-5 b(alen)m(t')33 b(data)e(t)m(yp)s(e)h(that)f(is)g(needed)g
+(to)h(store)g(the)f(scaled)h(v)-5 b(alues.)43 b(F)-8
+b(or)32 b(example,)g(if)f(BITPIX)227 4639 y(=)39 b(16)g(and)g(BSCALE)f
+(=)g(0.1)i(then)f(the)g(equiv)-5 b(alen)m(t)40 b(data)f(t)m(yp)s(e)g
+(is)g(\015oating)h(p)s(oin)m(t,)h(and)d(-32)i(will)g(b)s(e)227
+4752 y(returned.)65 b(There)39 b(are)g(2)g(sp)s(ecial)h(cases:)58
+b(if)39 b(the)g(image)h(con)m(tains)g(unsigned)e(2-b)m(yte)i(in)m
+(teger)g(v)-5 b(alues,)227 4865 y(with)40 b(BITPIX)g(=)f(16,)44
+b(BSCALE)39 b(=)h(1,)j(and)c(BZER)m(O)h(=)g(32768,)45
+b(then)39 b(this)h(routine)g(will)h(return)e(a)227 4978
+y(non-standard)26 b(v)-5 b(alue)27 b(of)g(20)h(for)f(the)g(bitpix)g(v)
+-5 b(alue.)40 b(Similarly)27 b(if)f(the)i(image)g(con)m(tains)g
+(unsigned)e(4-b)m(yte)227 5091 y(in)m(tegers,)32 b(then)e(bitpix)g
+(will)h(b)s(e)f(returned)f(with)h(a)h(v)-5 b(alue)31
+b(of)f(40.)382 5346 y Fe(FTGIDT\(unit,)44 b(>)k(bitpix,status\))382
+5459 y(FTGIET\(unit,)c(>)k(bitpix,status\))0 5714 y Fh(2)81
+b Fi(Get)31 b(the)g(dimension)e(\(n)m(um)m(b)s(er)h(of)g(axes)h(=)f
+(NAXIS\))h(of)f(the)h(image)p eop end
+%%Page: 53 59
+TeXDict begin 53 58 bop 0 299 a Fg(6.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(53)382 555 y Fe(FTGIDM\(unit,)44
+b(>)k(naxis,status\))0 807 y Fh(3)81 b Fi(Get)38 b(the)f(size)h(of)f
+(all)h(the)f(dimensions)g(of)g(the)g(image.)62 b(The)37
+b(FTGISZLL)e(routine)i(returns)f(an)h(arra)m(y)h(of)227
+920 y(64-bit)32 b(in)m(tegers)g(instead)e(of)h(32-bit)g(in)m(tegers.)
+382 1172 y Fe(FTGISZ\(unit,)44 b(maxdim,)i(>)i(naxes,status\))382
+1285 y(FTGISZLL\(unit,)c(maxdim,)i(>)h(naxesll,status\))0
+1537 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)g(of)h(the)f(image.)53 b(This)33
+b(routine)h(simply)f(com)m(bines)227 1649 y(calls)40
+b(to)f(the)g(ab)s(o)m(v)m(e)h(3)f(routines.)65 b(The)38
+b(FTGIPRLL)g(routine)h(returns)e(an)i(arra)m(y)g(of)g(64-bit)h(in)m
+(tegers)227 1762 y(instead)31 b(of)f(32-bit)i(in)m(tegers.)382
+2014 y Fe(FTGIPR\(unit,)44 b(maxdim,)i(>)i(bitpix,)d(naxis,)h(naxes,)h
+(int)f(*status\))382 2127 y(FTGIPRLL\(unit,)e(maxdim,)i(>)h(bitpix,)f
+(naxis,)g(naxesll,)f(int)i(*status\))0 2379 y Fh(5)81
+b Fi(Put)30 b(elemen)m(ts)h(in)m(to)h(the)e(data)h(arra)m(y)382
+2631 y Fe(FTPPR[BIJKED]\(unit,group)o(,fp)o(ixel)o(,nel)o(eme)o(nts,)o
+(valu)o(es,)41 b(>)48 b(status\))0 2883 y Fh(6)81 b Fi(Put)30
+b(elemen)m(ts)i(in)m(to)f(the)g(data)g(arra)m(y)-8 b(,)32
+b(substituting)e(the)g(appropriate)h(FITS)f(n)m(ull)g(v)-5
+b(alue)31 b(for)f(all)i(elemen)m(ts)227 2996 y(whic)m(h)c(are)f(equal)i
+(to)f(the)f(v)-5 b(alue)28 b(of)g(NULL)-10 b(V)g(AL.)28
+b(F)-8 b(or)28 b(in)m(teger)h(FITS)e(arra)m(ys,)i(the)e(n)m(ull)h(v)-5
+b(alue)28 b(de\014ned)e(b)m(y)227 3109 y(the)k(previous)f(call)i(to)g
+(FTPNUL)e(will)h(b)s(e)f(substituted;)h(for)f(\015oating)i(p)s(oin)m(t)
+f(FITS)f(arra)m(ys)h(\(BITPIX)f(=)227 3221 y(-32)j(or)e(-64\))i(then)e
+(the)h(sp)s(ecial)g(IEEE)e(NaN)i(\(Not-a-Num)m(b)s(er\))h(v)-5
+b(alue)31 b(will)g(b)s(e)f(substituted.)382 3473 y Fe
+(FTPPN[BIJKED]\(unit,group)o(,fp)o(ixel)o(,nel)o(eme)o(nts,)o(valu)o
+(es,)o(null)o(val)41 b(>)48 b(status\))0 3725 y Fh(7)81
+b Fi(Set)30 b(data)h(arra)m(y)g(elemen)m(ts)h(as)e(unde\014ned)382
+3977 y Fe(FTPPRU\(unit,group,fpixel)o(,ne)o(leme)o(nts,)41
+b(>)47 b(status\))0 4229 y Fh(8)81 b Fi(Get)36 b(elemen)m(ts)g(from)f
+(the)g(data)h(arra)m(y)-8 b(.)55 b(Unde\014ned)34 b(arra)m(y)h(elemen)m
+(ts)i(will)e(b)s(e)g(returned)f(with)g(a)i(v)-5 b(alue)35
+b(=)227 4342 y(n)m(ullv)-5 b(al,)31 b(unless)f(n)m(ullv)-5
+b(al)31 b(=)f(0)h(in)f(whic)m(h)g(case)h(no)g(c)m(hec)m(ks)g(for)g
+(unde\014ned)d(pixels)i(will)h(b)s(e)f(p)s(erformed.)382
+4594 y Fe(FTGPV[BIJKED]\(unit,group)o(,fp)o(ixel)o(,nel)o(eme)o(nts,)o
+(null)o(val)o(,)42 b(>)47 b(values,anyf,status\))0 4845
+y Fh(9)81 b Fi(Get)32 b(elemen)m(ts)g(and)f(n)m(ull\015ags)g(from)g
+(data)h(arra)m(y)-8 b(.)44 b(An)m(y)32 b(unde\014ned)d(arra)m(y)i
+(elemen)m(ts)i(will)e(ha)m(v)m(e)i(the)e(corre-)227 4958
+y(sp)s(onding)e(\015agv)-5 b(als)31 b(elemen)m(t)h(set)f(equal)g(to)g
+(.TR)m(UE.)382 5210 y Fe(FTGPF[BIJKED]\(unit,group)o(,fp)o(ixel)o(,nel)
+o(eme)o(nts,)41 b(>)48 b(values,flagvals,anyf,st)o(atu)o(s\))0
+5462 y Fh(10)e Fi(Put)30 b(v)-5 b(alues)31 b(in)m(to)g(group)f
+(parameters)382 5714 y Fe(FTPGP[BIJKED]\(unit,group)o(,fp)o(arm,)o
+(npar)o(m,v)o(alue)o(s,)42 b(>)47 b(status\))p eop end
+%%Page: 54 60
+TeXDict begin 54 59 bop 0 299 a Fi(54)1319 b Fg(CHAPTER)29
+b(6.)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(11)46 b Fi(Get)31 b(v)-5
+b(alues)31 b(from)f(group)g(parameters)382 809 y Fe
+(FTGGP[BIJKED]\(unit,group)o(,fp)o(arm,)o(npar)o(m,)41
+b(>)48 b(values,status\))0 1062 y Fi(The)32 b(follo)m(wing)h(4)g
+(subroutines)e(transfer)g(FITS)h(images)h(with)f(2)g(or)g(3)h
+(dimensions)e(to)i(or)f(from)g(a)h(data)f(arra)m(y)0
+1175 y(whic)m(h)h(has)g(b)s(een)g(declared)g(in)g(the)h(calling)h
+(program.)49 b(The)33 b(dimensionalit)m(y)h(of)g(the)f(FITS)g(image)h
+(is)f(passed)0 1288 y(b)m(y)26 b(the)g(naxis1,)h(naxis2,)h(and)d
+(naxis3)i(parameters)f(and)f(the)h(declared)h(dimensions)e(of)h(the)g
+(program)g(arra)m(y)h(are)0 1401 y(passed)k(in)f(the)i(dim1)e(and)h
+(dim2)g(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
+1514 y(same)28 b(dimensions)f(as)h(the)g(FITS)e(arra)m(y)-8
+b(,)30 b(but)d(m)m(ust)g(b)s(e)g(at)i(least)f(as)g(big.)40
+b(F)-8 b(or)29 b(example)f(if)f(a)h(FITS)f(image)i(with)0
+1627 y(NAXIS1)i(=)f(NAXIS2)h(=)f(400)i(is)e(read)h(in)m(to)g(a)g
+(program)f(arra)m(y)h(whic)m(h)f(is)h(dimensioned)f(as)g(512)i(x)f(512)
+g(pixels,)0 1739 y(then)d(the)g(image)i(will)e(just)g(\014ll)g(the)h
+(lo)m(w)m(er)g(left)g(corner)f(of)h(the)f(arra)m(y)h(with)f(pixels)g
+(in)g(the)h(range)f(1)h(-)f(400)i(in)e(the)0 1852 y(X)k(an)g(Y)h
+(directions.)47 b(This)31 b(has)h(the)h(e\013ect)g(of)g(taking)g(a)g
+(con)m(tiguous)g(set)g(of)f(pixel)h(v)-5 b(alue)33 b(in)e(the)i(FITS)e
+(arra)m(y)0 1965 y(and)k(writing)g(them)g(to)h(a)g(non-con)m(tiguous)g
+(arra)m(y)f(in)g(program)g(memory)g(\(i.e.,)j(there)e(are)f(no)m(w)h
+(some)f(blank)0 2078 y(pixels)c(around)e(the)h(edge)i(of)e(the)h(image)
+g(in)f(the)h(program)f(arra)m(y\).)0 2332 y Fh(11)46
+b Fi(Put)30 b(2-D)i(image)f(in)m(to)h(the)e(data)h(arra)m(y)382
+2585 y Fe(FTP2D[BIJKED]\(unit,group)o(,di)o(m1,n)o(axis)o(1,n)o(axis)o
+(2,im)o(age)o(,)42 b(>)47 b(status\))0 2838 y Fh(12)f
+Fi(Put)30 b(3-D)i(cub)s(e)d(in)m(to)j(the)e(data)h(arra)m(y)382
+3092 y Fe(FTP3D[BIJKED]\(unit,group)o(,di)o(m1,d)o(im2,)o(nax)o(is1,)o
+(naxi)o(s2,)o(naxi)o(s3,c)o(ube)o(,)42 b(>)47 b(status\))0
+3345 y Fh(13)f Fi(Get)29 b(2-D)f(image)h(from)f(the)f(data)i(arra)m(y)
+-8 b(.)41 b(Unde\014ned)26 b(pixels)h(in)h(the)g(arra)m(y)g(will)g(b)s
+(e)f(set)h(equal)g(to)h(the)e(v)-5 b(alue)227 3458 y(of)31
+b('n)m(ullv)-5 b(al',)31 b(unless)f(n)m(ullv)-5 b(al=0)31
+b(in)f(whic)m(h)g(case)i(no)e(testing)i(for)e(unde\014ned)e(pixels)i
+(will)h(b)s(e)f(p)s(erformed.)382 3712 y Fe(FTG2D[BIJKED]\(unit,group)o
+(,nu)o(llva)o(l,di)o(m1,)o(naxi)o(s1,n)o(axi)o(s2,)41
+b(>)48 b(image,anyf,status\))0 3965 y Fh(14)e 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)i(in)f(the)g(arra)m(y)h(will)g(b)s(e)f(set)h
+(equal)g(to)g(the)f(v)-5 b(alue)227 4078 y(of)31 b('n)m(ullv)-5
+b(al',)31 b(unless)f(n)m(ullv)-5 b(al=0)31 b(in)f(whic)m(h)g(case)i(no)
+e(testing)i(for)e(unde\014ned)e(pixels)i(will)h(b)s(e)f(p)s(erformed.)
+382 4331 y Fe(FTG3D[BIJKED]\(unit,group)o(,nu)o(llva)o(l,di)o(m1,)o
+(dim2)o(,nax)o(is1)o(,nax)o(is2,)o(nax)o(is3,)41 b(>)1002
+4444 y(cube,anyf,status\))0 4698 y Fi(The)i(follo)m(wing)h(subroutines)
+e(transfer)h(a)h(rectangular)g(subset)e(of)i(the)f(pixels)g(in)g(a)h
+(FITS)e(N-dimensional)0 4811 y(image)31 b(to)g(or)f(from)f(an)h(arra)m
+(y)g(whic)m(h)g(has)g(b)s(een)f(declared)h(in)g(the)g(calling)i
+(program.)40 b(The)29 b(fpixels)h(and)f(lpixels)0 4924
+y(parameters)e(are)h(in)m(teger)g(arra)m(ys)g(whic)m(h)f(sp)s(ecify)f
+(the)i(starting)g(and)e(ending)h(pixels)g(in)g(eac)m(h)h(dimension)e
+(of)i(the)0 5036 y(FITS)36 b(image)i(that)f(are)g(to)h(b)s(e)e(read)g
+(or)h(written.)60 b(\(Note)38 b(that)g(these)f(are)g(the)g(starting)g
+(and)f(ending)h(pixels)0 5149 y(in)d(the)h(FITS)f(image,)k(not)d(in)f
+(the)h(declared)g(arra)m(y\).)55 b(The)34 b(arra)m(y)i(parameter)f(is)g
+(treated)g(simply)g(as)g(a)g(large)0 5262 y(one-dimensional)c(arra)m(y)
+f(of)h(the)f(appropriate)g(datat)m(yp)s(e)h(con)m(taining)h(the)e
+(pixel)g(v)-5 b(alues;)31 b(The)e(pixel)i(v)-5 b(alues)30
+b(in)0 5375 y(the)c(FITS)f(arra)m(y)i(are)f(read/written)g(from/to)h
+(this)f(program)f(arra)m(y)i(in)e(strict)i(sequence)f(without)g(an)m(y)
+h(gaps;)g(it)0 5488 y(is)i(up)e(to)j(the)f(calling)h(routine)f(to)g
+(correctly)h(in)m(terpret)f(the)g(dimensionalit)m(y)h(of)f(this)g(arra)
+m(y)-8 b(.)41 b(The)28 b(t)m(w)m(o)i(families)0 5601
+y(of)d(FITS)g(reading)g(routines)g(\(FTGSVx)g(and)g(FTGSFx)g
+(subroutines\))f(also)j(ha)m(v)m(e)f(an)f('incs')h(parameter)f(whic)m
+(h)0 5714 y(de\014nes)j(the)h(data)h(sampling)e(in)m(terv)-5
+b(al)32 b(in)f(eac)m(h)h(dimension)e(of)h(the)g(FITS)f(arra)m(y)-8
+b(.)43 b(F)-8 b(or)32 b(example,)g(if)f(incs\(1\)=2)p
+eop end
+%%Page: 55 61
+TeXDict begin 55 60 bop 0 299 a Fg(6.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(55)0 555 y(and)33
+b(incs\(2\)=3)h(when)f(reading)g(a)h(2-dimensional)g(FITS)f(image,)i
+(then)e(only)h(ev)m(ery)g(other)f(pixel)h(in)f(the)h(\014rst)0
+668 y(dimension)e(and)h(ev)m(ery)h(3rd)e(pixel)i(in)f(the)g(second)g
+(dimension)f(will)i(b)s(e)e(returned)g(in)h(the)g('arra)m(y')h
+(parameter.)0 781 y([Note:)39 b(the)25 b(FTGSSx)f(family)i(of)e
+(routines)h(whic)m(h)g(w)m(ere)g(presen)m(t)g(in)f(previous)g(v)m
+(ersions)h(of)g(FITSIO)f(ha)m(v)m(e)i(b)s(een)0 894 y(sup)s(erseded)i
+(b)m(y)j(the)f(more)h(general)g(FTGSVx)f(family)h(of)g(routines.])0
+1152 y Fh(15)46 b Fi(Put)30 b(an)g(arbitrary)g(data)h(subsection)g(in)m
+(to)g(the)g(data)g(arra)m(y)-8 b(.)382 1411 y Fe
+(FTPSS[BIJKED]\(unit,group)o(,na)o(xis,)o(naxe)o(s,f)o(pixe)o(ls,l)o
+(pix)o(els,)o(arra)o(y,)41 b(>)48 b(status\))0 1669 y
+Fh(16)e Fi(Get)30 b(an)e(arbitrary)g(data)i(subsection)e(from)g(the)h
+(data)g(arra)m(y)-8 b(.)42 b(Unde\014ned)27 b(pixels)h(in)h(the)f(arra)
+m(y)i(will)e(b)s(e)g(set)227 1782 y(equal)k(to)h(the)e(v)-5
+b(alue)33 b(of)e('n)m(ullv)-5 b(al',)33 b(unless)e(n)m(ullv)-5
+b(al=0)33 b(in)e(whic)m(h)g(case)i(no)e(testing)i(for)e(unde\014ned)f
+(pixels)227 1895 y(will)h(b)s(e)f(p)s(erformed.)382 2154
+y Fe(FTGSV[BIJKED]\(unit,group)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 2266
+y(array,anyf,status\))0 2525 y Fh(17)k Fi(Get)34 b(an)f(arbitrary)g
+(data)g(subsection)g(from)g(the)g(data)g(arra)m(y)-8
+b(.)50 b(An)m(y)33 b(Unde\014ned)e(pixels)i(in)g(the)g(arra)m(y)h(will)
+227 2638 y(ha)m(v)m(e)e(the)e(corresp)s(onding)g('\015agv)-5
+b(als')31 b(elemen)m(t)h(set)f(equal)g(to)g(.TR)m(UE.)382
+2896 y Fe(FTGSF[BIJKED]\(unit,group)o(,na)o(xis,)o(naxe)o(s,f)o(pixe)o
+(ls,l)o(pix)o(els,)o(incs)o(,)42 b(>)1002 3009 y
+(array,flagvals,anyf,statu)o(s\))0 3343 y Fd(6.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 3596 y Fb(6.7.1)112 b(Column)39
+b(Information)f(Subroutines)0 3805 y Fh(1)81 b Fi(Get)37
+b(the)f(n)m(um)m(b)s(er)f(of)i(ro)m(ws)f(or)g(columns)g(in)g(the)h
+(curren)m(t)f(FITS)g(table.)59 b(The)36 b(n)m(um)m(b)s(er)f(of)h(ro)m
+(ws)h(is)f(giv)m(en)227 3918 y(b)m(y)f(the)h(NAXIS2)f(k)m(eyw)m(ord)h
+(and)f(the)g(n)m(um)m(b)s(er)f(of)h(columns)g(is)g(giv)m(en)h(b)m(y)g
+(the)f(TFIELDS)g(k)m(eyw)m(ord)g(in)227 4031 y(the)d(header)f(of)h(the)
+g(table.)45 b(The)31 b(FTGNR)-10 b(WLL)32 b(routine)g(is)f(iden)m
+(tical)i(to)g(FTGNR)-10 b(W)32 b(except)h(that)f(the)227
+4144 y(n)m(um)m(b)s(er)d(of)i(ro)m(ws)f(is)h(returned)e(as)h(a)h
+(64-bit)h(in)m(teger)g(rather)e(than)g(a)h(32-bit)g(in)m(teger.)382
+4402 y Fe(FTGNRW\(unit,)44 b(>)k(nrows,)e(status\))382
+4515 y(FTGNRWLL\(unit,)e(>)j(nrowsll,)f(status\))382
+4628 y(FTGNCL\(unit,)e(>)k(ncols,)e(status\))0 4886 y
+Fh(2)81 b Fi(Get)25 b(the)f(table)i(column)e(n)m(um)m(b)s(er)f(\(and)h
+(name\))h(of)f(the)h(column)f(whose)g(name)g(matc)m(hes)i(an)e(input)g
+(template)227 4999 y(name.)38 b(The)21 b(table)i(column)e(names)h(are)g
+(de\014ned)e(b)m(y)i(the)g(TTYPEn)e(k)m(eyw)m(ords)i(in)f(the)h(FITS)f
+(header.)37 b(If)22 b(a)227 5112 y(column)i(do)s(es)g(not)g(ha)m(v)m(e)
+h(a)f(TTYPEn)f(k)m(eyw)m(ord,)j(then)d(these)h(routines)g(assume)g
+(that)g(the)h(name)e(consists)227 5225 y(of)i(all)h(blank)f(c)m
+(haracters.)40 b(These)25 b(2)g(subroutines)e(p)s(erform)h(the)h(same)g
+(function)g(except)h(that)f(FTGCNO)227 5338 y(only)j(returns)e(the)h(n)
+m(um)m(b)s(er)f(of)h(the)g(matc)m(hing)i(column)e(whereas)g(FTGCNN)g
+(also)h(returns)e(the)i(name)f(of)227 5451 y(the)k(column.)40
+b(If)30 b(CASESEN)f(=)h(.true.)41 b(then)30 b(the)h(column)f(name)g
+(matc)m(h)i(will)e(b)s(e)g(case-sensitiv)m(e.)227 5601
+y(The)41 b(input)e(column)i(name)g(template)h(\(COL)-8
+b(TEMPLA)g(TE\))41 b(is)g(\(1\))g(either)h(the)f(exact)h(name)f(of)g
+(the)227 5714 y(column)36 b(to)i(b)s(e)d(searc)m(hed)i(for,)h(or)e
+(\(2\))i(it)f(ma)m(y)g(con)m(tain)g(wild)f(cards)g(c)m(haracters)i
+(\(*,)h(?,)f(or)e(#\),)i(or)f(\(3\))p eop end
+%%Page: 56 62
+TeXDict begin 56 61 bop 0 299 a Fi(56)1319 b Fg(CHAPTER)29
+b(6.)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(it)k(ma)m(y)g(con)m(tain)g(the)f(n)m(um)m
+(b)s(er)f(of)h(the)g(desired)g(column)g(\(where)g(the)g(n)m(um)m(b)s
+(er)f(is)h(expressed)f(as)h(ASCI)s(I)227 668 y(digits\).)41
+b(The)28 b(\014rst)g(2)h(wild)f(cards)g(b)s(eha)m(v)m(e)h(similarly)g
+(to)g(UNIX)g(\014lename)g(matc)m(hing:)40 b(the)29 b('*')g(c)m
+(haracter)227 781 y(matc)m(hes)e(an)m(y)g(sequence)f(of)h(c)m
+(haracters)g(\(including)f(zero)h(c)m(haracters\))h(and)d(the)i(')10
+b(?')39 b(c)m(haracter)28 b(matc)m(hes)227 894 y(an)m(y)40
+b(single)h(c)m(haracter.)71 b(The)39 b(#)h(wildcard)f(will)h(matc)m(h)h
+(an)m(y)f(consecutiv)m(e)i(string)e(of)g(decimal)g(digits)227
+1007 y(\(0-9\).)45 b(As)31 b(an)g(example,)h(the)f(template)h(strings)f
+('AB?DE',)h('AB*E',)h(and)d('AB*CDE')j(will)e(all)h(matc)m(h)227
+1120 y(the)26 b(string)g('ABCDE'.)i(If)d(more)h(than)g(one)g(column)g
+(name)g(in)g(the)g(table)h(matc)m(hes)g(the)f(template)i(string,)227
+1233 y(then)33 b(the)h(\014rst)f(matc)m(h)h(is)f(returned)g(and)f(the)i
+(status)g(v)-5 b(alue)34 b(will)f(b)s(e)g(set)h(to)g(237)h(as)f(a)f(w)m
+(arning)h(that)g(a)227 1346 y(unique)g(matc)m(h)i(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,)i(simply)e(call)227 1458 y(the)27
+b(subroutine)f(again)i(lea)m(ving)h(the)e(input)f(status)h(v)-5
+b(alue)28 b(equal)f(to)h(237)g(and)f(the)g(next)g(matc)m(hing)h(name)
+227 1571 y(will)k(then)g(b)s(e)f(returned.)43 b(Rep)s(eat)32
+b(this)g(pro)s(cess)f(un)m(til)h(a)g(status)g(=)g(219)h(\(column)e
+(name)h(not)g(found\))f(is)227 1684 y(returned.)40 b(If)30
+b(these)h(subroutines)e(fail)i(to)g(matc)m(h)g(the)g(template)h(to)f
+(an)m(y)g(of)f(the)h(columns)f(in)g(the)h(table,)227
+1797 y(they)i(lastly)g(c)m(hec)m(k)h(if)f(the)f(template)i(can)f(b)s(e)
+e(in)m(terpreted)i(as)g(a)g(simple)f(p)s(ositiv)m(e)h(in)m(teger)h
+(\(e.g.,)h('7',)f(or)227 1910 y('512'\))i(and)d(if)g(so,)i(they)f
+(return)e(that)j(column)e(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
+2023 y(219)e(error)e(is)g(returned.)227 2187 y(Note)h(that)e(the)h
+(FITS)e(Standard)g(recommends)g(that)i(only)f(letters,)i(digits,)f(and)
+f(the)g(underscore)f(c)m(har-)227 2300 y(acter)44 b(b)s(e)e(used)g(in)h
+(column)f(names)h(\(with)g(no)f(em)m(b)s(edded)g(spaces)h(in)g(the)g
+(name\).)78 b(T)-8 b(railing)43 b(blank)227 2412 y(c)m(haracters)32
+b(are)f(not)f(signi\014can)m(t.)382 2699 y Fe
+(FTGCNO\(unit,casesen,colt)o(emp)o(late)o(,)42 b(>)47
+b(colnum,status\))382 2812 y(FTGCNN\(unit,casesen,colt)o(emp)o(late)o
+(,)42 b(>)47 b(colname,colnum,status\))0 3098 y Fh(3)81
+b Fi(Get)39 b(the)g(datat)m(yp)s(e)h(of)e(a)h(column)g(in)f(an)g(ASCI)s
+(I)g(or)g(binary)g(table.)66 b(This)38 b(routine)h(returns)e(an)i(in)m
+(teger)227 3211 y(co)s(de)34 b(v)-5 b(alue)33 b(corresp)s(onding)f(to)i
+(the)g(datat)m(yp)s(e)g(of)f(the)g(column.)49 b(\(See)34
+b(the)f(FTBNFM)i(and)d(FT)-8 b(ASFM)227 3324 y(subroutines)27
+b(in)h(the)g(Utilities)j(section)e(of)f(this)g(do)s(cumen)m(t)g(for)g
+(a)h(list)g(of)f(the)h(co)s(de)f(v)-5 b(alues\).)41 b(The)27
+b(v)m(ector)227 3437 y(rep)s(eat)38 b(coun)m(t)g(\(whic)m(h)g(is)g(alw)
+m(a)m(y)h(1)f(for)g(ASCI)s(I)e(table)i(columns\))g(is)g(also)g
+(returned.)62 b(If)37 b(the)h(sp)s(eci\014ed)227 3550
+y(column)32 b(has)f(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)e(of)i(a)g(unit)f(string)h
+(in)f(the)227 3663 y(column)i(is)g(also)h(returned.)48
+b(Note)34 b(that)g(this)e(routine)h(supp)s(orts)f(the)h(lo)s(cal)h(con)
+m(v)m(en)m(tion)h(for)e(sp)s(ecifying)227 3776 y(arra)m(ys)f(of)f
+(strings)g(within)f(a)i(binary)e(table)i(c)m(haracter)g(column,)g
+(using)e(the)h(syn)m(tax)h(TF)m(ORM)f(=)g('rAw')227 3889
+y(where)f('r')g(is)h(the)f(total)i(n)m(um)m(b)s(er)d(of)i(c)m
+(haracters)g(\(=)g(the)f(width)g(of)g(the)g(column\))h(and)f('w')g(is)g
+(the)h(width)227 4002 y(of)39 b(a)f(unit)g(string)g(within)g(the)g
+(column.)64 b(Th)m(us)37 b(if)h(the)g(column)g(has)g(TF)m(ORM)h(=)f
+('60A12')i(then)e(this)227 4114 y(routine)29 b(will)g(return)f(dataco)s
+(de)i(=)e(16,)i(rep)s(eat)f(=)f(60,)j(and)d(width)g(=)g(12.)41
+b(\(The)29 b(TDIMn)f(k)m(eyw)m(ord)h(ma)m(y)227 4227
+y(also)35 b(b)s(e)e(used)g(to)h(sp)s(ecify)f(the)h(unit)f(string)h
+(length;)i(The)d(pair)g(of)h(k)m(eyw)m(ords)g(TF)m(ORMn)f(=)g('60A')j
+(and)227 4340 y(TDIMn)30 b(=)g('\(12,5\)')j(w)m(ould)e(ha)m(v)m(e)g
+(the)g(same)g(e\013ect)g(as)g(TF)m(ORMn)f(=)g('60A12'\).)227
+4504 y(The)h(second)h(routine,)g(FTEQTY)f(is)g(similar)h(except)h(that)
+f(in)f(the)h(case)g(of)g(scaled)g(in)m(teger)h(columns)e(it)227
+4617 y(returns)23 b(the)h('equiv)-5 b(alen)m(t')25 b(data)f(t)m(yp)s(e)
+g(that)h(is)e(needed)h(to)g(store)g(the)g(scaled)g(v)-5
+b(alues,)26 b(and)d(not)h(necessarily)227 4730 y(the)38
+b(ph)m(ysical)h(data)f(t)m(yp)s(e)g(of)g(the)g(unscaled)g(v)-5
+b(alues)38 b(as)g(stored)g(in)g(the)g(FITS)f(table.)64
+b(F)-8 b(or)38 b(example)h(if)227 4843 y(a)c('1I')g(column)f(in)g(a)g
+(binary)g(table)h(has)f(TSCALn)f(=)g(1)i(and)f(TZER)m(On)f(=)g(32768,)
+38 b(then)c(this)g(column)227 4956 y(e\013ectiv)m(ely)27
+b(con)m(tains)e(unsigned)e(short)g(in)m(teger)j(v)-5
+b(alues,)25 b(and)f(th)m(us)f(the)h(returned)f(v)-5 b(alue)24
+b(of)g(t)m(yp)s(eco)s(de)h(will)227 5068 y(b)s(e)32 b(the)h(co)s(de)g
+(for)g(an)f(unsigned)g(short)g(in)m(teger,)j(not)e(a)g(signed)g(short)f
+(in)m(teger.)49 b(Similarly)-8 b(,)34 b(if)f(a)g(column)227
+5181 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)h(b)s(e)f(the)h(co)s(de)f(for)h
+(a)227 5294 y('real')h(column.)382 5581 y Fe(FTGTCL\(unit,colnum,)42
+b(>)48 b(datacode,repeat,width,st)o(atu)o(s\))382 5694
+y(FTEQTY\(unit,colnum,)42 b(>)48 b(datacode,repeat,width,st)o(atu)o
+(s\))p eop end
+%%Page: 57 63
+TeXDict begin 57 62 bop 0 299 a Fg(6.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(57)0 555 y
+Fh(4)81 b Fi(Return)22 b(the)i(displa)m(y)g(width)f(of)g(a)h(column.)39
+b(This)22 b(is)i(the)g(length)g(of)f(the)h(string)g(that)g(will)g(b)s
+(e)f(returned)f(when)227 668 y(reading)33 b(the)g(column)g(as)g(a)g
+(formatted)g(string.)48 b(The)32 b(displa)m(y)h(width)f(is)h
+(determined)g(b)m(y)f(the)h(TDISPn)227 781 y(k)m(eyw)m(ord,)e(if)g
+(presen)m(t,)f(otherwise)h(b)m(y)f(the)h(data)g(t)m(yp)s(e)g(of)f(the)h
+(column.)382 1012 y Fe(FTGCDW\(unit,)44 b(colnum,)i(>)i(dispwidth,)d
+(status\))0 1243 y Fh(5)81 b Fi(Get)29 b(information)f(ab)s(out)g(an)g
+(existing)h(ASCI)s(I)e(table)i(column.)40 b(\(NOTE:)28
+b(TSCAL)f(and)g(TZER)m(O)h(m)m(ust)g(b)s(e)227 1356 y(declared)j(as)g
+(Double)g(Precision)g(v)-5 b(ariables\).)41 b(All)31
+b(the)g(returned)e(parameters)i(are)f(scalar)i(quan)m(tities.)382
+1586 y Fe(FTGACL\(unit,colnum,)42 b(>)716 1699 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 1930 y Fh(6)81 b Fi(Get)29 b(information)f(ab)s
+(out)f(an)h(existing)h(binary)e(table)i(column.)40 b(\(NOTE:)28
+b(TSCAL)e(and)i(TZER)m(O)f(m)m(ust)h(b)s(e)227 2043 y(declared)j(as)f
+(Double)g(Precision)h(v)-5 b(ariables\).)41 b(D)m(A)-8
+b(T)g(A)g(TYPE)32 b(is)e(a)g(c)m(haracter)i(string)d(whic)m(h)h
+(returns)f(the)227 2156 y(datat)m(yp)s(e)35 b(of)g(the)f(column)g(as)g
+(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 2269 y(the)27
+b(case)g(of)g(an)f(ASCI)s(I)f(c)m(haracter)j(column,)f(D)m(A)-8
+b(T)g(A)g(TYPE)29 b(will)d(ha)m(v)m(e)i(a)f(v)-5 b(alue)27
+b(of)f(the)h(form)f('An')g(where)227 2382 y('n')34 b(is)g(an)g(in)m
+(teger)i(expressing)e(the)g(width)f(of)h(the)h(\014eld)e(in)h(c)m
+(haracters.)53 b(F)-8 b(or)35 b(example,)h(if)e(TF)m(ORM)g(=)227
+2495 y('160A8')39 b(then)e(FTGBCL)f(will)h(return)f(D)m(A)-8
+b(T)g(A)g(TYPE='A8')39 b(and)d(REPEA)-8 b(T=20.)60 b(All)37
+b(the)g(returned)227 2608 y(parameters)31 b(are)g(scalar)g(quan)m
+(tities.)382 2838 y Fe(FTGBCL\(unit,colnum,)42 b(>)716
+2951 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 3182 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)33 b(has)f(the)g(form)g('\(l,m,n...\)')47 b(where)32
+b(l,)h(m,)f(n...)46 b(are)33 b(the)227 3295 y(dimensions)d(of)g(a)h(m)m
+(ultidimensional)g(arra)m(y)g(column)f(in)g(a)h(binary)f(table.)382
+3526 y Fe(FTPTDM\(unit,colnum,naxis)o(,na)o(xes,)41 b(>)48
+b(status\))0 3757 y Fh(8)81 b Fi(Return)29 b(the)h(n)m(um)m(b)s(er)e
+(of)i(and)g(size)g(of)g(the)g(dimensions)g(of)g(a)g(table)h(column.)40
+b(Normally)31 b(this)f(information)227 3870 y(is)h(giv)m(en)h(b)m(y)f
+(the)g(TDIMn)f(k)m(eyw)m(ord,)i(but)e(if)h(this)g(k)m(eyw)m(ord)g(is)g
+(not)g(presen)m(t)g(then)g(this)f(routine)h(returns)227
+3983 y(NAXIS)f(=)g(1)h(and)f(NAXES\(1\))h(equal)g(to)g(the)g(rep)s(eat)
+g(coun)m(t)g(in)f(the)g(TF)m(ORM)h(k)m(eyw)m(ord.)382
+4213 y Fe(FTGTDM\(unit,colnum,maxdi)o(m,)41 b(>)48 b
+(naxis,naxes,status\))0 4444 y Fh(9)81 b Fi(Deco)s(de)33
+b(the)g(input)f(TDIMn)h(k)m(eyw)m(ord)g(string)f(\(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 4557 y(of)c(the)g(dimensions)f(of)h(a)g(binary)f(table)
+h(column.)40 b(If)27 b(the)h(input)f(tdimstr)g(c)m(haracter)i(string)f
+(is)g(n)m(ull,)g(then)227 4670 y(this)d(routine)f(returns)f(naxis)h(=)h
+(1)f(and)g(naxes[0])i(equal)e(to)i(the)e(rep)s(eat)h(coun)m(t)g(in)f
+(the)g(TF)m(ORM)h(k)m(eyw)m(ord.)227 4783 y(This)30 b(routine)g(is)h
+(called)g(b)m(y)f(FTGTDM.)382 5014 y Fe(FTDTDM\(unit,tdimstr,coln)o
+(um,)o(maxd)o(im,)41 b(>)48 b(naxis,naxes,)c(status\))0
+5245 y Fh(10)i Fi(Return)32 b(the)h(optimal)h(n)m(um)m(b)s(er)e(of)h
+(ro)m(ws)g(to)h(read)f(or)g(write)g(at)h(one)f(time)h(for)e(maxim)m(um)
+h(I/O)g(e\016ciency)-8 b(.)227 5358 y(Refer)31 b(to)g(the)g
+(\\Optimizing)g(Co)s(de")f(section)i(in)e(Chapter)g(5)g(for)h(more)f
+(discussion)g(on)g(ho)m(w)h(to)g(use)f(this)227 5470
+y(routine.)382 5701 y Fe(FFGRSZ\(unit,)44 b(>)k(nrows,status\))p
+eop end
+%%Page: 58 64
+TeXDict begin 58 63 bop 0 299 a Fi(58)1319 b Fg(CHAPTER)29
+b(6.)112 b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30
+b(SUBR)m(OUTINES)0 555 y Fb(6.7.2)112 b(Lo)m(w-Lev)m(el)39
+b(T)-9 b(able)38 b(Access)f(Subroutines)0 774 y Fi(The)d(follo)m(wing)h
+(subroutines)e(pro)m(vide)i(lo)m(w-lev)m(el)i(access)e(to)g(the)g(data)
+g(in)f(ASCI)s(I)e(or)i(binary)g(tables)h(and)f(are)0
+887 y(mainly)29 b(useful)f(as)i(an)f(e\016cien)m(t)h(w)m(a)m(y)g(to)g
+(cop)m(y)g(all)g(or)f(part)g(of)g(a)g(table)h(from)f(one)g(lo)s(cation)
+i(to)f(another.)40 b(These)0 1000 y(routines)24 b(simply)g(read)g(or)h
+(write)f(the)h(sp)s(eci\014ed)e(n)m(um)m(b)s(er)g(of)i(consecutiv)m(e)h
+(b)m(ytes)f(in)f(an)g(ASCI)s(I)f(or)h(binary)g(table,)0
+1113 y(without)37 b(regard)g(for)f(column)h(b)s(oundaries)e(or)i(the)g
+(ro)m(w)g(length)h(in)e(the)h(table.)61 b(The)37 b(\014rst)f(t)m(w)m(o)
+i(subroutines)0 1226 y(read)29 b(or)h(write)g(consecutiv)m(e)h(b)m
+(ytes)f(in)f(a)h(table)g(to)h(or)e(from)g(a)h(c)m(haracter)h(string)e
+(v)-5 b(ariable,)31 b(while)f(the)f(last)i(t)m(w)m(o)0
+1339 y(subroutines)f(read)i(or)g(write)g(consecutiv)m(e)h(b)m(ytes)g
+(to)f(or)g(from)f(a)h(v)-5 b(ariable)33 b(declared)f(as)g(a)g(n)m
+(umeric)f(data)i(t)m(yp)s(e)0 1452 y(\(e.g.,)40 b(INTEGER,)d
+(INTEGER*2,)i(REAL,)d(DOUBLE)h(PRECISION\).)f(These)g(routines)h(do)f
+(not)h(p)s(erform)0 1564 y(an)m(y)c(mac)m(hine)g(dep)s(enden)m(t)f
+(data)i(con)m(v)m(ersion)g(or)e(b)m(yte)i(sw)m(apping,)f(except)h(that)
+f(con)m(v)m(ersion)h(to/from)f(ASCI)s(I)0 1677 y(format)d(is)g(p)s
+(erformed)e(b)m(y)h(the)h(FTGTBS)f(and)g(FTPTBS)g(routines)h(on)f(mac)m
+(hines)h(whic)m(h)g(do)f(not)h(use)f(ASCI)s(I)0 1790
+y(c)m(haracter)j(co)s(des)e(in)g(the)h(in)m(ternal)g(data)g(represen)m
+(tations)h(\(e.g.,)g(on)e(IBM)h(mainframe)f(computers\).)0
+2049 y Fh(1)81 b Fi(Read)26 b(a)h(consecutiv)m(e)h(string)f(of)f(c)m
+(haracters)i(from)e(an)g(ASCI)s(I)f(table)i(in)m(to)h(a)e(c)m(haracter)
+i(v)-5 b(ariable)28 b(\(spanning)227 2162 y(columns)k(and)g(m)m
+(ultiple)h(ro)m(ws)f(if)g(necessary\))h(This)f(routine)g(should)f(not)i
+(b)s(e)e(used)h(with)g(binary)f(tables)227 2275 y(b)s(ecause)g(of)f
+(complications)i(related)g(to)f(passing)f(string)g(v)-5
+b(ariables)31 b(b)s(et)m(w)m(een)g(C)f(and)g(F)-8 b(ortran.)382
+2533 y Fe(FTGTBS\(unit,frow,startch)o(ar,)o(ncha)o(rs,)41
+b(>)48 b(string,status\))0 2792 y Fh(2)81 b Fi(W)-8 b(rite)31
+b(a)g(consecutiv)m(e)h(string)e(of)h(c)m(haracters)g(to)g(an)f(ASCI)s
+(I)f(table)i(from)f(a)h(c)m(haracter)h(v)-5 b(ariable)31
+b(\(spanning)227 2905 y(columns)h(and)g(m)m(ultiple)h(ro)m(ws)f(if)g
+(necessary\))h(This)f(routine)g(should)f(not)i(b)s(e)e(used)h(with)g
+(binary)f(tables)227 3018 y(b)s(ecause)g(of)f(complications)i(related)g
+(to)f(passing)f(string)g(v)-5 b(ariables)31 b(b)s(et)m(w)m(een)g(C)f
+(and)g(F)-8 b(ortran.)382 3277 y Fe(FTPTBS\(unit,frow,startch)o(ar,)o
+(ncha)o(rs,s)o(tri)o(ng,)41 b(>)48 b(status\))0 3535
+y Fh(3)81 b Fi(Read)27 b(a)h(consecutiv)m(e)i(arra)m(y)e(of)g(b)m(ytes)
+g(from)f(an)g(ASCI)s(I)f(or)i(binary)e(table)j(in)m(to)f(a)g(n)m
+(umeric)g(v)-5 b(ariable)28 b(\(span-)227 3648 y(ning)k(columns)f(and)h
+(m)m(ultiple)g(ro)m(ws)g(if)g(necessary\).)46 b(The)32
+b(arra)m(y)g(parameter)g(ma)m(y)h(b)s(e)e(declared)h(as)h(an)m(y)227
+3761 y(n)m(umerical)i(datat)m(yp)s(e)g(as)g(long)g(as)g(the)f(arra)m(y)
+h(is)f(at)h(least)h('nc)m(hars')f(b)m(ytes)f(long,)j(e.g.,)f(if)f(nc)m
+(hars)f(=)g(17,)227 3874 y(then)c(declare)i(the)e(arra)m(y)h(as)g
+(INTEGER*4)g(ARRA)-8 b(Y\(5\).)382 4133 y Fe(FTGTBB\(unit,frow,startch)
+o(ar,)o(ncha)o(rs,)41 b(>)48 b(array,status\))0 4391
+y Fh(4)81 b Fi(W)-8 b(rite)32 b(a)f(consecutiv)m(e)i(arra)m(y)f(of)f(b)
+m(ytes)g(to)h(an)e(ASCI)s(I)g(or)h(binary)f(table)i(from)e(a)i(n)m
+(umeric)e(v)-5 b(ariable)32 b(\(span-)227 4504 y(ning)j(columns)f(and)g
+(m)m(ultiple)h(ro)m(ws)g(if)f(necessary\))i(The)e(arra)m(y)h(parameter)
+g(ma)m(y)h(b)s(e)e(declared)h(as)g(an)m(y)227 4617 y(n)m(umerical)g
+(datat)m(yp)s(e)g(as)g(long)g(as)g(the)f(arra)m(y)h(is)f(at)h(least)h
+('nc)m(hars')f(b)m(ytes)f(long,)j(e.g.,)f(if)f(nc)m(hars)f(=)g(17,)227
+4730 y(then)c(declare)i(the)e(arra)m(y)h(as)g(INTEGER*4)g(ARRA)-8
+b(Y\(5\).)382 4989 y Fe(FTPTBB\(unit,frow,startch)o(ar,)o(ncha)o(rs,a)o
+(rra)o(y,)42 b(>)47 b(status\))0 5279 y Fb(6.7.3)112
+b(Edit)37 b(Ro)m(ws)g(or)h(Columns)0 5488 y Fh(1)81 b
+Fi(Insert)26 b(blank)h(ro)m(ws)h(in)m(to)g(an)f(existing)h(ASCI)s(I)e
+(or)h(binary)g(table)h(\(in)g(the)f(CDU\).)h(All)g(the)g(ro)m(ws)f(F)m
+(OLLO)m(W-)227 5601 y(ING)35 b(ro)m(w)g(FR)m(O)m(W)g(are)g(shifted)f
+(do)m(wn)g(b)m(y)h(NR)m(O)m(WS)g(ro)m(ws.)53 b(If)34
+b(FR)m(O)m(W)i(or)e(FR)m(O)m(WLL)i(equals)e(0)h(then)227
+5714 y(the)27 b(blank)f(ro)m(ws)h(are)g(inserted)f(at)h(the)g(b)s
+(eginning)f(of)g(the)h(table.)41 b(These)26 b(routines)g(mo)s(dify)g
+(the)h(NAXIS2)p eop end
+%%Page: 59 65
+TeXDict begin 59 64 bop 0 299 a Fg(6.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(59)227 555
+y(k)m(eyw)m(ord)35 b(to)h(re\015ect)f(the)g(new)f(n)m(um)m(b)s(er)f(of)
+i(ro)m(ws)g(in)f(the)h(table.)54 b(Note)36 b(that)f(it)h(is)e(*not*)i
+(necessary)f(to)227 668 y(insert)c(ro)m(ws)f(in)g(a)h(table)g(b)s
+(efore)f(writing)g(data)i(to)f(those)g(ro)m(ws)f(\(indeed,)g(it)h(w)m
+(ould)g(b)s(e)e(ine\016cien)m(t)j(to)f(do)227 781 y(so\).)54
+b(Instead,)35 b(one)g(ma)m(y)g(simply)f(write)h(data)g(to)g(an)m(y)g
+(ro)m(w)f(of)h(the)g(table,)h(whether)e(that)h(ro)m(w)g(of)f(data)227
+894 y(already)d(exists)g(or)g(not.)382 1116 y Fe
+(FTIROW\(unit,frow,nrows,)41 b(>)48 b(status\))382 1229
+y(FTIROWLL\(unit,frowll,nro)o(wsl)o(l,)42 b(>)47 b(status\))0
+1451 y Fh(2)81 b Fi(Delete)25 b(ro)m(ws)f(from)f(an)g(existing)i(ASCI)s
+(I)c(or)j(binary)f(table)h(\(in)f(the)h(CDU\).)g(The)f(NR)m(O)m(WS)h
+(\(or)g(NR)m(O)m(WSLL\))227 1564 y(is)e(the)g(n)m(um)m(b)s(er)f(of)h
+(ro)m(ws)g(are)g(deleted,)i(starting)f(with)f(ro)m(w)g(FR)m(O)m(W)h
+(\(or)f(FR)m(O)m(WLL\),)h(and)f(an)m(y)g(remaining)227
+1677 y(ro)m(ws)f(in)g(the)f(table)i(are)f(shifted)g(up)e(to)j(\014ll)f
+(in)f(the)h(space.)38 b(These)21 b(routines)f(mo)s(dify)g(the)h(NAXIS2)
+g(k)m(eyw)m(ord)227 1790 y(to)31 b(re\015ect)g(the)g(new)f(n)m(um)m(b)s
+(er)f(of)h(ro)m(ws)h(in)f(the)g(table.)382 2012 y Fe
+(FTDROW\(unit,frow,nrows,)41 b(>)48 b(status\))382 2125
+y(FTDROWLL\(unit,frowll,nro)o(wsl)o(l,)42 b(>)47 b(status\))0
+2348 y Fh(3)81 b Fi(Delete)26 b(a)f(list)g(of)g(ro)m(ws)f(from)g(an)h
+(ASCI)s(I)e(or)h(binary)g(table)h(\(in)g(the)f(CDU\).)i(In)e(the)g
+(\014rst)g(routine,)i('ro)m(wrange')227 2461 y(is)i(a)g(c)m(haracter)h
+(string)f(listing)h(the)f(ro)m(ws)f(or)h(ro)m(w)g(ranges)g(to)g(delete)
+h(\(e.g.,)i('2-4,)e(5,)g(8-9'\).)42 b(In)27 b(the)h(second)227
+2574 y(routine,)37 b('ro)m(wlist')f(is)f(an)f(in)m(teger)j(arra)m(y)e
+(of)g(ro)m(w)g(n)m(um)m(b)s(ers)e(to)j(b)s(e)e(deleted)i(from)e(the)h
+(table.)56 b(nro)m(ws)34 b(is)227 2686 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)h(the)g(list.)45 b(The)31
+b(\014rst)f(ro)m(w)i(in)f(the)g(table)i(is)e(1)h(not)f(0.)44
+b(The)31 b(list)h(of)g(ro)m(w)227 2799 y(n)m(um)m(b)s(ers)d(m)m(ust)h
+(b)s(e)g(sorted)h(in)f(ascending)g(order.)382 3022 y
+Fe(FTDRRG\(unit,rowrange,)42 b(>)47 b(status\))382 3135
+y(FTDRWS\(unit,rowlist,nrow)o(s,)41 b(>)48 b(status\))0
+3357 y Fh(4)81 b Fi(Insert)43 b(a)i(blank)f(column)h(\(or)f(columns\))h
+(in)m(to)g(an)f(existing)i(ASCI)s(I)d(or)h(binary)g(table)h(\(in)g(the)
+f(CDU\).)227 3470 y(COLNUM)c(sp)s(eci\014es)g(the)h(column)f(n)m(um)m
+(b)s(er)f(that)i(the)f(\(\014rst\))g(new)g(column)g(should)f(o)s(ccup)m
+(y)i(in)f(the)227 3583 y(table.)58 b(NCOLS)34 b(sp)s(eci\014es)h(ho)m
+(w)h(man)m(y)g(columns)f(are)h(to)g(b)s(e)f(inserted.)57
+b(An)m(y)35 b(existing)i(columns)e(from)227 3696 y(this)k(p)s(osition)f
+(and)g(higher)g(are)h(mo)m(v)m(ed)g(o)m(v)m(er)h(to)f(allo)m(w)h(ro)s
+(om)e(for)h(the)f(new)g(column\(s\).)65 b(The)38 b(index)227
+3808 y(n)m(um)m(b)s(er)j(on)h(all)h(the)f(follo)m(wing)h(k)m(eyw)m
+(ords)g(will)f(b)s(e)f(incremen)m(ted)i(if)f(necessary)g(to)h
+(re\015ect)f(the)g(new)227 3921 y(p)s(osition)32 b(of)f(the)g
+(column\(s\))h(in)f(the)g(table:)43 b(TBCOLn,)30 b(TF)m(ORMn,)i
+(TTYPEn,)e(TUNITn,)h(TNULLn,)227 4034 y(TSCALn,)22 b(TZER)m(On,)g
+(TDISPn,)g(TDIMn,)h(TLMINn,)g(TLMAXn,)f(TDMINn,)i(TDMAXn,)f(TCTYPn,)227
+4147 y(TCRPXn,)30 b(TCR)-10 b(VLn,)29 b(TCDL)-8 b(Tn,)30
+b(TCR)m(OTn,)f(and)g(TCUNIn.)382 4370 y Fe(FTICOL\(unit,colnum,ttype)o
+(,tf)o(orm,)41 b(>)48 b(status\))382 4482 y(FTICLS\(unit,colnum,ncols)o
+(,tt)o(ype,)o(tfor)o(m,)41 b(>)48 b(status\))0 4705 y
+Fh(5)81 b Fi(Mo)s(dify)37 b(the)g(v)m(ector)i(length)f(of)f(a)h(binary)
+e(table)i(column)f(\(e.g.,)k(c)m(hange)e(a)e(column)g(from)g(TF)m(ORMn)
+g(=)227 4818 y('1E')31 b(to)h('20E'\).)g(The)e(v)m(ector)i(length)e(ma)
+m(y)h(b)s(e)f(increased)h(or)f(decreased)h(from)f(the)g(curren)m(t)h(v)
+-5 b(alue.)382 5040 y Fe(FTMVEC\(unit,colnum,newve)o(cle)o(n,)42
+b(>)47 b(status\))0 5262 y Fh(6)81 b Fi(Delete)29 b(a)f(column)g(from)f
+(an)g(existing)i(ASCI)s(I)d(or)i(binary)e(table)j(\(in)f(the)f(CDU\).)i
+(The)e(index)g(n)m(um)m(b)s(er)f(of)i(all)227 5375 y(the)k(k)m(eyw)m
+(ords)h(listed)f(ab)s(o)m(v)m(e)i(\(for)e(FTICOL\))f(will)h(b)s(e)g
+(decremen)m(ted)g(if)g(necessary)h(to)g(re\015ect)f(the)g(new)227
+5488 y(p)s(osition)26 b(of)g(the)g(column\(s\))g(in)f(the)h(table.)40
+b(Those)26 b(index)f(k)m(eyw)m(ords)h(that)g(refer)f(to)i(the)f
+(deleted)g(column)227 5601 y(will)33 b(also)g(b)s(e)f(deleted.)47
+b(Note)33 b(that)g(the)g(ph)m(ysical)g(size)g(of)f(the)h(FITS)e(\014le)
+i(will)f(not)h(b)s(e)e(reduced)h(b)m(y)g(this)227 5714
+y(op)s(eration,)e(and)e(the)h(empt)m(y)g(FITS)f(blo)s(c)m(ks)h(if)g(an)
+m(y)g(at)g(the)g(end)f(of)h(the)g(\014le)g(will)g(b)s(e)f(padded)g
+(with)g(zeros.)p eop end
+%%Page: 60 66
+TeXDict begin 60 65 bop 0 299 a Fi(60)1319 b Fg(CHAPTER)29
+b(6.)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(FTDCOL\(unit,colnum,)42
+b(>)48 b(status\))0 795 y Fh(7)81 b Fi(Cop)m(y)30 b(a)g(column)g(from)g
+(one)g(HDU)h(to)g(another)f(\(or)h(to)g(the)f(same)h(HDU\).)g(If)f
+(createcol)j(=)c(TR)m(UE,)i(then)f(a)227 908 y(new)20
+b(column)g(will)h(b)s(e)f(inserted)g(in)g(the)h(output)f(table,)k(at)d
+(p)s(osition)f(`outcolumn',)j(otherwise)e(the)g(existing)227
+1021 y(output)29 b(column)f(will)h(b)s(e)f(o)m(v)m(erwritten)i(\(in)f
+(whic)m(h)f(case)i(it)f(m)m(ust)f(ha)m(v)m(e)i(a)f(compatible)h(datat)m
+(yp)s(e\).)42 b(Note)227 1134 y(that)31 b(the)g(\014rst)e(column)i(in)f
+(a)g(table)i(is)e(at)h(coln)m(um)g(=)f(1.)382 1373 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 1661 y Fb(6.7.4)112
+b(Read)38 b(and)h(W)-9 b(rite)36 b(Column)j(Data)e(Routines)0
+1880 y Fi(These)22 b(subroutines)f(put)h(or)g(get)i(data)f(v)-5
+b(alues)22 b(in)g(the)h(curren)m(t)f(ASCI)s(I)f(or)h(Binary)g(table)i
+(extension.)38 b(Automatic)0 1992 y(data)21 b(t)m(yp)s(e)g(con)m(v)m
+(ersion)g(is)f(p)s(erformed)f(for)h(n)m(umerical)h(data)g(t)m(yp)s(es)g
+(\(B,I,J,E,D\))h(if)e(the)h(data)g(t)m(yp)s(e)f(of)h(the)f(column)0
+2105 y(\(de\014ned)32 b(b)m(y)i(the)f(TF)m(ORM)h(k)m(eyw)m(ord\))g
+(di\013ers)f(from)f(the)i(data)g(t)m(yp)s(e)f(of)h(the)f(calling)i
+(subroutine.)48 b(The)33 b(data)0 2218 y(v)-5 b(alues)30
+b(are)h(also)g(scaled)f(b)m(y)g(the)g(TSCALn)f(and)g(TZER)m(On)g
+(header)h(v)-5 b(alues)30 b(as)g(they)g(are)h(b)s(eing)e(written)h(to)h
+(or)0 2331 y(read)j(from)f(the)h(FITS)f(arra)m(y)-8 b(.)51
+b(The)33 b(fttscl)i(subroutine)d(MUST)i(b)s(e)f(used)g(to)h(de\014ne)f
+(the)h(scaling)h(parameters)0 2444 y(when)d(writing)h(data)h(to)g(the)f
+(table)h(or)f(to)h(o)m(v)m(erride)g(the)g(default)f(scaling)h(v)-5
+b(alues)34 b(giv)m(en)g(in)f(the)g(header)g(when)0 2557
+y(reading)27 b(from)g(the)g(table.)40 b(Note)29 b(that)e(it)h(is)f
+(*not*)h(necessary)f(to)h(insert)f(ro)m(ws)g(in)f(a)i(table)g(b)s
+(efore)e(writing)h(data)0 2670 y(to)j(those)h(ro)m(ws)e(\(indeed,)h(it)
+g(w)m(ould)g(b)s(e)f(ine\016cien)m(t)i(to)f(do)g(so\).)41
+b(Instead,)30 b(one)g(ma)m(y)g(simply)f(write)h(data)g(to)h(an)m(y)0
+2783 y(ro)m(w)f(of)h(the)g(table,)g(whether)f(that)h(ro)m(w)f(of)h
+(data)g(already)g(exists)g(or)f(not.)0 2943 y(In)i(the)i(case)g(of)f
+(binary)g(tables)h(with)f(v)m(ector)h(elemen)m(ts,)i(the)d('felem')h
+(parameter)g(de\014nes)e(the)i(starting)g(pixel)0 3056
+y(within)k(the)g(elemen)m(t)i(v)m(ector.)65 b(This)38
+b(parameter)g(is)g(ignored)h(with)e(ASCI)s(I)g(tables.)65
+b(Similarly)-8 b(,)41 b(in)d(the)g(case)0 3169 y(of)45
+b(binary)e(tables)i(the)g('nelemen)m(ts')h(parameter)f(sp)s(eci\014es)f
+(the)g(total)i(n)m(um)m(b)s(er)d(of)i(v)m(ector)h(v)-5
+b(alues)45 b(read)f(or)0 3282 y(written)36 b(\(con)m(tin)m(uing)h(on)f
+(subsequen)m(t)f(ro)m(ws)g(if)h(required\))f(and)h(not)g(the)g(n)m(um)m
+(b)s(er)e(of)i(table)h(elemen)m(ts.)58 b(Tw)m(o)0 3395
+y(sets)36 b(of)f(subroutines)g(are)g(pro)m(vided)g(to)i(get)f(the)g
+(column)f(data)h(whic)m(h)f(di\013er)g(in)h(the)f(w)m(a)m(y)i
+(unde\014ned)c(pixels)0 3508 y(are)f(handled.)42 b(The)31
+b(\014rst)g(set)h(of)f(routines)h(\(FTGCV\))g(simply)f(return)f(an)h
+(arra)m(y)h(of)f(data)h(elemen)m(ts)h(in)e(whic)m(h)0
+3620 y(unde\014ned)41 b(pixels)j(are)g(set)g(equal)g(to)h(a)f(v)-5
+b(alue)44 b(sp)s(eci\014ed)f(b)m(y)g(the)h(user)f(in)g(the)h('n)m(ullv)
+-5 b(al')44 b(parameter.)81 b(An)0 3733 y(additional)44
+b(feature)g(of)g(these)g(subroutines)e(is)i(that)g(if)f(the)h(user)e
+(sets)i(n)m(ullv)-5 b(al)44 b(=)f(0,)48 b(then)43 b(no)g(c)m(hec)m(ks)i
+(for)0 3846 y(unde\014ned)33 b(pixels)j(will)g(b)s(e)e(p)s(erformed,)i
+(th)m(us)f(increasing)h(the)g(sp)s(eed)e(of)i(the)g(program.)55
+b(The)35 b(second)h(set)g(of)0 3959 y(routines)h(\(FTGCF\))h(returns)d
+(the)i(data)h(elemen)m(t)g(arra)m(y)g(and)e(in)h(addition)g(a)g
+(logical)j(arra)m(y)d(of)g(\015ags)g(whic)m(h)0 4072
+y(de\014nes)29 b(whether)h(the)h(corresp)s(onding)e(data)i(pixel)g(is)f
+(unde\014ned.)0 4232 y(An)m(y)41 b(column,)i(regardless)e(of)g(it's)g
+(in)m(trinsic)g(datat)m(yp)s(e,)k(ma)m(y)c(b)s(e)f(read)h(as)g(a)g
+(string.)71 b(It)41 b(should)f(b)s(e)g(noted)0 4345 y(ho)m(w)m(ev)m(er)
+32 b(that)f(reading)f(a)h(n)m(umeric)f(column)g(as)h(a)f(string)h(is)f
+(10)h(-)g(100)g(times)g(slo)m(w)m(er)h(than)e(reading)g(the)h(same)0
+4458 y(column)g(as)h(a)g(n)m(um)m(b)s(er)e(due)h(to)h(the)g(large)h(o)m
+(v)m(erhead)f(in)g(constructing)g(the)g(formatted)g(strings.)44
+b(The)31 b(displa)m(y)0 4571 y(format)26 b(of)g(the)h(returned)d
+(strings)i(will)g(b)s(e)g(determined)f(b)m(y)h(the)g(TDISPn)f(k)m(eyw)m
+(ord,)j(if)d(it)i(exists,)h(otherwise)e(b)m(y)0 4684
+y(the)i(datat)m(yp)s(e)h(of)g(the)f(column.)40 b(The)28
+b(length)g(of)h(the)f(returned)f(strings)h(can)g(b)s(e)g(determined)g
+(with)f(the)i(ftgcdw)0 4797 y(routine.)41 b(The)30 b(follo)m(wing)h
+(TDISPn)f(displa)m(y)g(formats)h(are)f(curren)m(tly)h(supp)s(orted:)191
+5036 y Fe(Iw.m)142 b(Integer)191 5149 y(Ow.m)g(Octal)46
+b(integer)191 5262 y(Zw.m)142 b(Hexadecimal)45 b(integer)191
+5375 y(Fw.d)142 b(Fixed)46 b(floating)g(point)191 5488
+y(Ew.d)142 b(Exponential)45 b(floating)g(point)191 5601
+y(Dw.d)142 b(Exponential)45 b(floating)g(point)191 5714
+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)p eop end
+%%Page: 61 67
+TeXDict begin 61 66 bop 0 299 a Fg(6.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(61)0 555 y(where)37
+b(w)h(is)g(the)g(width)f(in)h(c)m(haracters)h(of)f(the)h(displa)m(y)m
+(ed)f(v)-5 b(alues,)41 b(m)c(is)h(the)g(minim)m(um)g(n)m(um)m(b)s(er)e
+(of)i(digits)0 668 y(displa)m(y)m(ed,)31 b(and)f(d)g(is)g(the)h(n)m(um)
+m(b)s(er)e(of)h(digits)h(to)g(the)g(righ)m(t)g(of)g(the)f(decimal.)42
+b(The)30 b(.m)g(\014eld)g(is)g(optional.)0 920 y Fh(1)81
+b Fi(Put)30 b(elemen)m(ts)i(in)m(to)g(an)e(ASCI)s(I)f(or)i(binary)f
+(table)i(column)e(\(in)h(the)g(CDU\).)g(\(The)g(SPP)f(FSPCLS)f(routine)
+227 1033 y(has)38 b(an)f(additional)i(in)m(teger)g(argumen)m(t)f(after)
+h(the)f(V)-10 b(ALUES)37 b(c)m(haracter)i(string)f(whic)m(h)f(sp)s
+(eci\014es)h(the)227 1145 y(size)31 b(of)g(the)g(1st)g(dimension)e(of)i
+(this)f(2-D)i(CHAR)e(arra)m(y\).)227 1294 y(The)24 b(alternate)i(v)m
+(ersion)f(of)g(these)g(routines,)h(whose)e(names)g(end)g(in)g('LL')h
+(after)g(the)g(datat)m(yp)s(e)g(c)m(haracter,)227 1407
+y(supp)s(ort)34 b(large)j(tables)f(with)g(more)f(then)h(2*31)h(ro)m
+(ws.)57 b(When)35 b(calling)i(these)f(routines,)h(the)f(fro)m(w)g(and)
+227 1520 y(felem)31 b(parameters)g(*m)m(ust*)g(b)s(e)f(64-bit)h(in)m
+(teger*8)i(v)-5 b(ariables,)31 b(instead)g(of)g(normal)f(4-b)m(yte)i
+(in)m(tegers.)382 1772 y Fe(FTPCL[SLBIJKEDCM]\(unit,c)o(oln)o(um,f)o
+(row,)o(fel)o(em,n)o(elem)o(ent)o(s,va)o(lues)o(,)42
+b(>)47 b(status\))382 1885 y(FTPCL[LBIJKEDCM]LL\(unit,)o(col)o(num,)o
+(frow)o(,fe)o(lem,)o(nele)o(men)o(ts,v)o(alue)o(s,)41
+b(>)48 b(status\))0 2136 y Fh(2)81 b Fi(Put)29 b(elemen)m(ts)i(in)m(to)
+g(an)f(ASCI)s(I)e(or)i(binary)f(table)i(column)e(\(in)h(the)g(CDU\))g
+(substituting)g(the)g(appropriate)227 2249 y(FITS)c(n)m(ull)g(v)-5
+b(alue)26 b(for)g(an)m(y)h(elemen)m(ts)g(that)g(are)f(equal)h(to)g
+(NULL)-10 b(V)g(AL.)26 b(F)-8 b(or)27 b(ASCI)s(I)e(T)-8
+b(ABLE)26 b(extensions,)227 2362 y(the)31 b(n)m(ull)f(v)-5
+b(alue)31 b(de\014ned)e(b)m(y)h(the)g(previous)g(call)i(to)f(FTSNUL)f
+(will)g(b)s(e)g(substituted;)g(F)-8 b(or)31 b(in)m(teger)h(FITS)227
+2475 y(columns,)39 b(in)e(a)h(binary)f(table)h(the)f(n)m(ull)h(v)-5
+b(alue)37 b(de\014ned)g(b)m(y)g(the)g(previous)g(call)i(to)f(FTTNUL)f
+(will)h(b)s(e)227 2588 y(substituted;)28 b(F)-8 b(or)28
+b(\015oating)h(p)s(oin)m(t)e(FITS)f(columns)h(a)h(sp)s(ecial)g(IEEE)f
+(NaN)h(\(Not-a-Num)m(b)s(er\))h(v)-5 b(alue)28 b(will)227
+2701 y(b)s(e)i(substituted.)227 2850 y(The)24 b(alternate)i(v)m(ersion)
+f(of)g(these)g(routines,)h(whose)e(names)g(end)g(in)g('LL')h(after)g
+(the)g(datat)m(yp)s(e)g(c)m(haracter,)227 2963 y(supp)s(ort)34
+b(large)j(tables)f(with)g(more)f(then)h(2*31)h(ro)m(ws.)57
+b(When)35 b(calling)i(these)f(routines,)h(the)f(fro)m(w)g(and)227
+3075 y(felem)31 b(parameters)g(*m)m(ust*)g(b)s(e)f(64-bit)h(in)m
+(teger*8)i(v)-5 b(ariables,)31 b(instead)g(of)g(normal)f(4-b)m(yte)i
+(in)m(tegers.)382 3327 y Fe(FTPCN[SBIJKED]\(unit,coln)o(um,)o(frow)o
+(,fel)o(em,)o(nele)o(ment)o(s,v)o(alue)o(s,nu)o(llv)o(al)42
+b(>)47 b(status\))382 3440 y(FTPCN[SBIJKED]LL\(unit,co)o(lnu)o(m,\(I)o
+(*8\))41 b(frow,\(I*8\))k(felem,nelements,values,)764
+3553 y(nullval)g(>)j(status\))0 3804 y Fh(3)81 b Fi(Put)37
+b(bit)h(v)-5 b(alues)38 b(in)m(to)h(a)f(binary)f(b)m(yte)h(\('B'\))i
+(or)d(bit)h(\('X'\))h(table)g(column)f(\(in)f(the)h(CDU\).)h(LRA)-8
+b(Y)38 b(is)g(an)227 3917 y(arra)m(y)c(of)g(logical)h(v)-5
+b(alues)34 b(corresp)s(onding)e(to)i(the)g(sequence)f(of)h(bits)f(to)h
+(b)s(e)f(written.)49 b(If)33 b(LRA)-8 b(Y)34 b(is)f(true)227
+4030 y(then)f(the)g(corresp)s(onding)f(bit)h(is)g(set)g(to)h(1,)g
+(otherwise)f(the)g(bit)g(is)g(set)h(to)g(0.)45 b(Note)34
+b(that)e(in)g(the)g(case)h(of)227 4143 y('X')g(columns,)g(FITSIO)e
+(will)i(write)f(to)h(all)g(8)g(bits)f(of)g(eac)m(h)i(b)m(yte)f(whether)
+e(they)i(are)g(formally)f(v)-5 b(alid)33 b(or)227 4256
+y(not.)46 b(Th)m(us)31 b(if)h(the)g(column)g(is)f(de\014ned)g(as)h
+('4X',)i(and)d(one)h(calls)h(FTPCLX)f(with)f(fbit=1)h(and)f(n)m(bit=8,)
+227 4369 y(then)j(all)h(8)f(bits)g(will)g(b)s(e)f(written)h(in)m(to)h
+(the)f(\014rst)g(b)m(yte)g(\(as)h(opp)s(osed)e(to)i(writing)e(the)i
+(\014rst)e(4)h(bits)g(in)m(to)227 4482 y(the)d(\014rst)f(ro)m(w)g(and)g
+(then)g(the)h(next)f(4)h(bits)f(in)m(to)i(the)e(next)h(ro)m(w\),)g(ev)m
+(en)g(though)f(the)h(last)g(4)g(bits)f(of)h(eac)m(h)227
+4595 y(b)m(yte)g(are)g(formally)g(not)g(de\014ned.)382
+4846 y Fe(FTPCLX\(unit,colnum,frow,)o(fbi)o(t,nb)o(it,l)o(ray)o(,)42
+b(>)47 b(status\))0 5098 y Fh(4)81 b Fi(Set)30 b(table)h(elemen)m(ts)h
+(in)e(a)h(column)f(as)h(unde\014ned)382 5349 y Fe
+(FTPCLU\(unit,colnum,frow,)o(fel)o(em,n)o(elem)o(ent)o(s,)42
+b(>)47 b(status\))0 5601 y Fh(5)81 b Fi(Get)34 b(elemen)m(ts)g(from)f
+(an)g(ASCI)s(I)f(or)h(binary)g(table)h(column)f(\(in)g(the)g(CDU\).)i
+(These)e(routines)g(return)f(the)227 5714 y(v)-5 b(alues)30
+b(of)g(the)g(table)h(column)f(arra)m(y)g(elemen)m(ts.)42
+b(Unde\014ned)28 b(arra)m(y)j(elemen)m(ts)g(will)f(b)s(e)f(returned)g
+(with)h(a)p eop end
+%%Page: 62 68
+TeXDict begin 62 67 bop 0 299 a Fi(62)1319 b Fg(CHAPTER)29
+b(6.)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(v)-5 b(alue)26 b(=)g(n)m(ullv)-5
+b(al,)27 b(unless)e(n)m(ullv)-5 b(al)26 b(=)f(0)h(\(or)g(=)f(')h(')g
+(for)f(ftgcvs\))i(in)e(whic)m(h)g(case)i(no)e(c)m(hec)m(king)j(for)d
+(unde\014ned)227 668 y(v)-5 b(alues)28 b(will)g(b)s(e)f(p)s(erformed.)
+39 b(The)27 b(ANYF)h(parameter)g(is)g(set)g(to)g(true)g(if)g(an)m(y)f
+(of)h(the)g(returned)f(elemen)m(ts)227 781 y(are)f(unde\014ned.)37
+b(\(Note:)i(the)26 b(ftgcl)g(routine)f(simple)g(gets)h(an)g(arra)m(y)f
+(of)g(logical)j(data)e(v)-5 b(alues)25 b(without)h(an)m(y)227
+894 y(c)m(hec)m(ks)39 b(for)e(unde\014ned)e(v)-5 b(alues;)41
+b(use)c(the)g(ftgc\015)h(routine)f(to)h(c)m(hec)m(k)g(for)f
+(unde\014ned)e(logical)40 b(elemen)m(ts\).)227 1007 y(\(The)29
+b(SPP)f(FSGCVS)g(routine)g(has)h(an)f(additional)i(in)m(teger)g
+(argumen)m(t)f(after)g(the)g(V)-10 b(ALUES)28 b(c)m(haracter)227
+1120 y(string)j(whic)m(h)f(sp)s(eci\014es)g(the)g(size)i(of)e(the)h
+(1st)g(dimension)e(of)i(this)f(2-D)i(CHAR)e(arra)m(y\).)227
+1272 y(The)24 b(alternate)i(v)m(ersion)f(of)g(these)g(routines,)h
+(whose)e(names)g(end)g(in)g('LL')h(after)g(the)g(datat)m(yp)s(e)g(c)m
+(haracter,)227 1385 y(supp)s(ort)34 b(large)j(tables)f(with)g(more)f
+(then)h(2*31)h(ro)m(ws.)57 b(When)35 b(calling)i(these)f(routines,)h
+(the)f(fro)m(w)g(and)227 1498 y(felem)31 b(parameters)g(*m)m(ust*)g(b)s
+(e)f(64-bit)h(in)m(teger*8)i(v)-5 b(ariables,)31 b(instead)g(of)g
+(normal)f(4-b)m(yte)i(in)m(tegers.)382 1761 y Fe
+(FTGCL\(unit,colnum,frow,f)o(ele)o(m,ne)o(leme)o(nts)o(,)42
+b(>)47 b(values,status\))382 1874 y(FTGCV[SBIJKEDCM]\(unit,co)o(lnu)o
+(m,fr)o(ow,f)o(ele)o(m,ne)o(leme)o(nts)o(,nul)o(lval)o(,)42
+b(>)1098 1987 y(values,anyf,status\))382 2100 y
+(FTGCV[BIJKEDCM]LL\(unit,c)o(oln)o(um,\()o(I*8\))f(frow,)46
+b(\(I*8\))h(felem,)f(nelements,)716 2213 y(nullval,)f(>)j
+(values,anyf,status\))0 2476 y Fh(6)81 b Fi(Get)44 b(elemen)m(ts)h(and)
+d(n)m(ull)i(\015ags)f(from)g(an)h(ASCI)s(I)d(or)j(binary)e(table)j
+(column)e(\(in)g(the)h(CHDU\).)g(These)227 2589 y(routines)29
+b(return)e(the)i(v)-5 b(alues)29 b(of)g(the)g(table)h(column)e(arra)m
+(y)i(elemen)m(ts.)41 b(An)m(y)29 b(unde\014ned)d(arra)m(y)k(elemen)m
+(ts)227 2702 y(will)37 b(ha)m(v)m(e)h(the)f(corresp)s(onding)f(\015agv)
+-5 b(als)37 b(elemen)m(t)i(set)e(equal)g(to)h(.TR)m(UE.)f(The)f(ANYF)i
+(parameter)f(is)227 2815 y(set)30 b(to)g(true)g(if)f(an)m(y)h(of)f(the)
+h(returned)e(elemen)m(ts)j(are)f(unde\014ned.)38 b(\(The)29
+b(SPP)f(FSGCFS)h(routine)h(has)f(an)227 2928 y(additional)e(in)m(teger)
+h(argumen)m(t)e(after)h(the)f(V)-10 b(ALUES)26 b(c)m(haracter)i(string)
+e(whic)m(h)f(sp)s(eci\014es)h(the)h(size)f(of)h(the)227
+3041 y(1st)k(dimension)f(of)h(this)f(2-D)h(CHAR)g(arra)m(y\).)227
+3193 y(The)24 b(alternate)i(v)m(ersion)f(of)g(these)g(routines,)h
+(whose)e(names)g(end)g(in)g('LL')h(after)g(the)g(datat)m(yp)s(e)g(c)m
+(haracter,)227 3306 y(supp)s(ort)34 b(large)j(tables)f(with)g(more)f
+(then)h(2*31)h(ro)m(ws.)57 b(When)35 b(calling)i(these)f(routines,)h
+(the)f(fro)m(w)g(and)227 3418 y(felem)31 b(parameters)g(*m)m(ust*)g(b)s
+(e)f(64-bit)h(in)m(teger*8)i(v)-5 b(ariables,)31 b(instead)g(of)g
+(normal)f(4-b)m(yte)i(in)m(tegers.)382 3682 y Fe
+(FTGCF[SLBIJKEDCM]\(unit,c)o(oln)o(um,f)o(row,)o(fel)o(em,n)o(elem)o
+(ent)o(s,)42 b(>)1193 3795 y(values,flagvals,anyf,stat)o(us\))382
+3908 y(FTGCF[BIJKED]LL\(unit,col)o(num)o(,)g(\(I*8\))k(frow,)h(\(I*8\))
+f(felem,nelements,)d(>)1193 4021 y(values,flagvals,anyf,stat)o(us\))0
+4284 y Fh(7)81 b Fi(Get)29 b(an)f(arbitrary)g(data)h(subsection)f(from)
+g(an)g(N-dimensional)h(arra)m(y)g(in)f(a)g(binary)g(table)h(v)m(ector)h
+(column.)227 4397 y(Unde\014ned)k(pixels)h(in)g(the)h(arra)m(y)g(will)f
+(b)s(e)g(set)h(equal)f(to)h(the)g(v)-5 b(alue)36 b(of)f('n)m(ullv)-5
+b(al',)38 b(unless)c(n)m(ullv)-5 b(al=0)36 b(in)227 4510
+y(whic)m(h)d(case)i(no)e(testing)i(for)e(unde\014ned)e(pixels)j(will)f
+(b)s(e)g(p)s(erformed.)49 b(The)32 b(\014rst)h(and)g(last)h(ro)m(ws)g
+(in)f(the)227 4623 y(table)28 b(to)f(b)s(e)f(read)g(are)h(sp)s
+(eci\014ed)e(b)m(y)i(fpixels\(naxis+1\))g(and)f(lpixels\(naxis+1\),)j
+(and)d(hence)g(are)h(treated)227 4736 y(as)f(the)f(next)h(higher)f
+(dimension)g(of)g(the)h(FITS)e(N-dimensional)i(arra)m(y)-8
+b(.)40 b(The)25 b(INCS)f(parameter)i(sp)s(eci\014es)227
+4848 y(the)31 b(sampling)f(in)m(terv)-5 b(al)32 b(in)e(eac)m(h)h
+(dimension)f(b)s(et)m(w)m(een)h(the)g(data)g(elemen)m(ts)g(that)g(will)
+g(b)s(e)f(returned.)382 5112 y Fe(FTGSV[BIJKED]\(unit,colnu)o(m,n)o
+(axis)o(,nax)o(es,)o(fpix)o(els,)o(lpi)o(xels)o(,inc)o(s,n)o(ullv)o
+(al,)41 b(>)1002 5225 y(array,anyf,status\))0 5488 y
+Fh(8)81 b Fi(Get)29 b(an)f(arbitrary)g(data)h(subsection)f(from)g(an)g
+(N-dimensional)h(arra)m(y)g(in)f(a)g(binary)g(table)h(v)m(ector)h
+(column.)227 5601 y(An)m(y)39 b(Unde\014ned)e(pixels)i(in)g(the)g(arra)
+m(y)g(will)g(ha)m(v)m(e)h(the)f(corresp)s(onding)f('\015agv)-5
+b(als')40 b(elemen)m(t)g(set)f(equal)227 5714 y(to)d(.TR)m(UE.)f(The)f
+(\014rst)g(and)g(last)i(ro)m(ws)f(in)f(the)h(table)h(to)f(b)s(e)g(read)
+f(are)h(sp)s(eci\014ed)f(b)m(y)h(fpixels\(naxis+1\))p
+eop end
+%%Page: 63 69
+TeXDict begin 63 68 bop 0 299 a Fg(6.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(63)227 555
+y(and)39 b(lpixels\(naxis+1\),)k(and)38 b(hence)i(are)f(treated)i(as)e
+(the)g(next)h(higher)f(dimension)f(of)i(the)f(FITS)g(N-)227
+668 y(dimensional)g(arra)m(y)-8 b(.)66 b(The)38 b(INCS)g(parameter)h
+(sp)s(eci\014es)f(the)g(sampling)h(in)m(terv)-5 b(al)40
+b(in)e(eac)m(h)i(dimension)227 781 y(b)s(et)m(w)m(een)31
+b(the)g(data)g(elemen)m(ts)h(that)f(will)f(b)s(e)g(returned.)382
+1028 y Fe(FTGSF[BIJKED]\(unit,colnu)o(m,n)o(axis)o(,nax)o(es,)o(fpix)o
+(els,)o(lpi)o(xels)o(,inc)o(s,)41 b(>)1002 1141 y
+(array,flagvals,anyf,statu)o(s\))0 1389 y Fh(9)81 b Fi(Get)33
+b(bit)g(v)-5 b(alues)34 b(from)e(a)h(b)m(yte)h(\('B'\))g(or)f(bit)g
+(\(`X`\))h(table)g(column)f(\(in)g(the)g(CDU\).)g(LRA)-8
+b(Y)34 b(is)f(an)f(arra)m(y)i(of)227 1502 y(logical)41
+b(v)-5 b(alues)39 b(corresp)s(onding)f(to)h(the)g(sequence)f(of)h(bits)
+g(to)g(b)s(e)f(read.)65 b(If)38 b(LRA)-8 b(Y)39 b(is)f(true)h(then)f
+(the)227 1615 y(corresp)s(onding)c(bit)g(w)m(as)g(set)h(to)g(1,)h
+(otherwise)f(the)f(bit)h(w)m(as)f(set)h(to)g(0.)53 b(Note)35
+b(that)g(in)f(the)h(case)g(of)f('X')227 1728 y(columns,)41
+b(FITSIO)d(will)h(read)f(all)i(8)f(bits)g(of)g(eac)m(h)h(b)m(yte)f
+(whether)f(they)h(are)g(formally)h(v)-5 b(alid)39 b(or)f(not.)227
+1840 y(Th)m(us)c(if)g(the)h(column)f(is)g(de\014ned)f(as)i('4X',)h(and)
+d(one)i(calls)h(FTGCX)e(with)g(fbit=1)h(and)e(n)m(bit=8,)j(then)227
+1953 y(all)30 b(8)g(bits)f(will)g(b)s(e)g(read)g(from)g(the)g(\014rst)f
+(b)m(yte)i(\(as)g(opp)s(osed)e(to)i(reading)f(the)h(\014rst)e(4)i(bits)
+f(from)f(the)i(\014rst)227 2066 y(ro)m(w)g(and)e(then)h(the)h(\014rst)e
+(4)i(bits)f(from)g(the)g(next)g(ro)m(w\),)i(ev)m(en)f(though)f(the)g
+(last)h(4)g(bits)f(of)g(eac)m(h)i(b)m(yte)f(are)227 2179
+y(formally)h(not)g(de\014ned.)382 2427 y Fe(FTGCX\(unit,colnum,frow,f)o
+(bit)o(,nbi)o(t,)42 b(>)47 b(lray,status\))0 2674 y Fh(10)f
+Fi(Read)31 b(an)m(y)g(consecutiv)m(e)h(set)f(of)g(bits)g(from)f(an)g
+('X')i(or)e('B')i(column)e(and)g(in)m(terpret)h(them)g(as)g(an)f
+(unsigned)227 2787 y(n-bit)k(in)m(teger.)54 b(NBIT)35
+b(m)m(ust)f(b)s(e)f(less)i(than)f(or)g(equal)h(to)g(16)g(when)f
+(calling)h(FTGCXI,)g(and)f(less)g(than)227 2900 y(or)e(equal)g(to)g(32)
+g(when)e(calling)j(FTGCXJ;)f(there)f(is)h(no)f(limit)h(on)g(the)f(v)-5
+b(alue)32 b(of)g(NBIT)f(for)g(FTGCXD,)227 3013 y(but)38
+b(the)h(returned)e(double)i(precision)f(v)-5 b(alue)39
+b(only)g(has)f(48)i(bits)e(of)h(precision)g(on)f(most)h(32-bit)h(w)m
+(ord)227 3126 y(mac)m(hines.)64 b(The)37 b(NBITS)g(bits)h(are)g(in)m
+(terpreted)g(as)g(an)g(unsigned)e(in)m(teger)k(unless)d(NBITS)g(=)g(16)
+i(\(in)227 3239 y(FTGCXI\))e(or)g(32)g(\(in)g(FTGCXJ\))f(in)g(whic)m(h)
+h(case)g(the)g(string)g(of)f(bits)h(are)g(in)m(terpreted)f(as)h(16-bit)
+h(or)227 3352 y(32-bit)j(2's)f(complemen)m(t)h(signed)e(in)m(tegers.)69
+b(If)39 b(NR)m(O)m(WS)i(is)e(greater)i(than)e(1)h(then)f(the)h(same)g
+(set)g(of)227 3464 y(bits)34 b(will)g(b)s(e)f(read)h(from)f(sequen)m
+(tial)i(ro)m(ws)f(in)f(the)h(table)g(starting)h(with)e(ro)m(w)h(FR)m(O)
+m(W.)h(Note)g(that)g(the)227 3577 y(n)m(um)m(b)s(ering)27
+b(con)m(v)m(en)m(tion)j(used)d(here)g(for)h(the)g(FBIT)f(parameter)i
+(adopts)e(1)h(for)g(the)g(\014rst)f(elemen)m(t)i(of)f(the)227
+3690 y(v)m(ector)k(of)f(bits;)f(this)h(is)f(the)h(Most)g(Signi\014can)m
+(t)g(Bit)g(of)g(the)f(in)m(teger)i(v)-5 b(alue.)382 3938
+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 4185 y Fh(11)f Fi(Get)37 b(the)e(descriptor)h
+(for)f(a)h(v)-5 b(ariable)37 b(length)f(column)f(in)g(a)h(binary)f
+(table.)57 b(The)35 b(descriptor)h(consists)g(of)227
+4298 y(2)c(in)m(teger)g(parameters:)42 b(the)31 b(n)m(um)m(b)s(er)f(of)
+h(elemen)m(ts)i(in)d(the)h(arra)m(y)h(and)e(the)h(starting)h(o\013set)g
+(relativ)m(e)h(to)227 4411 y(the)28 b(start)f(of)g(the)h(heap.)39
+b(The)27 b(\014rst)f(routine)h(returns)f(a)h(single)h(descriptor)f
+(whereas)g(the)g(second)g(routine)227 4524 y(returns)i(the)i
+(descriptors)f(for)g(a)h(range)g(of)f(ro)m(ws)h(in)f(the)g(table.)382
+4771 y Fe(FTGDES\(unit,colnum,rownu)o(m,)41 b(>)48 b
+(nelements,offset,status\))382 4884 y(FTGDESLL\(unit,colnum,row)o(num)o
+(,)42 b(>)47 b(nelementsll,offsetll,statu)o(s\))382 5110
+y(FFGDESS\(unit,colnum,firs)o(tro)o(w,nr)o(ows)41 b(>)48
+b(nelements,offset,)43 b(status\))382 5223 y(FFGDESSLL\(unit,colnum,fi)
+o(rst)o(row,)o(nrow)o(s)f(>)47 b(nelementsll,offsetll,)42
+b(status\))0 5470 y Fh(12)k Fi(W)-8 b(rite)33 b(the)f(descriptor)g(for)
+f(a)i(v)-5 b(ariable)32 b(length)g(column)g(in)f(a)i(binary)e(table.)45
+b(These)32 b(subroutines)e(can)j(b)s(e)227 5583 y(used)f(in)h
+(conjunction)g(with)g(FTGDES)g(to)g(enable)h(2)f(or)g(more)g(arra)m(ys)
+h(to)f(p)s(oin)m(t)g(to)h(the)f(same)g(storage)227 5696
+y(lo)s(cation)f(to)f(sa)m(v)m(e)h(storage)g(space)f(if)f(the)h(arra)m
+(ys)g(are)g(iden)m(tical.)p eop end
+%%Page: 64 70
+TeXDict begin 64 69 bop 0 299 a Fi(64)1319 b Fg(CHAPTER)29
+b(6.)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(FTPDES\(unit,colnum,rownu)o(m,n)o(elem)o
+(ents)o(,of)o(fset)o(,)42 b(>)47 b(status\))382 668 y
+(FTPDESLL\(unit,colnum,row)o(num)o(,nel)o(emen)o(tsl)o(l,of)o(fset)o
+(ll,)41 b(>)48 b(status\))0 1001 y Fd(6.8)135 b(Ro)l(w)46
+b(Selection)g(and)f(Calculator)h(Routines)0 1252 y Fi(These)21
+b(routines)f(all)i(parse)f(and)f(ev)-5 b(aluate)23 b(an)d(input)g
+(string)h(con)m(taining)i(a)e(user)f(de\014ned)g(arithmetic)i
+(expression.)0 1365 y(The)29 b(\014rst)f(3)i(routines)f(select)i(ro)m
+(ws)e(in)g(a)h(FITS)e(table,)j(based)e(on)g(whether)g(the)g(expression)
+g(ev)-5 b(aluates)31 b(to)f(true)0 1477 y(\(not)e(equal)f(to)h(zero\))g
+(or)f(false)h(\(zero\).)41 b(The)27 b(other)g(routines)g(ev)-5
+b(aluate)29 b(the)e(expression)g(and)f(calculate)k(a)d(v)-5
+b(alue)0 1590 y(for)35 b(eac)m(h)h(ro)m(w)g(of)f(the)h(table.)56
+b(The)35 b(allo)m(w)m(ed)i(expression)e(syn)m(tax)g(is)h(describ)s(ed)e
+(in)h(the)g(ro)m(w)h(\014lter)f(section)h(in)0 1703 y(the)h(earlier)h
+(`Extended)e(File)i(Name)f(Syn)m(tax')g(c)m(hapter)h(of)f(this)f(do)s
+(cumen)m(t.)60 b(The)36 b(expression)h(ma)m(y)g(also)h(b)s(e)0
+1816 y(written)28 b(to)i(a)e(text)i(\014le,)f(and)f(the)h(name)f(of)h
+(the)f(\014le,)h(prep)s(ended)e(with)h(a)h('@')f(c)m(haracter)i(ma)m(y)
+f(b)s(e)f(supplied)f(for)0 1929 y(the)34 b('expr')g(parameter)g(\(e.g.)
+53 b('@\014lename.txt'\).)f(The)34 b(expression)f(in)h(the)g(\014le)g
+(can)g(b)s(e)f(arbitrarily)h(complex)0 2042 y(and)h(extend)h(o)m(v)m
+(er)h(m)m(ultiple)f(lines)g(of)g(the)f(\014le.)57 b(Lines)36
+b(that)g(b)s(egin)f(with)g(2)h(slash)g(c)m(haracters)h(\('//'\))h(will)
+e(b)s(e)0 2155 y(ignored)30 b(and)g(ma)m(y)h(b)s(e)f(used)g(to)h(add)e
+(commen)m(ts)j(to)f(the)f(\014le.)0 2412 y Fh(1)81 b
+Fi(Ev)-5 b(aluate)38 b(a)f(b)s(o)s(olean)g(expression)g(o)m(v)m(er)h
+(the)g(indicated)f(ro)m(ws,)i(returning)d(an)h(arra)m(y)h(of)f(\015ags)
+g(indicating)227 2525 y(whic)m(h)30 b(ro)m(ws)h(ev)-5
+b(aluated)31 b(to)g(TR)m(UE/F)-10 b(ALSE)430 2783 y Fe
+(FTFROW\(unit,expr,firstr)o(ow,)41 b(nrows,)46 b(>)i(n_good_rows,)c
+(row_status,)h(status\))0 3040 y Fh(2)81 b Fi(Find)29
+b(the)i(\014rst)f(ro)m(w)g(whic)m(h)g(satis\014es)h(the)g(input)e(b)s
+(o)s(olean)h(expression)430 3298 y Fe(FTFFRW\(unit,)44
+b(expr,)i(>)i(rownum,)e(status\))0 3555 y Fh(3)81 b Fi(Ev)-5
+b(aluate)35 b(an)f(expression)h(on)f(all)h(ro)m(ws)g(of)f(a)h(table.)54
+b(If)34 b(the)g(input)g(and)g(output)g(\014les)g(are)h(not)g(the)f
+(same,)227 3668 y(cop)m(y)i(the)g(TR)m(UE)f(ro)m(ws)g(to)h(the)f
+(output)g(\014le;)j(if)d(the)g(output)g(table)h(is)f(not)h(empt)m(y)-8
+b(,)37 b(then)e(this)g(routine)227 3781 y(will)28 b(app)s(end)e(the)i
+(new)f(selected)i(ro)m(ws)e(after)h(the)g(existing)h(ro)m(ws.)39
+b(If)27 b(the)h(\014les)g(are)f(the)h(same,)h(delete)g(the)227
+3894 y(F)-10 b(ALSE)30 b(ro)m(ws)h(\(preserv)m(e)f(the)h(TR)m(UE)f(ro)m
+(ws\).)430 4151 y Fe(FTSROW\(inunit,)43 b(outunit,)j(expr,)g(>)i
+(status\))0 4409 y Fh(4)81 b Fi(Calculate)28 b(an)f(expression)f(for)h
+(the)f(indicated)i(ro)m(ws)e(of)h(a)g(table,)i(returning)d(the)h
+(results,)g(cast)h(as)f(datat)m(yp)s(e)227 4522 y(\(TSHOR)-8
+b(T,)32 b(TDOUBLE,)h(etc\),)h(in)e(arra)m(y)-8 b(.)48
+b(If)31 b(n)m(ulv)-5 b(al==NULL,)33 b(UNDEFs)g(will)f(b)s(e)g(zero)s
+(ed)g(out.)47 b(F)-8 b(or)227 4634 y(v)m(ector)37 b(results,)f(the)f(n)
+m(um)m(b)s(er)e(of)i(elemen)m(ts)i(returned)c(ma)m(y)j(b)s(e)e(less)h
+(than)g(nelemen)m(ts)g(if)g(nelemen)m(ts)h(is)227 4747
+y(not)30 b(an)g(ev)m(en)h(m)m(ultiple)f(of)g(the)g(result)g(dimension.)
+40 b(Call)30 b(FTTEXP)g(to)g(obtain)h(the)f(dimensions)f(of)h(the)227
+4860 y(results.)430 5118 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 5231
+y(array,anynul,status\))0 5488 y Fh(5)81 b Fi(Ev)-5 b(aluate)33
+b(an)g(expression)f(and)h(write)f(the)h(result)g(either)g(to)h(a)f
+(column)f(\(if)h(the)g(expression)f(is)h(a)g(function)227
+5601 y(of)d(other)g(columns)g(in)f(the)h(table\))h(or)f(to)g(a)h(k)m
+(eyw)m(ord)f(\(if)g(the)g(expression)f(ev)-5 b(aluates)32
+b(to)e(a)g(constan)m(t)i(and)227 5714 y(is)f(not)f(a)h(function)f(of)h
+(other)f(columns)h(in)f(the)g(table\).)42 b(In)30 b(the)h(former)e
+(case,)j(the)f(parName)f(parameter)p eop end
+%%Page: 65 71
+TeXDict begin 65 70 bop 0 299 a Fg(6.9.)72 b(CELESTIAL)29
+b(COORDINA)-8 b(TE)30 b(SYSTEM)f(SUBR)m(OUTINES)1307
+b Fi(65)227 555 y(is)40 b(the)g(name)f(of)h(the)g(column)f(\(whic)m(h)h
+(ma)m(y)g(or)f(ma)m(y)h(not)g(already)g(exist\))h(in)m(to)f(whic)m(h)g
+(to)g(write)g(the)227 668 y(results,)e(and)f(parInfo)e(con)m(tains)j
+(an)f(optional)g(TF)m(ORM)g(k)m(eyw)m(ord)g(v)-5 b(alue)38
+b(if)e(a)h(new)f(column)h(is)f(b)s(eing)227 781 y(created.)42
+b(If)28 b(a)h(TF)m(ORM)h(v)-5 b(alue)29 b(is)g(not)g(sp)s(eci\014ed)g
+(then)f(a)i(default)f(format)g(will)h(b)s(e)e(used,)h(dep)s(ending)e
+(on)227 894 y(the)35 b(expression.)54 b(If)34 b(the)h(expression)f(ev)
+-5 b(aluates)37 b(to)e(a)g(constan)m(t,)i(then)e(the)g(result)f(will)h
+(b)s(e)f(written)h(to)227 1007 y(the)28 b(k)m(eyw)m(ord)g(name)f(giv)m
+(en)h(b)m(y)g(the)f(parName)h(parameter,)h(and)d(the)i(parInfo)e
+(parameter)i(ma)m(y)g(b)s(e)f(used)227 1120 y(to)k(supply)e(an)h
+(optional)i(commen)m(t)f(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)h(exist,)g
+(then)227 1233 y(the)f(name)f(of)h(the)g(k)m(eyw)m(ord)g(m)m(ust)f(b)s
+(e)g(preceded)g(with)g(a)h('#')f(c)m(haracter,)j(otherwise)e(the)f
+(result)h(will)g(b)s(e)227 1346 y(written)h(to)g(a)g(column)f(with)g
+(that)h(name.)430 1605 y Fe(FTCALC\(inunit,)43 b(expr,)k(outunit,)e
+(parName,)h(parInfo,)f(>)j(status\))0 1865 y Fh(6)81
+b Fi(This)38 b(calculator)k(routine)e(is)f(similar)h(to)g(the)g
+(previous)f(routine,)j(except)f(that)f(the)g(expression)f(is)h(only)227
+1978 y(ev)-5 b(aluated)42 b(o)m(v)m(er)f(the)f(sp)s(eci\014ed)g(ro)m(w)
+g(ranges.)70 b(nranges)39 b(sp)s(eci\014es)h(the)g(n)m(um)m(b)s(er)f
+(of)h(ro)m(w)h(ranges,)i(and)227 2091 y(\014rstro)m(w)30
+b(and)g(lastro)m(w)h(giv)m(e)h(the)f(starting)g(and)f(ending)g(ro)m(w)g
+(n)m(um)m(b)s(er)f(of)i(eac)m(h)g(range.)430 2350 y Fe
+(FTCALC_RNG\(inunit,)42 b(expr,)47 b(outunit,)e(parName,)h(parInfo,)573
+2463 y(nranges,)f(firstrow,)h(lastrow,)f(>)j(status\))0
+2723 y Fh(7)81 b Fi(Ev)-5 b(aluate)36 b(the)f(giv)m(en)h(expression)f
+(and)g(return)f(dimension)g(and)h(t)m(yp)s(e)g(information)g(on)g(the)h
+(result.)54 b(The)227 2836 y(returned)37 b(dimensions)f(corresp)s(ond)g
+(to)j(a)e(single)i(ro)m(w)e(en)m(try)h(of)f(the)h(requested)f
+(expression,)j(and)d(are)227 2949 y(equiv)-5 b(alen)m(t)26
+b(to)f(the)g(result)f(of)g(\014ts)p 1380 2949 28 4 v
+33 w(read)p 1585 2949 V 32 w(tdim\(\).)40 b(Note)25 b(that)g(strings)f
+(are)h(considered)f(to)h(b)s(e)f(one)g(elemen)m(t)227
+3062 y(regardless)31 b(of)g(string)f(length.)41 b(If)30
+b(maxdim)g(==)g(0,)h(then)f(naxes)g(is)h(optional.)430
+3321 y Fe(FTTEXP\(unit,)44 b(expr,)i(maxdim)g(>)i(datatype,)d(nelem,)h
+(naxis,)g(naxes,)g(status\))0 3655 y Fd(6.9)135 b(Celestial)48
+b(Co)t(ordinate)e(System)f(Subroutines)0 3905 y Fi(The)36
+b(FITS)g(comm)m(unit)m(y)h(has)f(adopted)h(a)g(set)g(of)g(k)m(eyw)m
+(ord)g(con)m(v)m(en)m(tions)h(that)f(de\014ne)f(the)h(transformations)0
+4018 y(needed)30 b(to)i(con)m(v)m(ert)g(b)s(et)m(w)m(een)f(pixel)g(lo)s
+(cations)h(in)e(an)h(image)h(and)e(the)g(corresp)s(onding)g(celestial)j
+(co)s(ordinates)0 4131 y(on)25 b(the)h(sky)-8 b(,)27
+b(or)e(more)g(generally)-8 b(,)29 b(that)d(de\014ne)e(w)m(orld)h(co)s
+(ordinates)i(that)e(are)h(to)g(b)s(e)f(asso)s(ciated)i(with)e(an)m(y)h
+(pixel)0 4244 y(lo)s(cation)36 b(in)e(an)h(n-dimensional)f(FITS)g(arra)
+m(y)-8 b(.)54 b(CFITSIO)33 b(is)h(distributed)g(with)g(a)h(couple)f(of)
+h(self-con)m(tained)0 4357 y(W)-8 b(orld)28 b(Co)s(ordinate)f(System)f
+(\(W)m(CS\))i(routines,)g(ho)m(w)m(ev)m(er,)h(these)f(routines)f(DO)g
+(NOT)f(supp)s(ort)f(all)j(the)f(latest)0 4470 y(W)m(CS)38
+b(con)m(v)m(en)m(tions,)k(so)d(it)g(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)e(use)g
+(a)h(more)0 4583 y(robust)30 b(external)h(W)m(CS)f(library)-8
+b(.)41 b(Sev)m(eral)31 b(recommended)f(libraries)h(are:)95
+4842 y Fe(WCSLIB)47 b(-)95 b(supported)45 b(by)i(Mark)g(Calabretta)95
+4955 y(WCSTools)f(-)h(supported)f(by)h(Doug)g(Mink)95
+5068 y(AST)g(library)f(-)i(developed)d(by)i(the)g(U.K.)g(Starlink)e
+(project)0 5328 y Fi(More)30 b(information)f(ab)s(out)g(the)g(W)m(CS)g
+(k)m(eyw)m(ord)h(con)m(v)m(en)m(tions)h(and)d(links)h(to)h(all)g(of)f
+(these)g(W)m(CS)g(libraries)h(can)0 5441 y(b)s(e)g(found)f(on)h(the)h
+(FITS)e(Supp)s(ort)g(O\016ce)h(w)m(eb)g(site)i(at)f(h)m
+(ttp://\014ts.gsfc.nasa.go)m(v)j(under)29 b(the)h(W)m(CS)h(link.)0
+5601 y(The)i(functions)h(pro)m(vided)g(in)f(these)i(external)f(W)m(CS)g
+(libraries)h(will)f(need)g(access)h(to)g(the)f(W)m(CS)g(information)0
+5714 y(con)m(tained)i(in)f(the)h(FITS)e(\014le)i(headers.)55
+b(One)35 b(con)m(v)m(enien)m(t)i(w)m(a)m(y)f(to)g(pass)f(this)g
+(information)h(to)g(the)f(external)p eop end
+%%Page: 66 72
+TeXDict begin 66 71 bop 0 299 a Fi(66)1319 b Fg(CHAPTER)29
+b(6.)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(library)39 b(is)h(to)h(use)e(FITSIO)g(to)h
+(cop)m(y)h(the)f(header)f(k)m(eyw)m(ords)h(in)m(to)h(one)f(long)g(c)m
+(haracter)i(string,)g(and)d(then)0 668 y(pass)29 b(this)h(string)g(to)g
+(an)g(in)m(terface)h(routine)f(in)g(the)g(external)g(library)g(that)g
+(will)g(extract)i(the)e(necessary)g(W)m(CS)0 781 y(information)h
+(\(e.g.,)h(see)f(the)f(astFitsChan)h(and)f(astPutCards)g(routines)g(in)
+g(the)h(Starlink)f(AST)g(library\).)0 941 y(The)24 b(follo)m(wing)j
+(FITSIO)c(routines)i(DO)g(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)i(that)f(ha)m(v)m(e)g(b)s(een)0
+1054 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(,)39 b(the)f(follo)m(wing)g(routines)g(ARE)f(NO)
+m(W)h(DEP-)0 1167 y(RECA)-8 b(TED.)29 b(It)f(is)h(STR)m(ONGL)-8
+b(Y)28 b(RECOMMENDED)h(that)g(soft)m(w)m(are)h(dev)m(elop)s(ers)f(not)g
+(use)f(these)h(routines,)0 1280 y(and)h(instead)g(use)g(an)h(external)g
+(W)m(CS)f(library)-8 b(,)31 b(as)g(describ)s(ed)e(ab)s(o)m(v)m(e.)0
+1440 y(These)21 b(routines)g(are)g(included)f(mainly)h(for)g(bac)m(kw)m
+(ard)g(compatibilit)m(y)j(with)c(existing)i(soft)m(w)m(are.)39
+b(They)21 b(supp)s(ort)0 1553 y(the)30 b(follo)m(wing)i(standard)d(map)
+g(pro)5 b(jections:)41 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 1666
+y(are)f(the)g(legal)h(v)-5 b(alues)29 b(for)f(the)h(co)s(ordt)m(yp)s(e)
+f(parameter\).)41 b(These)28 b(routines)h(are)g(based)f(on)g(similar)h
+(functions)f(in)0 1779 y(Classic)j(AIPS.)f(All)h(the)g(angular)f(quan)m
+(tities)i(are)f(giv)m(en)g(in)f(units)g(of)g(degrees.)0
+2048 y Fh(1)81 b Fi(Get)22 b(the)g(v)-5 b(alues)21 b(of)h(all)g(the)g
+(standard)f(FITS)f(celestial)k(co)s(ordinate)f(system)e(k)m(eyw)m(ords)
+h(from)f(the)h(header)f(of)h(a)227 2161 y(FITS)j(image)i(\(i.e.,)h(the)
+d(primary)g(arra)m(y)h(or)f(an)h(image)g(extension\).)40
+b(These)26 b(v)-5 b(alues)25 b(ma)m(y)h(then)g(b)s(e)e(passed)227
+2274 y(to)39 b(the)e(subroutines)g(that)h(p)s(erform)e(the)i(co)s
+(ordinate)g(transformations.)63 b(If)37 b(an)m(y)h(or)g(all)g(of)g(the)
+g(W)m(CS)227 2387 y(k)m(eyw)m(ords)32 b(are)f(not)g(presen)m(t,)h(then)
+f(default)g(v)-5 b(alues)31 b(will)h(b)s(e)e(returned.)41
+b(If)31 b(the)g(\014rst)g(co)s(ordinate)g(axis)h(is)227
+2500 y(the)d(declination-lik)m(e)j(co)s(ordinate,)e(then)e(this)g
+(routine)h(will)g(sw)m(ap)f(them)h(so)g(that)g(the)g(longitudinal-lik)m
+(e)227 2612 y(co)s(ordinate)i(is)g(returned)e(as)i(the)f(\014rst)g
+(axis.)227 2767 y(If)35 b(the)h(\014le)f(uses)g(the)g(new)m(er)h('CDj)p
+1454 2767 28 4 v 32 w(i')g(W)m(CS)f(transformation)h(matrix)g(k)m(eyw)m
+(ords)f(instead)h(of)f(old)h(st)m(yle)227 2880 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)f
+(routine)h(will)g(calculate)j(and)c(return)g(the)h(v)-5
+b(alues)227 2993 y(of)33 b(the)g(equiv)-5 b(alen)m(t)35
+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)h(from)e(the)i(new-st)m(yle)g(k)m(eyw)m(ords)227
+3106 y(to)e(the)f(old-st)m(yle)h(v)-5 b(alues)31 b(is)g(sometimes)g
+(only)g(an)g(appro)m(ximation,)h(so)e(if)h(the)g(appro)m(ximation)h(is)
+e(larger)227 3219 y(than)37 b(an)h(in)m(ternally)g(de\014ned)e
+(threshold)h(lev)m(el,)k(then)c(CFITSIO)f(will)i(still)g(return)e(the)i
+(appro)m(ximate)227 3332 y(W)m(CS)f(k)m(eyw)m(ord)g(v)-5
+b(alues,)39 b(but)d(will)h(also)h(return)d(with)i(status)g(=)f(506,)k
+(to)e(w)m(arn)e(the)h(calling)h(program)227 3445 y(that)30
+b(appro)m(ximations)f(ha)m(v)m(e)h(b)s(een)e(made.)40
+b(It)29 b(is)g(then)f(up)g(to)h(the)g(calling)i(program)d(to)h(decide)h
+(whether)227 3558 y(the)k(appro)m(ximations)g(are)g(su\016cien)m(tly)g
+(accurate)i(for)d(the)h(particular)f(application,)j(or)e(whether)f
+(more)227 3671 y(precise)e(W)m(CS)f(transformations)h(m)m(ust)f(b)s(e)g
+(p)s(erformed)f(using)h(new-st)m(yle)h(W)m(CS)g(k)m(eyw)m(ords)f
+(directly)-8 b(.)382 3940 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 4209 y Fh(2)81 b Fi(Get)34 b(the)f(v)-5
+b(alues)33 b(of)g(all)h(the)f(standard)f(FITS)h(celestial)i(co)s
+(ordinate)f(system)f(k)m(eyw)m(ords)g(from)g(the)g(header)227
+4322 y(of)j(a)h(FITS)e(table)h(where)g(the)g(X)g(and)f(Y)h(\(or)g(RA)g
+(and)g(DEC)f(co)s(ordinates)i(are)f(stored)g(in)g(2)g(separate)227
+4435 y(columns)c(of)g(the)g(table.)46 b(These)31 b(v)-5
+b(alues)32 b(ma)m(y)h(then)e(b)s(e)h(passed)f(to)h(the)g(subroutines)f
+(that)h(p)s(erform)f(the)227 4548 y(co)s(ordinate)g(transformations.)
+382 4817 y Fe(FTGTCS\(unit,xcol,ycol,)42 b(>)716 4930
+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 5199 y Fh(3)81 b Fi(Calculate)42
+b(the)g(celestial)h(co)s(ordinate)f(corresp)s(onding)e(to)i(the)f
+(input)f(X)h(and)g(Y)g(pixel)g(lo)s(cation)i(in)e(the)227
+5312 y(image.)382 5581 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 5694
+y(coordtype,)k(>)i(xpos,ypos,status\))p eop end
+%%Page: 67 73
+TeXDict begin 67 72 bop 0 299 a Fg(6.10.)73 b(FILE)30
+b(CHECKSUM)f(SUBR)m(OUTINES)2080 b Fi(67)0 555 y Fh(4)81
+b Fi(Calculate)42 b(the)g(X)f(and)f(Y)h(pixel)h(lo)s(cation)g(corresp)s
+(onding)e(to)i(the)f(input)f(celestial)k(co)s(ordinate)e(in)f(the)227
+668 y(image.)382 932 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 1045
+y(coordtype,)k(>)i(xpix,ypix,status\))0 1383 y Fd(6.10)136
+b(File)45 b(Chec)l(ksum)g(Subroutines)0 1634 y Fi(The)33
+b(follo)m(wing)h(routines)f(either)h(compute)f(or)h(v)-5
+b(alidate)34 b(the)g(c)m(hec)m(ksums)f(for)g(the)h(CHDU.)g(The)e(D)m(A)
+-8 b(T)g(ASUM)0 1747 y(k)m(eyw)m(ord)33 b(is)f(used)f(to)i(store)f(the)
+h(n)m(umerical)f(v)-5 b(alue)33 b(of)f(the)g(32-bit,)i(1's)f(complemen)
+m(t)g(c)m(hec)m(ksum)g(for)f(the)g(data)0 1860 y(unit)26
+b(alone.)40 b(If)25 b(there)h(is)h(no)e(data)i(unit)f(then)f(the)h(v)-5
+b(alue)27 b(is)f(set)g(to)h(zero.)40 b(The)26 b(n)m(umerical)g(v)-5
+b(alue)27 b(is)f(stored)g(as)g(an)0 1973 y(ASCI)s(I)20
+b(string)i(of)h(digits,)h(enclosed)f(in)e(quotes,)k(b)s(ecause)d(the)g
+(v)-5 b(alue)23 b(ma)m(y)f(b)s(e)f(to)s(o)i(large)g(to)g(represen)m(t)f
+(as)g(a)h(32-bit)0 2086 y(signed)28 b(in)m(teger.)41
+b(The)27 b(CHECKSUM)g(k)m(eyw)m(ord)i(is)f(used)f(to)h(store)h(the)f
+(ASCI)s(I)e(enco)s(ded)i(COMPLEMENT)f(of)0 2199 y(the)f(c)m(hec)m(ksum)
+h(for)f(the)h(en)m(tire)g(HDU.)g(Storing)f(the)h(complemen)m(t,)h
+(rather)e(than)g(the)h(actual)g(c)m(hec)m(ksum,)h(forces)0
+2312 y(the)k(c)m(hec)m(ksum)h(for)f(the)h(whole)f(HDU)h(to)g(equal)g
+(zero.)47 b(If)31 b(the)i(\014le)f(has)g(b)s(een)f(mo)s(di\014ed)g
+(since)i(the)f(c)m(hec)m(ksums)0 2425 y(w)m(ere)39 b(computed,)i(then)e
+(the)g(HDU)g(c)m(hec)m(ksum)h(will)f(usually)f(not)h(equal)h(zero.)66
+b(These)39 b(c)m(hec)m(ksum)g(k)m(eyw)m(ord)0 2538 y(con)m(v)m(en)m
+(tions)34 b(are)f(based)f(on)g(a)g(pap)s(er)f(b)m(y)h(Rob)g(Seaman)g
+(published)f(in)h(the)g(pro)s(ceedings)g(of)g(the)h(AD)m(ASS)f(IV)0
+2651 y(conference)f(in)f(Baltimore)i(in)f(No)m(v)m(em)m(b)s(er)g(1994)h
+(and)e(a)h(later)g(revision)g(in)f(June)f(1995.)0 2914
+y Fh(1)81 b Fi(Compute)33 b(and)g(write)h(the)g(D)m(A)-8
+b(T)g(ASUM)35 b(and)e(CHECKSUM)g(k)m(eyw)m(ord)h(v)-5
+b(alues)34 b(for)f(the)h(CHDU)g(in)m(to)h(the)227 3027
+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)25 b(is)f(the)h(32-bit)h(c)m(hec)m(ksum)f(for)f(the)h
+(data)g(unit,)h(expressed)e(as)h(a)227 3140 y(decimal)32
+b(in)m(teger)f(enclosed)g(in)f(single)h(quotes.)41 b(The)30
+b(CHECKSUM)g(k)m(eyw)m(ord)g(v)-5 b(alue)31 b(is)f(a)h(16-c)m(haracter)
+227 3253 y(string)j(whic)m(h)f(is)h(the)f(ASCI)s(I-enco)s(ded)f(v)-5
+b(alue)34 b(for)g(the)f(complemen)m(t)i(of)f(the)f(c)m(hec)m(ksum)i
+(for)e(the)h(whole)227 3366 y(HDU.)h(If)e(these)g(k)m(eyw)m(ords)h
+(already)g(exist,)h(their)e(v)-5 b(alues)34 b(will)g(b)s(e)f(up)s
+(dated)f(only)h(if)g(necessary)h(\(i.e.,)i(if)227 3479
+y(the)31 b(\014le)f(has)g(b)s(een)g(mo)s(di\014ed)f(since)i(the)g
+(original)g(k)m(eyw)m(ord)g(v)-5 b(alues)31 b(w)m(ere)g(computed\).)382
+3743 y Fe(FTPCKS\(unit,)44 b(>)k(status\))0 4007 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)29 b(in)f(the)h(CHDU,)g(assuming)f(that)h(the)f(D)m(A)-8
+b(T)g(ASUM)30 b(k)m(eyw)m(ord)227 4119 y(exists)36 b(and)f(already)h
+(has)f(the)h(correct)g(v)-5 b(alue.)56 b(This)35 b(routine)g
+(calculates)j(the)e(new)f(c)m(hec)m(ksum)h(for)f(the)227
+4232 y(curren)m(t)40 b(header)g(unit,)j(adds)c(it)i(to)g(the)f(data)h
+(unit)f(c)m(hec)m(ksum,)k(enco)s(des)c(the)g(v)-5 b(alue)41
+b(in)m(to)g(an)f(ASCI)s(I)227 4345 y(string,)31 b(and)f(writes)g(the)h
+(string)f(to)h(the)g(CHECKSUM)e(k)m(eyw)m(ord.)382 4609
+y Fe(FTUCKS\(unit,)44 b(>)k(status\))0 4873 y Fh(3)81
+b Fi(V)-8 b(erify)35 b(the)f(CHDU)h(b)m(y)g(computing)f(the)h(c)m(hec)m
+(ksums)g(and)f(comparing)h(them)f(with)g(the)h(k)m(eyw)m(ords.)53
+b(The)227 4986 y(data)34 b(unit)f(is)g(v)m(eri\014ed)g(correctly)h(if)f
+(the)h(computed)f(c)m(hec)m(ksum)g(equals)h(the)f(v)-5
+b(alue)34 b(of)f(the)g(D)m(A)-8 b(T)g(ASUM)227 5099 y(k)m(eyw)m(ord.)64
+b(The)37 b(c)m(hec)m(ksum)i(for)f(the)g(en)m(tire)g(HDU)h(\(header)f
+(plus)f(data)i(unit\))e(is)h(correct)h(if)f(it)h(equals)227
+5212 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)f(this)h(subroutine)e(are)i(in)m
+(tegers)h(whic)m(h)227 5325 y(will)27 b(ha)m(v)m(e)g(a)f(v)-5
+b(alue)27 b(=)f(1)g(if)g(the)h(data)f(or)g(HDU)h(is)f(v)m(eri\014ed)h
+(correctly)-8 b(,)29 b(a)d(v)-5 b(alue)27 b(=)e(0)i(if)f(the)g(D)m(A)-8
+b(T)g(ASUM)28 b(or)227 5437 y(CHECKSUM)h(k)m(eyw)m(ord)g(is)h(not)f
+(presen)m(t,)h(or)f(v)-5 b(alue)30 b(=)f(-1)h(if)f(the)h(computed)f(c)m
+(hec)m(ksum)h(is)f(not)h(correct.)382 5701 y Fe(FTVCKS\(unit,)44
+b(>)k(dataok,hduok,status\))p eop end
+%%Page: 68 74
+TeXDict begin 68 73 bop 0 299 a Fi(68)1319 b Fg(CHAPTER)29
+b(6.)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(Compute)25 b(and)h(return)f(the)i
+(c)m(hec)m(ksum)g(v)-5 b(alues)26 b(for)g(the)h(CHDU)f(\(as)h(double)f
+(precision)h(v)-5 b(ariables\))27 b(without)227 668 y(creating)46
+b(or)e(mo)s(difying)g(the)h(CHECKSUM)e(and)h(D)m(A)-8
+b(T)g(ASUM)46 b(k)m(eyw)m(ords.)83 b(This)44 b(routine)g(is)h(used)227
+781 y(in)m(ternally)32 b(b)m(y)e(FTV)m(CKS,)g(but)g(ma)m(y)h(b)s(e)e
+(useful)h(in)g(other)h(situations)g(as)f(w)m(ell.)382
+1050 y Fe(FTGCKS\(unit,)44 b(>)k(datasum,hdusum,status\))0
+1319 y Fh(5)81 b Fi(Enco)s(de)33 b(a)h(c)m(hec)m(ksum)h(v)-5
+b(alue)34 b(\(stored)g(in)g(a)g(double)g(precision)g(v)-5
+b(ariable\))35 b(in)m(to)f(a)h(16-c)m(haracter)h(string.)51
+b(If)227 1432 y(COMPLEMENT)30 b(=)g(.true.)41 b(then)30
+b(the)g(32-bit)i(sum)d(v)-5 b(alue)31 b(will)g(b)s(e)f(complemen)m(ted)
+h(b)s(efore)f(enco)s(ding.)382 1701 y Fe(FTESUM\(sum,complement,)42
+b(>)47 b(checksum\))0 1971 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)g(in)m(to)h(a)g
+(double)e(precision)h(v)-5 b(alue.)65 b(If)37 b(COMPLEMENT)g(=)227
+2083 y(.true.)k(then)30 b(the)h(32-bit)g(sum)f(v)-5 b(alue)31
+b(will)f(b)s(e)g(complemen)m(ted)i(after)e(deco)s(ding.)382
+2353 y Fe(FTDSUM\(checksum,compleme)o(nt,)41 b(>)48 b(sum\))0
+2697 y Fd(6.11)180 b(Date)46 b(and)f(Time)g(Utilit)l(y)i(Routines)0
+2950 y Fi(The)29 b(follo)m(wing)i(routines)f(help)f(to)i(construct)f
+(or)f(parse)h(the)g(FITS)f(date/time)i(strings.)41 b(Starting)30
+b(in)f(the)h(y)m(ear)0 3063 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)31 b(\(and)h(the)f(v)-5
+b(alues)32 b(of)f(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 3176 y(form)j('YYYY-MM-DD')k(\(date)e(only\))
+f(or)g('YYYY-MM-DDThh:mm:ss.ddd...')61 b(\(date)38 b(and)e(time\))h
+(where)0 3288 y(the)30 b(n)m(um)m(b)s(er)f(of)i(decimal)g(places)g(in)f
+(the)g(seconds)g(v)-5 b(alue)31 b(is)f(optional.)42 b(These)30
+b(times)h(are)f(in)g(UTC.)g(The)g(older)0 3401 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 3670 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)g
+(\(1999,)h(2000,)h(etc.\))382 3940 y Fe(FTGSDT\()46 b(>)h(day,)g
+(month,)f(year,)g(status)g(\))0 4209 y Fh(2)81 b Fi(Get)34
+b(the)g(curren)m(t)g(system)f(date)i(and)e(time)h(string)g
+(\('YYYY-MM-DDThh:mm:ss'\).)53 b(The)33 b(time)i(will)f(b)s(e)227
+4322 y(in)26 b(UTC/GMT)g(if)g(a)m(v)-5 b(ailable,)29
+b(as)e(indicated)f(b)m(y)g(a)g(returned)f(timeref)h(v)-5
+b(alue)27 b(=)e(0.)40 b(If)26 b(the)g(returned)e(v)-5
+b(alue)227 4435 y(of)31 b(timeref)g(=)g(1)g(then)f(this)h(indicates)g
+(that)h(it)f(w)m(as)g(not)g(p)s(ossible)f(to)h(con)m(v)m(ert)i(the)d
+(lo)s(cal)i(time)g(to)f(UTC,)227 4547 y(and)f(th)m(us)g(the)h(lo)s(cal)
+g(time)g(w)m(as)g(returned.)382 4817 y Fe(FTGSTM\(>)45
+b(datestr,)h(timeref,)f(status\))0 5086 y Fh(3)81 b Fi(Construct)26
+b(a)i(date)g(string)f(from)g(the)g(input)f(date)i(v)-5
+b(alues.)40 b(If)27 b(the)g(y)m(ear)h(is)g(b)s(et)m(w)m(een)f(1900)i
+(and)e(1998,)j(inclu-)227 5199 y(siv)m(e,)38 b(then)c(the)i(returned)d
+(date)j(string)f(will)g(ha)m(v)m(e)i(the)e(old)g(FITS)f(format)i
+(\('dd/mm/yy'\),)h(otherwise)227 5312 y(the)32 b(date)g(string)f(will)g
+(ha)m(v)m(e)i(the)e(new)g(FITS)g(format)g(\('YYYY-MM-DD'\).)36
+b(Use)c(FTTM2S)f(instead)g(to)227 5425 y(alw)m(a)m(ys)h(return)d(a)i
+(date)g(string)g(using)e(the)i(new)f(FITS)g(format.)382
+5694 y Fe(FTDT2S\()46 b(year,)g(month,)g(day,)h(>)g(datestr,)f
+(status\))p eop end
+%%Page: 69 75
+TeXDict begin 69 74 bop 0 299 a Fg(6.12.)73 b(GENERAL)30
+b(UTILITY)g(SUBR)m(OUTINES)1979 b Fi(69)0 555 y Fh(4)81
+b Fi(Construct)34 b(a)i(new-format)f(date)h(+)f(time)h(string)f
+(\('YYYY-MM-DDThh:mm:ss.ddd...'\).)57 b(If)34 b(the)i(y)m(ear,)227
+668 y(mon)m(th,)d(and)e(da)m(y)h(v)-5 b(alues)32 b(all)h(=)e(0)h(then)g
+(only)g(the)g(time)g(is)g(enco)s(ded)f(with)h(format)g
+('hh:mm:ss.ddd...'.)227 781 y(The)j(decimals)h(parameter)g(sp)s
+(eci\014es)e(ho)m(w)i(man)m(y)f(decimal)h(places)g(of)f(fractional)i
+(seconds)e(to)h(include)227 894 y(in)30 b(the)h(string.)41
+b(If)29 b(`decimals')j(is)f(negativ)m(e,)h(then)f(only)f(the)h(date)g
+(will)f(b)s(e)g(return)f(\('YYYY-MM-DD'\).)382 1154 y
+Fe(FTTM2S\()46 b(year,)g(month,)g(day,)h(hour,)f(minute,)g(second,)g
+(decimals,)764 1267 y(>)h(datestr,)f(status\))0 1527
+y Fh(5)81 b Fi(Return)44 b(the)g(date)i(as)f(read)f(from)h(the)g(input)
+e(string,)49 b(where)44 b(the)h(string)g(ma)m(y)g(b)s(e)f(in)h(either)g
+(the)g(old)227 1640 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
+1900 y Fe(FTS2DT\(datestr,)43 b(>)48 b(year,)e(month,)g(day,)h
+(status\))0 2160 y Fh(6)81 b Fi(Return)30 b(the)h(date)h(and)f(time)h
+(as)f(read)g(from)g(the)h(input)e(string,)h(where)g(the)h(string)f(ma)m
+(y)h(b)s(e)e(in)h(either)h(the)227 2273 y(old)d(or)f(new)g(FITS)g
+(format.)40 b(The)28 b(returned)f(hours,)h(min)m(utes,)h(and)f(seconds)
+g(v)-5 b(alues)29 b(will)f(b)s(e)g(set)h(to)g(zero)227
+2386 y(if)k(the)h(input)e(string)h(do)s(es)g(not)h(include)f(the)g
+(time)h(\('dd/mm/yy')f(or)h('YYYY-MM-DD'\))j(.)c(Similarly)-8
+b(,)227 2499 y(the)36 b(returned)e(y)m(ear,)j(mon)m(th,)g(and)d(date)i
+(v)-5 b(alues)36 b(will)f(b)s(e)g(set)h(to)g(zero)g(if)f(the)g(date)h
+(is)f(not)h(included)e(in)227 2612 y(the)d(input)e(string)i
+(\('hh:mm:ss.ddd...'\).)382 2872 y Fe(FTS2TM\(datestr,)43
+b(>)48 b(year,)e(month,)g(day,)h(hour,)f(minute,)g(second,)g(status\))0
+3206 y Fd(6.12)136 b(General)45 b(Utilit)l(y)i(Subroutines)0
+3456 y Fi(The)30 b(follo)m(wing)i(utilit)m(y)f(subroutines)f(ma)m(y)h
+(b)s(e)e(useful)h(for)g(certain)h(applications:)0 3716
+y Fh(1)81 b Fi(Return)29 b(the)i(starting)g(b)m(yte)g(address)e(of)i
+(the)f(CHDU)h(and)f(the)h(next)f(HDU.)382 3976 y Fe(FTGHAD\(iunit,)44
+b(>)j(curaddr,)f(nextaddr\))0 4236 y Fh(2)81 b Fi(Con)m(v)m(ert)31
+b(a)g(c)m(haracter)h(string)e(to)h(upp)s(ercase)e(\(op)s(erates)j(in)e
+(place\).)382 4496 y Fe(FTUPCH\(string\))0 4756 y Fh(3)81
+b Fi(Compare)43 b(the)i(input)e(template)i(string)f(against)h(the)g
+(reference)f(string)g(to)h(see)g(if)f(they)g(matc)m(h.)82
+b(The)227 4869 y(template)36 b(string)f(ma)m(y)g(con)m(tain)g(wildcard)
+f(c)m(haracters:)51 b('*')35 b(will)g(matc)m(h)g(an)m(y)g(sequence)g
+(of)f(c)m(haracters)227 4982 y(\(including)j(zero)h(c)m(haracters\))g
+(and)e(')10 b(?')60 b(will)38 b(matc)m(h)f(an)m(y)g(single)h(c)m
+(haracter)g(in)f(the)g(reference)g(string.)227 5095 y(The)31
+b('#')g(c)m(haracter)i(will)f(matc)m(h)g(an)m(y)f(consecutiv)m(e)j
+(string)d(of)g(decimal)h(digits)g(\(0)g(-)g(9\).)43 b(If)31
+b(CASESN)f(=)227 5208 y(.true.)45 b(then)31 b(the)g(matc)m(h)i(will)f
+(b)s(e)f(case)h(sensitiv)m(e.)46 b(The)31 b(returned)f(MA)-8
+b(TCH)32 b(parameter)g(will)g(b)s(e)f(.true.)227 5321
+y(if)j(the)h(2)f(strings)g(matc)m(h,)j(and)c(EXA)m(CT)h(will)h(b)s(e)e
+(.true.)53 b(if)34 b(the)g(matc)m(h)h(is)g(exact)g(\(i.e.,)i(if)d(no)g
+(wildcard)227 5434 y(c)m(haracters)e(w)m(ere)f(used)f(in)g(the)g(matc)m
+(h\).)42 b(Both)31 b(strings)f(m)m(ust)h(b)s(e)e(68)j(c)m(haracters)f
+(or)g(less)f(in)g(length.)382 5694 y Fe(FTCMPS\(str_template,)42
+b(string,)k(casesen,)f(>)j(match,)e(exact\))p eop end
+%%Page: 70 76
+TeXDict begin 70 75 bop 0 299 a Fi(70)1319 b Fg(CHAPTER)29
+b(6.)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(T)-8 b(est)31 b(that)g(the)f(k)m
+(eyw)m(ord)h(name)f(con)m(tains)i(only)e(legal)j(c)m(haracters:)42
+b(A-Z,0-9,)32 b(h)m(yphen,)d(and)h(underscore.)382 820
+y Fe(FTTKEY\(keyword,)43 b(>)48 b(status\))0 1085 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)
+i(only)e(legal)i(prin)m(table)f(ASCI)s(I)e(c)m(haracters)382
+1350 y Fe(FTTREC\(card,)44 b(>)k(status\))0 1615 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)
+g(an)m(y)g(NULL)g(\(ASCI)s(I)e(0\))j(c)m(haracters.)40
+b(These)24 b(c)m(haracters)j(are)227 1728 y(illegal)37
+b(in)d(the)h(header,)g(but)f(they)g(will)h(go)g(undetected)g(b)m(y)f
+(most)h(of)g(the)f(CFITSIO)f(k)m(eyw)m(ord)i(header)227
+1841 y(routines,)29 b(b)s(ecause)f(the)h(n)m(ull)f(is)g(in)m(terpreted)
+g(as)h(the)f(normal)g(end-of-string)h(terminator.)41
+b(This)27 b(routine)227 1954 y(returns)h(the)g(p)s(osition)h(of)g(the)g
+(\014rst)f(n)m(ull)g(c)m(haracter)i(in)f(the)f(header,)h(or)g(zero)g
+(if)g(there)g(are)g(no)f(n)m(ulls.)40 b(F)-8 b(or)227
+2067 y(example)37 b(a)f(returned)f(v)-5 b(alue)37 b(of)f(110)h(w)m
+(ould)f(indicate)h(that)g(the)f(\014rst)f(NULL)h(is)g(lo)s(cated)h(in)f
+(the)g(30th)227 2180 y(c)m(haracter)28 b(of)f(the)g(second)f(k)m(eyw)m
+(ord)h(in)f(the)h(header)f(\(recall)i(that)f(eac)m(h)h(header)e(record)
+h(is)f(80)h(c)m(haracters)227 2293 y(long\).)56 b(Note)36
+b(that)g(this)f(is)g(one)g(of)g(the)g(few)g(FITSIO)f(routines)h(in)f
+(whic)m(h)h(the)g(returned)f(v)-5 b(alue)36 b(is)f(not)227
+2406 y(necessarily)d(equal)e(to)i(the)e(status)h(v)-5
+b(alue\).)382 2671 y Fe(FTNCHK\(unit,)44 b(>)k(status\))0
+2935 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)f(of)h(the)g(name.)227 3048 y(The)34 b(k)m(eyw)m(ord)h(name)f
+(normally)h(o)s(ccupies)f(the)h(\014rst)e(8)i(c)m(haracters)g(of)g(the)
+f(record,)i(except)f(under)e(the)227 3161 y(HIERAR)m(CH)e(con)m(v)m(en)
+m(tion)h(where)e(the)h(name)f(can)h(b)s(e)f(up)f(to)i(70)g(c)m
+(haracters)h(in)e(length.)382 3426 y Fe(FTGKNM\(card,)44
+b(>)k(keyname,)d(keylength,)g(staThe)h('\\#')h(character)e(will)i
+(match)f(any)h(consecutive)e(string)191 3539 y(of)i(decimal)f(digits)g
+(\(0)h(-)h(9\).)f(tus\))0 3804 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)33 b(subroutine)g
+(parses)h(the)g(input)g(header)g(record)g(to)h(return)e(the)227
+3917 y(v)-5 b(alue)27 b(\(as)g(a)g(c)m(haracter)g(string\))g(and)f
+(commen)m(t)h(strings.)39 b(If)26 b(the)g(k)m(eyw)m(ord)h(has)f(no)g(v)
+-5 b(alue)27 b(\(columns)f(9-10)227 4030 y(not)h(equal)f(to)h('=)f
+('\),)i(then)e(the)g(v)-5 b(alue)27 b(string)f(is)g(returned)f(blank)h
+(and)f(the)h(commen)m(t)i(string)e(is)g(set)g(equal)227
+4143 y(to)31 b(column)g(9)f(-)h(80)g(of)g(the)f(input)g(string.)382
+4408 y Fe(FTPSVC\(card,)44 b(>)k(value,comment,status\))0
+4673 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)35 b(subroutine)g(app)s(ends)f(the)j
+(sequence)227 4786 y(n)m(um)m(b)s(er)29 b(to)i(the)g(ro)s(ot)g(string)f
+(to)h(create)h(a)f(k)m(eyw)m(ord)g(name)f(\(e.g.,)i('NAXIS')f(+)f(2)h
+(=)f('NAXIS2'\))382 5051 y Fe(FTKEYN\(keyroot,seq_no,)42
+b(>)47 b(keyword,status\))0 5316 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)f
+(subroutine)g(concatenates)j(the)f(sequence)227 5429
+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)g(to)g(create)h(a)f(k)m(eyw)m(ord)g(name)g(\(e.g.,)j(1)d(+)f
+('CTYP')g(=)g('1CTYP'\))382 5694 y Fe(FTNKEY\(seq_no,keyroot,)42
+b(>)47 b(keyword,status\))p eop end
+%%Page: 71 77
+TeXDict begin 71 76 bop 0 299 a Fg(6.12.)73 b(GENERAL)30
+b(UTILITY)g(SUBR)m(OUTINES)1979 b Fi(71)0 555 y Fh(11)46
+b Fi(Determine)35 b(the)f(datat)m(yp)s(e)g(of)g(a)g(k)m(eyw)m(ord)h(v)
+-5 b(alue)34 b(string.)50 b(This)33 b(subroutine)g(parses)g(the)h(k)m
+(eyw)m(ord)g(v)-5 b(alue)227 668 y(string)31 b(\(usually)f(columns)g
+(11-30)j(of)d(the)h(header)f(record\))g(to)i(determine)e(its)h(datat)m
+(yp)s(e.)382 936 y Fe(FTDTYP\(value,)44 b(>)j(dtype,status\))0
+1204 y Fh(11)f Fi(Return)c(the)i(class)g(of)f(input)f(header)h(record.)
+79 b(The)43 b(record)g(is)g(classi\014ed)g(in)m(to)h(one)g(of)f(the)g
+(follo)m(wing)227 1317 y(categories)36 b(\(the)e(class)f(v)-5
+b(alues)34 b(are)f(de\014ned)f(in)h(\014tsio.h\).)49
+b(Note)35 b(that)e(this)g(is)g(one)h(of)f(the)g(few)g(FITSIO)227
+1430 y(routines)e(that)f(do)s(es)h(not)f(return)f(a)i(status)g(v)-5
+b(alue.)334 1697 y Fe(Class)94 b(Value)619 b(Keywords)95
+1810 y(TYP_STRUC_KEY)92 b(10)j(SIMPLE,)46 b(BITPIX,)g(NAXIS,)g(NAXISn,)
+g(EXTEND,)g(BLOCKED,)1002 1923 y(GROUPS,)g(PCOUNT,)g(GCOUNT,)g(END)1002
+2036 y(XTENSION,)g(TFIELDS,)f(TTYPEn,)h(TBCOLn,)g(TFORMn,)g(THEAP,)1002
+2149 y(and)h(the)g(first)f(4)i(COMMENT)e(keywords)f(in)i(the)g(primary)
+f(array)1002 2262 y(that)h(define)f(the)h(FITS)g(format.)95
+2375 y(TYP_CMPRS_KEY)92 b(20)j(The)47 b(experimental)e(keywords)g(used)
+i(in)g(the)g(compressed)1002 2488 y(image)g(format)f(ZIMAGE,)g
+(ZCMPTYPE,)f(ZNAMEn,)h(ZVALn,)1002 2601 y(ZTILEn,)g(ZBITPIX,)g
+(ZNAXISn,)f(ZSCALE,)h(ZZERO,)g(ZBLANK)95 2714 y(TYP_SCAL_KEY)140
+b(30)95 b(BSCALE,)46 b(BZERO,)g(TSCALn,)g(TZEROn)95 2826
+y(TYP_NULL_KEY)140 b(40)95 b(BLANK,)46 b(TNULLn)95 2939
+y(TYP_DIM_KEY)188 b(50)95 b(TDIMn)95 3052 y(TYP_RANG_KEY)140
+b(60)95 b(TLMINn,)46 b(TLMAXn,)g(TDMINn,)g(TDMAXn,)g(DATAMIN,)f
+(DATAMAX)95 3165 y(TYP_UNIT_KEY)140 b(70)95 b(BUNIT,)46
+b(TUNITn)95 3278 y(TYP_DISP_KEY)140 b(80)95 b(TDISPn)95
+3391 y(TYP_HDUID_KEY)d(90)j(EXTNAME,)46 b(EXTVER,)g(EXTLEVEL,)f
+(HDUNAME,)g(HDUVER,)h(HDULEVEL)95 3504 y(TYP_CKSUM_KEY)f(100)94
+b(CHECKSUM,)46 b(DATASUM)95 3617 y(TYP_WCS_KEY)141 b(110)94
+b(CTYPEn,)46 b(CUNITn,)g(CRVALn,)g(CRPIXn,)g(CROTAn,)f(CDELTn)1002
+3730 y(CDj_is,)h(PVj_ms,)g(LONPOLEs,)f(LATPOLEs)1002
+3843 y(TCTYPn,)h(TCTYns,)g(TCUNIn,)g(TCUNns,)g(TCRVLn,)f(TCRVns,)h
+(TCRPXn,)1002 3956 y(TCRPks,)g(TCDn_k,)g(TCn_ks,)g(TPVn_m,)g(TPn_ms,)f
+(TCDLTn,)h(TCROTn)1002 4068 y(jCTYPn,)g(jCTYns,)g(jCUNIn,)g(jCUNns,)g
+(jCRVLn,)f(jCRVns,)h(iCRPXn,)1002 4181 y(iCRPns,)g(jiCDn,)94
+b(jiCDns,)46 b(jPVn_m,)g(jPn_ms,)f(jCDLTn,)h(jCROTn)1002
+4294 y(\(i,j,m,n)g(are)h(integers,)e(s)i(is)h(any)f(letter\))95
+4407 y(TYP_REFSYS_KEY)d(120)j(EQUINOXs,)f(EPOCH,)g(MJD-OBSs,)f
+(RADECSYS,)g(RADESYSs)95 4520 y(TYP_COMM_KEY)140 b(130)47
+b(COMMENT,)f(HISTORY,)f(\(blank)h(keyword\))95 4633 y(TYP_CONT_KEY)140
+b(140)47 b(CONTINUE)95 4746 y(TYP_USER_KEY)140 b(150)47
+b(all)g(other)g(keywords)430 4972 y(class)f(=)h(FTGKCL)f(\(char)h
+(*card\))0 5240 y Fh(12)f Fi(P)m(arse)f(the)g('TF)m(ORM')h(binary)e
+(table)i(column)e(format)h(string.)84 b(This)44 b(subroutine)g(parses)g
+(the)h(input)227 5352 y(TF)m(ORM)27 b(c)m(haracter)g(string)f(and)g
+(returns)f(the)h(in)m(teger)h(datat)m(yp)s(e)g(co)s(de,)h(the)e(rep)s
+(eat)g(coun)m(t)h(of)f(the)g(\014eld,)227 5465 y(and,)f(in)e(the)h
+(case)g(of)g(c)m(haracter)h(string)e(\014elds,)i(the)e(length)h(of)g
+(the)g(unit)f(string.)38 b(The)23 b(follo)m(wing)i(datat)m(yp)s(e)227
+5578 y(co)s(des)e(are)h(returned)e(\(the)h(negativ)m(e)i(of)f(the)f(v)
+-5 b(alue)23 b(is)g(returned)f(if)h(the)g(column)g(con)m(tains)h(v)-5
+b(ariable-length)227 5691 y(arra)m(ys\):)p eop end
+%%Page: 72 78
+TeXDict begin 72 77 bop 0 299 a Fi(72)1319 b Fg(CHAPTER)29
+b(6.)112 b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30
+b(SUBR)m(OUTINES)764 555 y Fe(Datatype)761 b(DATACODE)46
+b(value)764 668 y(bit,)g(X)907 b(1)764 781 y(byte,)46
+b(B)811 b(11)764 894 y(logical,)45 b(L)668 b(14)764 1007
+y(ASCII)46 b(character,)f(A)286 b(16)764 1120 y(short)46
+b(integer,)g(I)381 b(21)764 1233 y(integer,)45 b(J)668
+b(41)764 1346 y(real,)46 b(E)811 b(42)764 1458 y(double)46
+b(precision,)f(D)238 b(82)764 1571 y(complex)809 b(83)764
+1684 y(double)46 b(complex)475 b(163)382 1910 y(FTBNFM\(tform,)44
+b(>)j(datacode,repeat,width,stat)o(us\))0 2147 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)37 b(that)h(de\014nes)e(the)h(column)g(format)h(in)e(an)h(ASCI)s
+(I)f(table.)62 b(This)227 2260 y(routine)31 b(parses)g(the)g(input)g
+(TF)m(ORM)g(c)m(haracter)i(string)e(and)f(returns)g(the)i(datat)m(yp)s
+(e)g(co)s(de,)f(the)h(width)227 2373 y(of)40 b(the)h(column,)h(and)e
+(\(if)g(it)g(is)h(a)f(\015oating)h(p)s(oin)m(t)f(column\))g(the)g(n)m
+(um)m(b)s(er)f(of)h(decimal)h(places)g(to)g(the)227 2486
+y(righ)m(t)28 b(of)g(the)f(decimal)h(p)s(oin)m(t.)40
+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)g(table,)227 2599 y(listed)41
+b(ab)s(o)m(v)m(e,)j(with)c(the)g(follo)m(wing)i(additional)f(rules:)60
+b(in)m(teger)42 b(columns)e(that)g(are)h(b)s(et)m(w)m(een)g(1)g(and)227
+2712 y(4)36 b(c)m(haracters)i(wide)d(are)i(de\014ned)d(to)j(b)s(e)e
+(short)h(in)m(tegers)h(\(co)s(de)f(=)g(21\).)58 b(Wider)36
+b(in)m(teger)h(columns)f(are)227 2825 y(de\014ned)j(to)i(b)s(e)e
+(regular)h(in)m(tegers)i(\(co)s(de)e(=)g(41\).)71 b(Similarly)-8
+b(,)43 b(Fixed)d(decimal)h(p)s(oin)m(t)f(columns)g(\(with)227
+2937 y(TF)m(ORM)30 b(=)g('Fw.d'\))g(are)g(de\014ned)f(to)h(b)s(e)g
+(single)g(precision)g(reals)g(\(co)s(de)h(=)e(42\))i(if)f(w)f(is)h(b)s
+(et)m(w)m(een)g(1)h(and)227 3050 y(7)i(c)m(haracters)h(wide,)f
+(inclusiv)m(e.)47 b(Wider)32 b('F')h(columns)f(will)h(return)e(a)i
+(double)f(precision)g(data)h(co)s(de)g(\(=)227 3163 y(82\).)54
+b('Ew.d')34 b(format)g(columns)g(will)h(ha)m(v)m(e)g(dataco)s(de)g(=)f
+(42,)j(and)c('Dw.d')i(format)f(columns)g(will)h(ha)m(v)m(e)227
+3276 y(dataco)s(de)d(=)e(82.)382 3513 y Fe(FTASFM\(tform,)44
+b(>)j(datacode,width,decimals,st)o(atus)o(\))0 3750 y
+Fh(14)f Fi(Calculate)32 b(the)f(starting)g(column)g(p)s(ositions)f(and)
+g(total)i(ASCI)s(I)d(table)j(width)d(based)i(on)f(the)h(input)e(arra)m
+(y)227 3863 y(of)e(ASCI)s(I)e(table)i(TF)m(ORM)g(v)-5
+b(alues.)40 b(The)26 b(SP)-8 b(A)m(CE)27 b(input)e(parameter)i
+(de\014nes)f(ho)m(w)h(man)m(y)f(blank)h(spaces)227 3976
+y(to)40 b(lea)m(v)m(e)i(b)s(et)m(w)m(een)e(eac)m(h)g(column)g(\(it)g
+(is)f(recommended)g(to)h(ha)m(v)m(e)h(one)e(space)h(b)s(et)m(w)m(een)g
+(columns)f(for)227 4089 y(b)s(etter)31 b(h)m(uman)e(readabilit)m(y\).)
+382 4326 y Fe(FTGABC\(tfields,tform,spa)o(ce,)41 b(>)48
+b(rowlen,tbcol,status\))0 4563 y Fh(15)e Fi(P)m(arse)36
+b(a)f(template)h(string)f(and)g(return)f(a)h(formatted)h(80-c)m
+(haracter)h(string)e(suitable)h(for)f(app)s(ending)e(to)227
+4675 y(\(or)40 b(deleting)h(from\))e(a)h(FITS)f(header)h(\014le.)68
+b(This)39 b(subroutine)f(is)i(useful)f(for)g(parsing)g(lines)h(from)f
+(an)227 4788 y(ASCI)s(I)34 b(template)j(\014le)f(and)e(reformatting)j
+(them)e(in)m(to)i(legal)g(FITS)d(header)i(records.)55
+b(The)35 b(formatted)227 4901 y(string)c(ma)m(y)g(then)f(b)s(e)g
+(passed)g(to)i(the)e(FTPREC,)h(FTMCRD,)g(or)f(FTDKEY)h(subroutines)e
+(to)j(app)s(end)227 5014 y(or)f(mo)s(dify)e(a)i(FITS)f(header)g
+(record.)382 5251 y Fe(FTGTHD\(template,)43 b(>)48 b
+(card,hdtype,status\))0 5488 y Fi(The)23 b(input)h(TEMPLA)-8
+b(TE)23 b(c)m(haracter)j(string)e(generally)h(should)e(con)m(tain)i(3)g
+(tok)m(ens:)38 b(\(1\))25 b(the)f(KEYNAME,)h(\(2\))0
+5601 y(the)h(V)-10 b(ALUE,)26 b(and)f(\(3\))i(the)f(COMMENT)g(string.)
+39 b(The)25 b(TEMPLA)-8 b(TE)26 b(string)g(m)m(ust)f(adhere)h(to)g(the)
+g(follo)m(wing)0 5714 y(format:)p eop end
+%%Page: 73 79
+TeXDict begin 73 78 bop 0 299 a Fg(6.12.)73 b(GENERAL)30
+b(UTILITY)g(SUBR)m(OUTINES)1979 b Fi(73)0 555 y Fh(-)80
+b Fi(The)24 b(KEYNAME)g(tok)m(en)h(m)m(ust)e(b)s(egin)h(in)f(columns)h
+(1-8)h(and)e(b)s(e)h(a)g(maxim)m(um)g(of)g(8)g(c)m(haracters)h(long.)39
+b(If)24 b(the)227 668 y(\014rst)32 b(8)h(c)m(haracters)h(of)e(the)h
+(template)h(line)e(are)h(blank)f(then)g(the)h(remainder)f(of)g(the)h
+(line)g(is)f(considered)227 781 y(to)42 b(b)s(e)e(a)h(FITS)f(commen)m
+(t)h(\(with)g(a)g(blank)f(k)m(eyw)m(ord)h(name\).)72
+b(A)41 b(legal)i(FITS)d(k)m(eyw)m(ord)h(name)f(ma)m(y)227
+894 y(only)35 b(con)m(tain)i(the)e(c)m(haracters)h(A-Z,)f(0-9,)j(and)c
+('-')i(\(min)m(us)f(sign\))g(and)f(underscore.)54 b(This)34
+b(subroutine)227 1007 y(will)42 b(automatically)i(con)m(v)m(ert)f(an)m
+(y)f(lo)m(w)m(ercase)i(c)m(haracters)e(to)h(upp)s(ercase)d(in)h(the)h
+(output)f(string.)73 b(If)227 1120 y(KEYNAME)33 b(=)f('COMMENT')h(or)g
+('HISTOR)-8 b(Y')32 b(then)h(the)f(remainder)g(of)h(the)g(line)g(is)g
+(considered)f(to)227 1233 y(b)s(e)e(a)h(FITS)e(COMMENT)h(or)h(HISTOR)-8
+b(Y)30 b(record,)g(resp)s(ectiv)m(ely)-8 b(.)0 1490 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 1603 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,)g(logical,)i(or)d(c)m(haracter)h(string\))f
+(is)227 1716 y(automatically)35 b(determined)c(and)h(the)g(output)f
+(CARD)h(string)g(is)g(formatted)g(accordingly)-8 b(.)47
+b(The)31 b(v)-5 b(alue)227 1829 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)g(as)h(a)g(string)g(\(e.g.)48
+b(if)33 b(it)g(is)f(a)h(string)g(of)f(n)m(umeric)h(digits\))g(b)m(y)227
+1942 y(enclosing)g(it)f(in)f(single)h(quotes.)45 b(If)31
+b(the)h(v)-5 b(alue)32 b(tok)m(en)g(is)g(a)g(c)m(haracter)h(string)e
+(that)i(con)m(tains)f(1)g(or)g(more)227 2055 y(em)m(b)s(edded)39
+b(blank)g(space)h(c)m(haracters)h(or)e(slash)h(\('/'\))h(c)m(haracters)
+g(then)e(the)g(en)m(tire)i(c)m(haracter)g(string)227
+2168 y(m)m(ust)31 b(b)s(e)e(enclosed)i(in)f(single)h(quotes.)0
+2425 y Fh(-)80 b Fi(The)28 b(COMMENT)g(tok)m(en)h(is)f(optional,)i(but)
+e(if)g(presen)m(t)g(m)m(ust)g(b)s(e)g(separated)g(from)g(the)h(V)-10
+b(ALUE)28 b(tok)m(en)h(b)m(y)227 2538 y(a)i(blank)f(space)h(or)f(a)h
+('/')g(c)m(haracter.)0 2796 y Fh(-)80 b Fi(One)32 b(exception)i(to)f
+(the)g(ab)s(o)m(v)m(e)h(rules)e(is)g(that)h(if)g(the)f(\014rst)g
+(non-blank)g(c)m(haracter)i(in)e(the)h(template)h(string)227
+2909 y(is)h(a)g(min)m(us)f(sign)h(\('-'\))h(follo)m(w)m(ed)g(b)m(y)f(a)
+g(single)g(tok)m(en,)i(or)e(a)g(single)g(tok)m(en)h(follo)m(w)m(ed)g(b)
+m(y)f(an)f(equal)i(sign,)227 3022 y(then)29 b(it)g(is)g(in)m(terpreted)
+f(as)h(the)g(name)g(of)g(a)g(k)m(eyw)m(ord)g(whic)m(h)f(is)h(to)g(b)s
+(e)f(deleted)i(from)e(the)h(FITS)f(header.)0 3279 y Fh(-)80
+b Fi(The)40 b(second)g(exception)h(is)f(that)h(if)f(the)g(template)h
+(string)f(starts)g(with)g(a)h(min)m(us)e(sign)h(and)f(is)h(follo)m(w)m
+(ed)227 3392 y(b)m(y)33 b(2)g(tok)m(ens)g(then)g(the)f(second)h(tok)m
+(en)h(is)e(in)m(terpreted)h(as)g(the)g(new)f(name)g(for)h(the)g(k)m
+(eyw)m(ord)g(sp)s(eci\014ed)227 3505 y(b)m(y)h(\014rst)e(tok)m(en.)52
+b(In)33 b(this)g(case)i(the)e(old)h(k)m(eyw)m(ord)g(name)g(\(\014rst)f
+(tok)m(en\))i(is)e(returned)g(in)g(c)m(haracters)i(1-8)227
+3618 y(of)e(the)g(returned)e(CARD)i(string,)g(and)f(the)h(new)f(k)m
+(eyw)m(ord)h(name)g(\(the)g(second)f(tok)m(en\))i(is)f(returned)e(in)
+227 3731 y(c)m(haracters)c(41-48)h(of)e(the)f(returned)g(CARD)g
+(string.)40 b(These)25 b(old)h(and)f(new)g(names)g(ma)m(y)h(then)f(b)s
+(e)g(passed)227 3844 y(to)31 b(the)g(FTMNAM)g(subroutine)f(whic)m(h)g
+(will)g(c)m(hange)i(the)e(k)m(eyw)m(ord)h(name.)0 4101
+y(The)f(HDTYPE)g(output)g(parameter)h(indicates)g(ho)m(w)g(the)f
+(returned)g(CARD)g(string)g(should)g(b)s(e)g(in)m(terpreted:)382
+4359 y Fe(hdtype)857 b(interpretation)382 4472 y(------)523
+b(-------------------------)o(----)o(---)o(----)o(----)o(---)o(----)o
+(--)525 4585 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 4698 y(to)g(the)g(new)g(name)g(given)f
+(in)h(CARD\(41:48\))525 4924 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
+5036 y(from)g(the)g(FITS)f(header.)573 5262 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
+5375 y(keyword)f(does)h(not)g(already)e(exist,)h(otherwise)g(update)
+1193 5488 y(the)h(value/comment)d(if)j(the)g(keyword)f(is)h(already)f
+(present)1193 5601 y(in)h(the)g(header.)p eop end
+%%Page: 74 80
+TeXDict begin 74 79 bop 0 299 a Fi(74)1319 b Fg(CHAPTER)29
+b(6.)112 b(AD)m(V)-10 b(ANCED)32 b(INTERF)-10 b(A)m(CE)30
+b(SUBR)m(OUTINES)573 555 y Fe(1)572 b(simply)46 b(append)g(this)h
+(keyword)f(to)h(the)g(FITS)g(header)f(\(CARD)1193 668
+y(is)h(either)f(a)i(HISTORY)e(or)h(COMMENT)f(keyword\).)573
+894 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 1007 y(to)g(the)g(FITS)g(header)f(because)g
+(FITSIO)g(automatically)1193 1120 y(appends)g(the)h(END)g(record)f
+(when)h(the)f(header)h(is)g(closed.)0 1380 y Fi(EXAMPLES:)30
+b(The)g(follo)m(wing)i(lines)e(illustrate)i(v)-5 b(alid)31
+b(input)e(template)j(strings:)286 1639 y Fe(INTVAL)46
+b(7)i(This)f(is)g(an)g(integer)f(keyword)286 1752 y(RVAL)524
+b(34.6)142 b(/)239 b(This)46 b(is)i(a)f(floating)f(point)g(keyword)286
+1865 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 1978 y(lval)i(F)g(This)g(is)
+g(a)h(boolean)e(keyword)859 2091 y(This)h(is)g(a)g(comment)f(keyword)g
+(with)h(a)g(blank)f(keyword)g(name)286 2204 y(SVAL1)h(=)g('Hello)f
+(world')142 b(/)95 b(this)47 b(is)g(a)g(string)f(keyword)286
+2317 y(SVAL2)94 b('123.5')g(this)47 b(is)g(also)f(a)i(string)e(keyword)
+286 2430 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 2543
+y(#)48 b(the)f(following)e(template)h(line)g(deletes)g(the)h(DATE)g
+(keyword)286 2655 y(-)h(DATE)286 2768 y(#)g(the)f(following)e(template)
+h(line)g(modifies)g(the)h(NAME)f(keyword)g(to)h(OBJECT)286
+2881 y(-)h(NAME)e(OBJECT)0 3141 y Fh(16)g Fi(P)m(arse)35
+b(the)g(input)f(string)h(con)m(taining)h(a)f(list)h(of)f(ro)m(ws)f(or)h
+(ro)m(w)g(ranges,)h(and)e(return)g(in)m(teger)i(arra)m(ys)f(con-)227
+3254 y(taining)27 b(the)f(\014rst)f(and)g(last)i(ro)m(w)f(in)f(eac)m(h)
+i(range.)40 b(F)-8 b(or)26 b(example,)i(if)d(ro)m(wlist)i(=)e("3-5,)k
+(6,)e(8-9")h(then)d(it)i(will)227 3367 y(return)34 b(n)m(umranges)h(=)g
+(3,)h(rangemin)f(=)g(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 3480 y(n)m(um)m(b)s(er)31
+b(of)h(ranges)f(will)h(b)s(e)g(returned.)43 b('maxro)m(ws')32
+b(is)g(the)g(maxim)m(um)g(n)m(um)m(b)s(er)e(of)i(ro)m(ws)g(in)f(the)h
+(table;)227 3593 y(an)m(y)e(ro)m(ws)f(or)g(ranges)g(larger)h(than)f
+(this)g(will)g(b)s(e)g(ignored.)40 b(The)29 b(ro)m(ws)g(m)m(ust)g(b)s
+(e)f(sp)s(eci\014ed)h(in)f(increasing)227 3706 y(order,)33
+b(and)f(the)g(ranges)h(m)m(ust)f(not)g(o)m(v)m(erlap.)48
+b(A)33 b(min)m(us)e(sign)i(ma)m(y)g(b)s(e)e(use)h(to)h(sp)s(ecify)f
+(all)h(the)g(ro)m(ws)f(to)227 3819 y(the)h(upp)s(er)d(or)j(lo)m(w)m(er)
+h(b)s(ound,)d(so)i("50-")h(means)e(all)i(the)f(ro)m(ws)f(from)g(50)h
+(to)h(the)e(end)g(of)h(the)f(table,)j(and)227 3931 y("-")d(means)e(all)
+h(the)g(ro)m(ws)f(in)g(the)h(table,)g(from)f(1)h(-)g(maxro)m(ws.)191
+4191 y Fe(FTRWRG\(rowlist,)44 b(maxrows,)h(maxranges,)g(>)525
+4304 y(numranges,)g(rangemin,)g(rangemax,)h(status\))p
+eop end
+%%Page: 75 81
+TeXDict begin 75 80 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
+614 2180 V 34 w(data)i(function)e(in)h(CFITSIO)e(pro)m(vides)i(a)g
+(unique)e(metho)s(d)i(of)g(executing)h(an)e(arbitrary)0
+2293 y(user-supplied)35 b(`w)m(ork')i(function)f(that)h(op)s(erates)g
+(on)g(ro)m(ws)f(of)h(data)g(in)f(FITS)g(tables)h(or)f(on)h(pixels)f(in)
+h(FITS)0 2406 y(images.)i(Rather)24 b(than)e(explicitly)j(reading)e
+(and)g(writing)g(the)g(FITS)g(images)h(or)f(columns)g(of)g(data,)i(one)
+f(instead)0 2518 y(calls)36 b(the)g(CFITSIO)d(iterator)k(routine,)g
+(passing)e(to)h(it)g(the)f(name)g(of)h(the)f(user's)g(w)m(ork)g
+(function)g(that)h(is)f(to)0 2631 y(b)s(e)30 b(executed)h(along)g(with)
+f(a)h(list)g(of)f(all)h(the)f(table)i(columns)e(or)g(image)h(arra)m(ys)
+g(that)g(are)f(to)h(b)s(e)f(passed)g(to)h(the)0 2744
+y(w)m(ork)37 b(function.)61 b(The)37 b(CFITSIO)e(iterator)k(function)e
+(then)g(do)s(es)g(all)h(the)f(w)m(ork)g(of)h(allo)s(cating)h(memory)e
+(for)0 2857 y(the)28 b(arra)m(ys,)h(reading)f(the)g(input)e(data)j
+(from)e(the)h(FITS)f(\014le,)h(passing)g(them)g(to)g(the)g(w)m(ork)g
+(function,)g(and)f(then)0 2970 y(writing)36 b(an)m(y)h(output)f(data)h
+(bac)m(k)h(to)f(the)f(FITS)g(\014le)g(after)h(the)g(w)m(ork)g(function)
+f(exits.)59 b(Because)38 b(it)f(is)g(often)0 3083 y(more)g(e\016cien)m
+(t)i(to)f(pro)s(cess)f(only)g(a)h(subset)f(of)g(the)g(total)i(table)g
+(ro)m(ws)e(at)h(one)f(time,)j(the)e(iterator)g(function)0
+3196 y(can)31 b(determine)f(the)h(optim)m(um)f(amoun)m(t)h(of)f(data)h
+(to)g(pass)f(in)g(eac)m(h)i(iteration)f(and)f(rep)s(eatedly)h(call)g
+(the)g(w)m(ork)0 3309 y(function)f(un)m(til)h(the)f(en)m(tire)i(table)f
+(b)s(een)e(pro)s(cessed.)0 3469 y(F)-8 b(or)37 b(man)m(y)f
+(applications)h(this)e(single)i(CFITSIO)d(iterator)k(function)d(can)h
+(e\013ectiv)m(ely)j(replace)e(all)g(the)f(other)0 3582
+y(CFITSIO)g(routines)i(for)f(reading)h(or)f(writing)h(data)g(in)f(FITS)
+g(images)i(or)e(tables.)64 b(Using)37 b(the)h(iterator)h(has)0
+3695 y(sev)m(eral)32 b(imp)s(ortan)m(t)e(adv)-5 b(an)m(tages)32
+b(o)m(v)m(er)g(the)f(traditional)g(metho)s(d)f(of)h(reading)f(and)g
+(writing)g(FITS)g(data)h(\014les:)136 3961 y Fc(\017)46
+b Fi(It)33 b(cleanly)h(separates)g(the)f(data)h(I/O)f(from)f(the)h
+(routine)g(that)h(op)s(erates)f(on)g(the)g(data.)49 b(This)32
+b(leads)h(to)227 4074 y(a)e(more)g(mo)s(dular)e(and)h(`ob)5
+b(ject)31 b(orien)m(ted')h(programming)e(st)m(yle.)136
+4268 y Fc(\017)46 b Fi(It)27 b(simpli\014es)f(the)h(application)h
+(program)f(b)m(y)f(eliminating)i(the)f(need)g(to)g(allo)s(cate)i
+(memory)e(for)f(the)h(data)227 4381 y(arra)m(ys)e(and)f(eliminates)i
+(most)e(of)h(the)f(calls)i(to)f(the)g(CFITSIO)d(routines)j(that)g
+(explicitly)h(read)e(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)h(as)e(p)s(ossible.)44
+b(This)31 b(is)g(esp)s(ecially)i(imp)s(ortan)m(t)227
+4801 y(when)44 b(pro)s(cessing)g(tabular)h(data)h(since)f(the)g
+(iterator)h(function)e(will)h(calculate)i(the)e(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)f(the)h(table)g(to)g
+(b)s(e)f(passed)g(at)i(one)e(time)i(to)f(the)g(user's)e(w)m(ork)i
+(function)f(on)h(eac)m(h)227 5027 y(iteration.)136 5222
+y Fc(\017)46 b Fi(Mak)m(es)39 b(it)e(p)s(ossible)g(for)g(larger)h(pro)5
+b(jects)37 b(to)h(dev)m(elop)g(a)g(library)e(of)i(w)m(ork)f(functions)f
+(that)i(all)g(ha)m(v)m(e)h(a)227 5335 y(uniform)29 b(calling)j
+(sequence)f(and)f(are)h(all)g(indep)s(enden)m(t)e(of)i(the)f(details)i
+(of)e(the)h(FITS)e(\014le)i(format.)0 5601 y(There)f(are)h(basically)h
+(2)g(steps)e(in)h(using)f(the)h(CFITSIO)e(iterator)j(function.)42
+b(The)30 b(\014rst)g(step)h(is)g(to)g(design)g(the)0
+5714 y(w)m(ork)26 b(function)f(itself)h(whic)m(h)f(m)m(ust)h(ha)m(v)m
+(e)g(a)g(prescrib)s(ed)e(set)i(of)g(input)f(parameters.)39
+b(One)25 b(of)h(these)g(parameters)1905 5942 y(75)p eop
+end
+%%Page: 76 82
+TeXDict begin 76 81 bop 0 299 a Fi(76)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)f(a)g(structure)g(con)m(taining)i(p)s(oin)m(ters)d(to)i
+(the)f(arra)m(ys)h(of)f(data;)h(the)f(w)m(ork)h(function)e(can)i(p)s
+(erform)d(an)m(y)i(desired)0 668 y(op)s(erations)k(on)h(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)e(data)i(w)m(ere)f(read)g(from)0 781 y(the)e(\014le)f(or)g
+(ho)m(w)h(the)f(output)g(data)h(get)h(written)e(bac)m(k)h(to)h(the)e
+(\014le.)0 941 y(The)24 b(second)h(step)g(is)f(to)i(design)e(the)h
+(driv)m(er)g(routine)f(that)i(op)s(ens)e(all)h(the)g(necessary)g(FITS)f
+(\014les)h(and)f(initializes)0 1054 y(the)41 b(input)g(parameters)g(to)
+h(the)g(iterator)g(function.)73 b(The)41 b(driv)m(er)g(program)g(calls)
+h(the)g(CFITSIO)e(iterator)0 1167 y(function)30 b(whic)m(h)g(then)g
+(reads)g(the)h(data)g(and)f(passes)g(it)h(to)g(the)g(user's)e(w)m(ork)i
+(function.)0 1327 y(F)-8 b(urther)41 b(details)i(on)f(using)f(the)h
+(iterator)h(function)f(can)g(b)s(e)f(found)f(in)i(the)g(companion)g
+(CFITSIO)e(User's)0 1440 y(Guide,)31 b(and)e(in)h(the)h(iter)p
+874 1440 28 4 v 33 w(a.f,)g(iter)p 1197 1440 V 34 w(b.f)f(and)f(iter)p
+1677 1440 V 34 w(c.f)h(example)h(programs.)p eop end
+%%Page: 77 83
+TeXDict begin 77 82 bop 0 1225 a Ff(Chapter)65 b(8)0
+1687 y Fl(Extended)77 b(File)g(Name)g(Syn)-6 b(tax)0
+2216 y Fd(8.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)g(the)
+h(name)f(of)h(the)g(data)g(\014le)f(to)h(b)s(e)f(op)s(ened)g(or)0
+2579 y(created)g(that)g(includes)f(the)h(follo)m(wing)h(features:)136
+2813 y Fc(\017)46 b Fi(CFITSIO)40 b(can)i(read)f(IRAF)h(format)g
+(images)g(whic)m(h)f(ha)m(v)m(e)i(header)e(\014le)h(names)f(that)h(end)
+f(with)g(the)227 2926 y('.imh')d(extension,)i(as)e(w)m(ell)g(as)g
+(reading)f(and)g(writing)g(FITS)g(\014les,)i(This)e(feature)h(is)f
+(implemen)m(ted)h(in)227 3039 y(CFITSIO)29 b(b)m(y)i(\014rst)e(con)m(v)
+m(erting)k(the)d(IRAF)h(image)h(in)m(to)f(a)g(temp)s(orary)f(FITS)g
+(format)h(\014le)f(in)g(memory)-8 b(,)227 3152 y(then)35
+b(op)s(ening)f(the)h(FITS)f(\014le.)54 b(An)m(y)35 b(of)g(the)g(usual)f
+(CFITSIO)g(routines)g(then)h(ma)m(y)g(b)s(e)f(used)g(to)i(read)227
+3265 y(the)31 b(image)g(header)f(or)h(data.)41 b(Similarly)-8
+b(,)31 b(ra)m(w)f(binary)g(data)h(arra)m(ys)f(can)h(b)s(e)f(read)g(b)m
+(y)g(con)m(v)m(erting)i(them)227 3378 y(on)f(the)f(\015y)g(in)m(to)h
+(virtual)g(FITS)f(images.)136 3557 y Fc(\017)46 b Fi(FITS)37
+b(\014les)g(on)g(the)g(In)m(ternet)h(can)f(b)s(e)g(read)g(\(and)g
+(sometimes)h(written\))f(using)g(the)g(FTP)-8 b(,)38
+b(HTTP)-8 b(,)37 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)g(can)h(b)s(e)f(pip)s(ed)f(b)s
+(et)m(w)m(een)i(tasks)f(on)h(the)f(stdin)g(and)g(stdout)g(streams.)136
+4028 y Fc(\017)46 b Fi(FITS)20 b(\014les)h(can)g(b)s(e)f(read)g(and)g
+(written)h(in)f(shared)g(memory)-8 b(.)38 b(This)20 b(can)h(p)s(oten)m
+(tially)h(ac)m(hiev)m(e)h(m)m(uc)m(h)e(b)s(etter)227
+4141 y(data)26 b(I/O)e(p)s(erformance)g(compared)h(to)h(reading)f(and)f
+(writing)g(the)h(same)h(FITS)e(\014les)g(on)h(magnetic)h(disk.)136
+4320 y Fc(\017)46 b Fi(Compressed)30 b(FITS)f(\014les)i(in)f(gzip)h(or)
+f(Unix)g(COMPRESS)f(format)h(can)h(b)s(e)f(directly)h(read.)136
+4499 y Fc(\017)46 b Fi(Output)28 b(FITS)h(\014les)g(can)g(b)s(e)g
+(written)g(directly)h(in)e(compressed)h(gzip)h(format,)g(th)m(us)e(sa)m
+(ving)i(disk)f(space.)136 4678 y Fc(\017)46 b Fi(FITS)26
+b(table)h(columns)f(can)h(b)s(e)f(created,)i(mo)s(di\014ed,)f(or)f
+(deleted)h('on-the-\015y')g(as)g(the)g(table)g(is)f(op)s(ened)g(b)m(y)
+227 4791 y(CFITSIO.)32 b(This)h(creates)i(a)e(virtual)h(FITS)f(\014le)g
+(con)m(taining)i(the)f(mo)s(di\014cations)f(that)h(is)g(then)f(op)s
+(ened)227 4904 y(b)m(y)e(the)f(application)i(program.)136
+5083 y Fc(\017)46 b Fi(T)-8 b(able)29 b(ro)m(ws)e(ma)m(y)i(b)s(e)e
+(selected,)j(or)e(\014ltered)g(out,)g(on)g(the)g(\015y)f(when)g(the)h
+(table)h(is)f(op)s(ened)f(b)m(y)g(CFITSIO,)227 5196 y(based)f(on)h(an)f
+(arbitrary)h(user-sp)s(eci\014ed)e(expression.)39 b(Only)26
+b(ro)m(ws)h(for)f(whic)m(h)g(the)h(expression)f(ev)-5
+b(aluates)227 5309 y(to)31 b('TR)m(UE')g(are)g(retained)g(in)f(the)g
+(cop)m(y)i(of)e(the)h(table)g(that)g(is)f(op)s(ened)g(b)m(y)g(the)h
+(application)g(program.)136 5488 y Fc(\017)46 b Fi(Histogram)28
+b(images)g(ma)m(y)f(b)s(e)f(created)h(on)f(the)h(\015y)f(b)m(y)g
+(binning)g(the)g(v)-5 b(alues)27 b(in)f(table)i(columns,)f(resulting)
+227 5601 y(in)36 b(a)g(virtual)h(N-dimensional)f(FITS)g(image.)59
+b(The)35 b(application)i(program)f(then)g(only)g(sees)g(the)h(FITS)227
+5714 y(image)32 b(\(in)e(the)h(primary)e(arra)m(y\))j(instead)e(of)h
+(the)f(original)i(FITS)d(table.)1905 5942 y(77)p eop
+end
+%%Page: 78 84
+TeXDict begin 78 83 bop 0 299 a Fi(78)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fi(The)43 b(latter)i(3)f(features)g(in)f(particular)h(add)f(v)m
+(ery)h(p)s(o)m(w)m(erful)f(data)h(pro)s(cessing)f(capabilities)j
+(directly)e(in)m(to)0 668 y(CFITSIO,)29 b(and)g(hence)h(in)m(to)h(ev)m
+(ery)f(task)h(that)f(uses)g(CFITSIO)e(to)j(read)f(or)g(write)g(FITS)f
+(\014les.)40 b(F)-8 b(or)31 b(example,)0 781 y(these)d(features)f
+(transform)f(a)i(v)m(ery)f(simple)g(program)g(that)h(just)f(copies)h
+(an)f(input)f(FITS)g(\014le)h(to)h(a)g(new)e(output)0
+894 y(\014le)36 b(\(lik)m(e)h(the)f(`\014tscop)m(y')h(program)f(that)g
+(is)g(distributed)f(with)g(CFITSIO\))g(in)m(to)i(a)f(m)m(ultipurp)s
+(ose)f(FITS)g(\014le)0 1007 y(pro)s(cessing)24 b(to)s(ol.)40
+b(By)25 b(app)s(ending)f(fairly)g(simple)h(quali\014ers)g(on)m(to)g
+(the)g(name)g(of)g(the)g(input)f(FITS)g(\014le,)i(the)f(user)0
+1120 y(can)37 b(p)s(erform)f(quite)i(complex)g(table)g(editing)g(op)s
+(erations)f(\(e.g.,)k(create)e(new)d(columns,)j(or)e(\014lter)h(out)f
+(ro)m(ws)0 1233 y(in)g(a)g(table\))h(or)f(create)h(FITS)f(images)h(b)m
+(y)f(binning)e(or)i(histogramming)h(the)f(v)-5 b(alues)37
+b(in)g(table)h(columns.)60 b(In)0 1346 y(addition,)33
+b(these)g(functions)e(ha)m(v)m(e)j(b)s(een)d(co)s(ded)h(using)f(new)h
+(state-of-the)i(art)f(algorithms)g(that)g(are,)g(in)f(some)0
+1458 y(cases,)g(10)f(-)f(100)i(times)f(faster)g(than)f(previous)g
+(widely)g(used)g(implemen)m(tations.)0 1619 y(Before)k(describing)f
+(the)h(complete)h(syn)m(tax)f(for)f(the)h(extended)f(FITS)g(\014le)g
+(names)g(in)g(the)h(next)g(section,)h(here)0 1732 y(are)c(a)g(few)f
+(examples)h(of)f(FITS)g(\014le)g(names)h(that)f(giv)m(e)i(a)f(quic)m(k)
+g(o)m(v)m(erview)h(of)f(the)f(allo)m(w)m(ed)i(syn)m(tax:)136
+1960 y Fc(\017)46 b Fe('myfile.fits')p Fi(:)37 b(the)31
+b(simplest)f(case)i(of)e(a)h(FITS)f(\014le)g(on)h(disk)e(in)i(the)f
+(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)
+i(\014le)e(and)f(con)m(v)m(erts)i(it)g(on)f(the)g(\015y)f(in)m(to)i(a)f
+(temp)s(orary)227 2250 y(FITS)h(format)h(image)g(in)f(memory)h(whic)m
+(h)f(can)g(then)g(b)s(e)g(read)g(with)g(an)m(y)h(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)e(data)i(arra)m(y)g(\(a)g
+(512)g(x)f(512)i(short)e(in)m(teger)h(arra)m(y)g(in)227
+2540 y(this)i(case\))i(and)d(con)m(v)m(erts)j(it)e(on)g(the)g(\015y)g
+(in)m(to)h(a)f(temp)s(orary)g(FITS)f(format)h(image)i(in)d(memory)h
+(whic)m(h)227 2652 y(can)e(then)f(b)s(e)g(read)g(with)g(an)m(y)h(other)
+f(CFITSIO)f(routine.)136 2830 y Fc(\017)46 b Fe(myfile.fits.gz)p
+Fi(:)d(if)33 b(this)g(is)g(the)g(name)g(of)h(a)f(new)g(output)g
+(\014le,)h(the)f('.gz')i(su\016x)d(will)h(cause)h(it)g(to)g(b)s(e)227
+2942 y(compressed)c(in)g(gzip)h(format)g(when)e(it)i(is)g(written)f(to)
+h(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)e(\014le)
+i(m)m(y\014le.\014ts)f(then)227 3232 y(mo)m(v)m(es)34
+b(to)f(the)f(extension)h(whic)m(h)f(has)f(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)g
+(sign\))h(signi\014es)f(that)h(the)g(input)f(\014le)g(is)h(to)g(b)s(e)f
+(read)g(from)g(the)h(stdin)f(\014le)g(stream,)227 3635
+y(or)h(that)g(the)f(output)g(\014le)h(is)f(to)h(b)s(e)f(written)g(to)h
+(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)g(in)g(an)m(y)g(ftp)g(arc)m(hiv)m(e)i(site)
+f(on)f(the)227 3925 y(In)m(ternet)j(ma)m(y)g(b)s(e)f(directly)h(op)s
+(ened)e(with)h(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)35 b(URL)f(to)h(a)f(FITS)g(\014le)
+g(on)227 4215 y(the)d(W)-8 b(eb)31 b(ma)m(y)g(b)s(e)f(op)s(ened)f(with)
+h(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)24 b(to)g(ftp)f(access)i(except)g(that)f(it)g(pro-)
+227 4505 y(vides)30 b(write)h(as)f(w)m(ell)h(as)g(read)f(access)h(to)g
+(the)f(\014les)h(across)f(the)h(net)m(w)m(ork.)41 b(This)29
+b(uses)h(the)h(ro)s(ot)f(proto)s(col)227 4618 y(dev)m(elop)s(ed)h(at)g
+(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)i(in)f(a)g(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)i(in)e(core)i
+(computer)f(memory)-8 b(.)62 b(The)37 b(resulting)g('\014le')h(will)227
+5198 y(disapp)s(ear)25 b(when)f(the)i(program)f(exits,)i(so)f(this)f
+(is)h(mainly)f(useful)g(for)g(testing)i(purp)s(oses)c(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)i(con)m(tained)f(in)f(the)h(10th)f(ro)
+m(w)h(of)227 5601 y(the)26 b('Images')i(column)d(in)h(the)g(binary)g
+(table)g(in)g(the)g(3th)h(extension)f(of)g(the)h(FITS)e(\014le.)39
+b(The)26 b(application)227 5714 y(just)k(sees)h(this)f(single)h(image)h
+(as)e(the)h(primary)e(arra)m(y)-8 b(.)p eop end
+%%Page: 79 85
+TeXDict begin 79 84 bop 0 299 a Fg(8.1.)72 b(O)m(VER)-10
+b(VIEW)3086 b Fi(79)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)h(of)e(the)h(input)f
+(image)i(ranging)f(from)f(the)227 668 y(1st)26 b(to)g(the)f(512th)h
+(pixel)g(in)e(X)i(and)e(Y,)i(and)e(selects)j(ev)m(ery)e(second)h(pixel)
+f(in)g(b)s(oth)f(dimensions,)i(resulting)227 781 y(in)k(a)h(256)h(x)e
+(256)i(pixel)e(image)i(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)f(on)f(the)g(\015y)g(\(in)g(memory)g(or)g(on)h
+(disk\))f(that)g(is)h(iden)m(tical)h(to)f(m)m(y\014le.\014ts)f(except)h
+(that)g(it)g(will)g(con)m(tain)227 1207 y(a)41 b(new)f(column)g(in)h
+(the)f(EVENTS)g(extension)h(called)h('Rad')f(whose)f(v)-5
+b(alue)41 b(is)f(computed)h(using)f(the)227 1320 y(indicated)31
+b(expression)f(whic)m(h)g(is)h(a)g(function)f(of)g(the)h(v)-5
+b(alues)30 b(in)h(the)f(X)h(and)e(Y)i(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)g(that)h(is)g(iden)m(ti-)227 1633 y(cal)k(to)g('m)m
+(y\014le.\014ts')f(except)h(that)f(the)g(EVENTS)f(table)i(will)f(only)g
+(con)m(tain)h(the)f(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)g(greater)i(than)e(5.)40
+b(In)27 b(general,)i(an)m(y)f(arbitrary)f(b)s(o)s(olean)h(expression)f
+(using)g(a)h(C)f(or)227 1859 y(F)-8 b(ortran-lik)m(e)31
+b(syn)m(tax,)e(whic)m(h)f(ma)m(y)h(com)m(bine)g(AND)g(and)f(OR)f(op)s
+(erators,)i(ma)m(y)g(b)s(e)f(used)f(to)i(select)h(ro)m(ws)227
+1972 y(from)g(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)g(arra)m(y)227
+2285 y(image)c(whic)m(h)f(is)g(computed)f(on)h(the)g(\015y)f(b)m(y)g
+(binning)g(\(i.e,)j(computing)d(the)h(2-dimensional)h(histogram\))227
+2398 y(of)k(the)f(v)-5 b(alues)34 b(in)f(the)h(X)g(and)e(Y)i(columns)f
+(of)h(the)f(EVENTS)g(extension.)50 b(In)33 b(this)g(case)i(the)e(X)h
+(and)f(Y)227 2511 y(co)s(ordinates)h(range)g(from)f(1)h(to)g(2048)h
+(and)e(the)h(image)g(pixel)g(size)g(is)g(4)f(units)g(in)g(b)s(oth)g
+(dimensions,)h(so)227 2624 y(the)d(resulting)f(image)i(is)e(512)i(x)e
+(512)i(pixels)f(in)f(size.)136 2824 y Fc(\017)46 b Fi(The)31
+b(\014nal)g(example)i(com)m(bines)f(man)m(y)f(of)h(these)g(feature)g
+(in)m(to)g(one)g(complex)g(expression)f(\(it)i(is)e(brok)m(en)227
+2937 y(in)m(to)h(sev)m(eral)f(lines)g(for)f(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)h(case,)j
+(CFITSIO)36 b(\(1\))j(copies)g(and)e(uncompresses)g(the)h(FITS)f
+(\014le)h(from)f(the)h(ftp)f(site)i(on)f(the)227 3814
+y(legacy)g(mac)m(hine,)h(\(2\))e(mo)m(v)m(es)g(to)g(the)g('EVENTS')f
+(extension,)i(\(3\))f(calculates)i(a)d(new)g(column)g(called)227
+3927 y('phacorr',)30 b(\(4\))f(selects)h(the)f(ro)m(ws)g(in)f(the)h
+(table)h(that)f(ha)m(v)m(e)h(phacorr)e(in)g(the)h(range)g(5)g(to)h(14,)
+g(and)e(\014nally)227 4040 y(\(5\))35 b(bins)d(the)h(remaining)g(ro)m
+(ws)g(on)h(the)f(X)g(and)g(Y)g(column)g(co)s(ordinates,)i(using)d(a)i
+(pixel)f(size)h(=)f(32)h(to)227 4153 y(create)d(a)f(2D)g(image.)42
+b(All)30 b(this)f(pro)s(cessing)g(is)h(completely)h(transparen)m(t)e
+(to)i(the)e(application)i(program,)227 4266 y(whic)m(h)f(simply)g(sees)
+h(the)g(\014nal)f(2-D)h(image)h(in)e(the)g(primary)g(arra)m(y)h(of)f
+(the)h(op)s(ened)f(\014le.)0 4538 y(The)c(full)h(extended)g(CFITSIO)e
+(FITS)h(\014le)h(name)g(can)g(con)m(tain)h(sev)m(eral)g(di\013eren)m(t)
+g(comp)s(onen)m(ts)f(dep)s(ending)e(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)e
+(in)h(the)g(follo)m(wing)i(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 end
+%%Page: 80 86
+TeXDict begin 80 85 bop 0 299 a Fi(80)1618 b Fg(CHAPTER)30
+b(8.)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,)k(BaseFilename,)i(outName,)e(HDUlo)
+s(cation,)i(and)41 b(ImageSection)i(comp)s(onen)m(ts,)i(if)d(presen)m
+(t,)0 668 y(m)m(ust)30 b(b)s(e)g(giv)m(en)i(in)e(that)h(order,)g(but)f
+(the)g(colFilter,)j(ro)m(wFilter,)g(and)c(binSp)s(ec)h(sp)s(eci\014ers)
+f(ma)m(y)j(follo)m(w)f(in)g(an)m(y)0 781 y(order.)39
+b(Regardless)29 b(of)g(the)f(order,)g(ho)m(w)m(ev)m(er,)i(the)f
+(colFilter)h(sp)s(eci\014er,)e(if)g(presen)m(t,)h(will)g(b)s(e)e(pro)s
+(cessed)h(\014rst)f(b)m(y)0 894 y(CFITSIO,)i(follo)m(w)m(ed)j(b)m(y)e
+(the)h(ro)m(wFilter)h(sp)s(eci\014er,)e(and)f(\014nally)i(b)m(y)f(the)g
+(binSp)s(ec)f(sp)s(eci\014er.)0 1253 y Fd(8.2)135 b(Filet)l(yp)t(e)0
+1508 y Fi(The)37 b(t)m(yp)s(e)g(of)g(\014le)g(determines)g(the)g
+(medium)f(on)h(whic)m(h)g(the)g(\014le)g(is)h(lo)s(cated)g(\(e.g.,)i
+(disk)d(or)g(net)m(w)m(ork\))h(and,)0 1621 y(hence,)f(whic)m(h)e(in)m
+(ternal)h(device)g(driv)m(er)f(is)g(used)f(b)m(y)h(CFITSIO)f(to)i(read)
+f(and/or)g(write)g(the)g(\014le.)56 b(Curren)m(tly)0
+1734 y(supp)s(orted)29 b(t)m(yp)s(es)h(are)382 2015 y
+Fe(file://)93 b(-)48 b(file)e(on)i(local)e(magnetic)g(disk)g
+(\(default\))382 2128 y(ftp://)141 b(-)48 b(a)f(readonly)f(file)g
+(accessed)g(with)h(the)g(anonymous)e(FTP)i(protocol.)907
+2241 y(It)g(also)g(supports)93 b(ftp://username:password@)o(host)o(nam)
+o(e/..)o(.)907 2354 y(for)47 b(accessing)e(password-protected)e(ftp)k
+(sites.)382 2467 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 2579 y(supports)45
+b(username:password)e(just)k(like)g(the)g(ftp)g(driver.)907
+2692 y(Proxy)f(HTTP)h(servers)f(are)h(supported)e(using)h(the)h
+(http_proxy)907 2805 y(environment)e(variable)g(\(see)i(following)e
+(note\).)286 2918 y(stream://)93 b(-)48 b(special)e(driver)g(to)h(read)
+g(an)g(input)f(FITS)h(file)f(from)h(the)g(stdin)907 3031
+y(stream,)f(and/or)g(write)g(an)h(output)f(FITS)h(file)g(to)g(the)g
+(stdout)143 3144 y(stream.)94 b(This)46 b(driver)g(is)i(fragile)d(and)i
+(has)g(limited)143 3257 y(functionality)d(\(see)j(the)g(following)e
+(note\).)286 3370 y(gsiftp://)93 b(-)48 b(access)e(files)g(on)h(a)h
+(computational)c(grid)j(using)f(the)h(gridftp)907 3483
+y(protocol)e(in)j(the)e(Globus)h(toolkit)e(\(see)i(following)e(note\).)
+382 3596 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 3709 y(reading)f(files)g(over)h
+(the)g(network.)382 3821 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
+3934 y(shared)f(memory.)382 4047 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 4160 y(disappears)e(when)h(the)h(program)f(exits)h
+(so)g(this)f(is)i(mainly)907 4273 y(useful)e(for)h(test)f(purposes)g
+(when)h(a)g(permanent)e(output)h(file)907 4386 y(is)h(not)g(desired.)0
+4667 y Fi(If)35 b(the)h(\014let)m(yp)s(e)g(is)f(not)h(sp)s(eci\014ed,)h
+(then)e(t)m(yp)s(e)h(\014le://)h(is)e(assumed.)56 b(The)35
+b(double)g(slashes)h('//')h(are)f(optional)0 4780 y(and)30
+b(ma)m(y)h(b)s(e)e(omitted)j(in)e(most)h(cases.)0 5096
+y Fb(8.2.1)112 b(Notes)37 b(ab)s(out)i(HTTP)d(pro)m(xy)i(serv)m(ers)0
+5320 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)f(the)h(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 5433 y(serv)m(er)f(with)f(the)g(h)m
+(ttp)p 801 5433 28 4 v 33 w(pro)m(xy)g(en)m(vironmen)m(t)h(v)-5
+b(ariable.)42 b(F)-8 b(or)31 b(example)191 5714 y Fe(setenv)46
+b(http_proxy)f(http://heasarc.gsfc.nasa)o(.gov)o(:312)o(8)p
+eop end
+%%Page: 81 87
+TeXDict begin 81 86 bop 0 299 a Fg(8.2.)72 b(FILETYPE)3128
+b Fi(81)0 555 y(will)38 b(cause)g(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)g(a)
+g(FITS)f(\014le)0 668 y(with)30 b(HTTP)-8 b(.)0 987 y
+Fb(8.2.2)112 b(Notes)37 b(ab)s(out)i(the)e(stream)h(\014let)m(yp)s(e)g
+(driv)m(er)0 1212 y Fi(The)e(stream)h(driv)m(er)f(can)h(b)s(e)f(used)g
+(to)h(e\016cien)m(tly)i(read)d(a)h(FITS)f(\014le)h(from)f(the)h(stdin)f
+(\014le)g(stream)h(or)g(write)0 1324 y(a)44 b(FITS)e(to)i(the)g(stdout)
+f(\014le)g(stream.)80 b(Ho)m(w)m(ev)m(er,)49 b(b)s(ecause)43
+b(these)h(input)e(and)h(output)g(streams)g(m)m(ust)h(b)s(e)0
+1437 y(accessed)30 b(sequen)m(tially)-8 b(,)31 b(the)e(FITS)f(\014le)g
+(reading)h(or)f(writing)h(application)h(m)m(ust)e(also)i(read)e(and)g
+(write)h(the)g(\014le)0 1550 y(sequen)m(tially)-8 b(,)33
+b(at)e(least)g(within)f(the)h(tolerances)h(describ)s(ed)d(b)s(elo)m(w.)
+0 1710 y(CFITSIO)34 b(supp)s(orts)f(2)j(di\013eren)m(t)f(metho)s(ds)g
+(for)g(accessing)i(FITS)d(\014les)h(on)h(the)f(stdin)g(and)f(stdout)h
+(streams.)0 1823 y(The)c(original)i(metho)s(d,)f(whic)m(h)f(is)h(in)m
+(v)m(ok)m(ed)h(b)m(y)f(sp)s(ecifying)f(a)h(dash)f(c)m(haracter,)j("-",)
+g(as)d(the)h(name)g(of)g(the)g(\014le)0 1936 y(when)g(op)s(ening)g(or)h
+(creating)h(it,)g(w)m(orks)e(b)m(y)h(storing)g(a)g(complete)h(cop)m(y)g
+(of)f(the)g(en)m(tire)g(FITS)f(\014le)h(in)f(memory)-8
+b(.)0 2049 y(In)35 b(this)g(case,)k(when)34 b(reading)i(from)f(stdin,)i
+(CFITSIO)d(will)i(cop)m(y)h(the)e(en)m(tire)i(stream)f(in)m(to)h
+(memory)e(b)s(efore)0 2162 y(doing)c(an)m(y)h(pro)s(cessing)f(of)h(the)
+f(\014le.)44 b(Similarly)-8 b(,)32 b(when)f(writing)g(to)h(stdout,)g
+(CFITSIO)d(will)j(create)h(a)f(cop)m(y)g(of)0 2275 y(the)h(en)m(tire)g
+(FITS)f(\014le)g(in)h(memory)-8 b(,)33 b(b)s(efore)f(\014nally)h
+(\015ushing)e(it)i(out)f(to)i(the)e(stdout)h(stream)g(when)e(the)i
+(FITS)0 2388 y(\014le)g(is)g(closed.)49 b(Bu\013ering)33
+b(the)g(en)m(tire)h(FITS)e(\014le)h(in)g(this)f(w)m(a)m(y)i(allo)m(ws)g
+(the)f(application)i(to)e(randomly)g(access)0 2501 y(an)m(y)h(part)f
+(of)h(the)f(FITS)g(\014le,)i(in)e(an)m(y)h(order,)f(but)g(it)h(also)h
+(requires)e(that)h(the)f(user)g(ha)m(v)m(e)i(su\016cien)m(t)f(a)m(v)-5
+b(ailable)0 2614 y(memory)30 b(\(or)g(virtual)g(memory\))g(to)h(store)f
+(the)g(en)m(tire)h(\014le,)f(whic)m(h)f(ma)m(y)i(not)f(b)s(e)f(p)s
+(ossible)g(in)h(the)g(case)h(of)f(v)m(ery)0 2727 y(large)h(\014les.)0
+2887 y(The)e(new)m(er)g(stream)h(\014let)m(yp)s(e)g(pro)m(vides)f(a)h
+(more)f(memory-e\016cien)m(t)i(metho)s(d)e(of)h(accessing)h(FITS)d
+(\014les)h(on)h(the)0 3000 y(stdin)37 b(or)h(stdout)g(streams.)64
+b(Instead)38 b(of)g(storing)g(a)g(cop)m(y)h(of)f(the)g(en)m(tire)h
+(FITS)e(\014le)h(in)g(memory)-8 b(,)40 b(CFITSIO)0 3113
+y(only)32 b(uses)g(a)g(set)h(of)f(in)m(ternal)h(bu\013er)e(whic)m(h)h
+(b)m(y)g(default)g(can)g(store)h(40)g(FITS)e(blo)s(c)m(ks,)i(or)g(ab)s
+(out)e(100K)i(b)m(ytes)0 3225 y(of)f(the)f(FITS)g(\014le.)43
+b(The)31 b(application)i(program)e(m)m(ust)g(pro)s(cess)g(the)h(FITS)e
+(\014le)i(sequen)m(tially)h(from)e(b)s(eginning)0 3338
+y(to)h(end,)e(within)g(this)h(100K)h(bu\013er.)41 b(Generally)32
+b(sp)s(eaking)f(the)g(application)h(program)f(m)m(ust)f(conform)h(to)h
+(the)0 3451 y(follo)m(wing)g(restrictions:)136 3735 y
+Fc(\017)46 b Fi(The)36 b(program)f(m)m(ust)h(\014nish)e(reading)i(or)g
+(writing)f(the)h(header)g(k)m(eyw)m(ords)g(b)s(efore)f(reading)h(or)g
+(writing)227 3848 y(an)m(y)31 b(data)g(in)f(the)h(HDU.)136
+4060 y Fc(\017)46 b Fi(The)24 b(HDU)h(can)f(con)m(tain)i(at)e(most)h
+(ab)s(out)f(1400)h(header)f(k)m(eyw)m(ords.)39 b(This)24
+b(is)g(the)g(maxim)m(um)g(that)h(can)f(\014t)227 4172
+y(in)g(the)g(nominal)h(40)g(FITS)e(blo)s(c)m(k)i(bu\013er.)37
+b(In)24 b(principle,)h(this)f(limit)h(could)f(b)s(e)g(increased)g(b)m
+(y)g(recompiling)227 4285 y(CFITSIO)29 b(with)h(a)h(larger)g(bu\013er)e
+(limit,)j(whic)m(h)e(is)g(set)h(b)m(y)f(the)h(NIOBUF)g(parameter)g(in)f
+(\014tsio2.h.)136 4497 y Fc(\017)46 b Fi(The)32 b(program)g(m)m(ust)f
+(read)h(or)g(write)h(the)f(data)g(in)g(a)g(sequen)m(tial)i(manner)d
+(from)h(the)g(b)s(eginning)f(to)i(the)227 4610 y(end)26
+b(of)g(the)h(HDU.)g(Note)h(that)f(CFITSIO's)e(in)m(ternal)i(100K)g
+(bu\013er)e(allo)m(ws)j(a)e(little)j(latitude)e(in)f(meeting)227
+4723 y(this)31 b(requiremen)m(t.)136 4934 y Fc(\017)46
+b Fi(The)30 b(program)g(cannot)h(mo)m(v)m(e)h(bac)m(k)f(to)g(a)g
+(previous)f(HDU)h(in)f(the)h(FITS)e(\014le.)136 5146
+y Fc(\017)46 b Fi(Reading)c(or)f(writing)f(of)h(v)-5
+b(ariable)42 b(length)f(arra)m(y)h(columns)e(in)h(binary)f(tables)i(is)
+f(not)g(supp)s(orted)e(on)227 5259 y(streams,)29 b(b)s(ecause)f(this)g
+(requires)g(mo)m(ving)g(bac)m(k)h(and)f(forth)f(b)s(et)m(w)m(een)i(the)
+f(\014xed-length)g(p)s(ortion)g(of)g(the)227 5372 y(binary)i(table)h
+(and)f(the)g(follo)m(wing)i(heap)e(area)i(where)e(the)g(arra)m(ys)h
+(are)g(actually)h(stored.)136 5583 y Fc(\017)46 b Fi(Reading)25
+b(or)g(writing)f(of)h(tile-compressed)h(images)g(is)e(not)h(supp)s
+(orted)e(on)h(streams,)i(b)s(ecause)f(the)g(images)227
+5696 y(are)31 b(in)m(ternally)g(stored)g(using)f(v)-5
+b(ariable)31 b(length)g(arra)m(ys.)p eop end
+%%Page: 82 88
+TeXDict begin 82 87 bop 0 299 a Fi(82)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fb(8.2.3)112 b(Notes)37 b(ab)s(out)i(the)e(gsiftp)h(\014let)m(yp)
+s(e)0 774 y Fi(DEPENDENCIES:)c(Globus)h(to)s(olkit)h(\(2.4.3)g(or)f
+(higher\))f(\(GT\))h(should)f(b)s(e)g(installed.)53 b(There)34
+b(are)h(t)m(w)m(o)h(dif-)0 887 y(feren)m(t)31 b(w)m(a)m(ys)g(to)g
+(install)g(GT:)0 1047 y(1\))43 b(goto)h(the)f(globus)f(to)s(olkit)i(w)m
+(eb)e(page)i(www.globus.org)e(and)g(follo)m(w)h(the)g(do)m(wnload)g
+(and)e(compilation)0 1160 y(instructions;)0 1320 y(2\))j(goto)i(the)d
+(Virtual)i(Data)g(T)-8 b(o)s(olkit)45 b(w)m(eb)e(page)i(h)m
+(ttp://vdt.cs.wisc.edu/)g(and)e(follo)m(w)i(the)f(instructions)0
+1433 y(\(STR)m(ONGL)-8 b(Y)31 b(SUGGESTED\);)0 1593 y(Once)23
+b(a)h(globus)f(clien)m(t)h(has)f(b)s(een)g(installed)h(in)e(y)m(our)i
+(system)f(with)g(a)g(sp)s(eci\014c)g(\015a)m(v)m(our)h(it)f(is)g(p)s
+(ossible)g(to)h(compile)0 1706 y(and)30 b(install)h(the)g(CFITSIO)d
+(libraries.)41 b(Sp)s(eci\014c)30 b(con\014guration)h(\015ags)f(m)m
+(ust)h(b)s(e)e(used:)0 1866 y(1\))21 b({with-gsiftp[[=P)-8
+b(A)g(TH]])22 b(Enable)f(Globus)f(T)-8 b(o)s(olkit)21
+b(gsiftp)g(proto)s(col)g(supp)s(ort)d(P)-8 b(A)g(TH=GLOBUS)p
+3532 1866 28 4 v 33 w(LOCA)g(TION)0 1979 y(i.e.)42 b(the)30
+b(lo)s(cation)i(of)f(y)m(our)f(globus)g(installation)0
+2139 y(2\))h({with-gsiftp-\015a)m(v)m(our[[=P)-8 b(A)g(TH])33
+b(de\014nes)d(the)g(sp)s(eci\014c)g(Globus)h(\015a)m(v)m(our)f(ex.)41
+b(gcc32)0 2300 y(Both)31 b(the)g(\015ags)f(m)m(ust)g(b)s(e)g(used)g
+(and)f(it)i(is)g(mandatory)f(to)h(set)g(b)s(oth)f(the)g(P)-8
+b(A)g(TH)31 b(and)f(the)h(\015a)m(v)m(our.)0 2460 y(USA)m(GE:)g(T)-8
+b(o)31 b(access)h(\014les)e(on)g(a)h(gridftp)f(serv)m(er)g(it)h(is)g
+(necessary)f(to)i(use)e(a)g(gsiftp)h(pre\014x:)0 2620
+y(example:)41 b(gsiftp://remote)p 1003 2620 V 35 w(serv)m(er)p
+1271 2620 V 34 w(fqhn/directory/\014lename)0 2780 y(The)f(gridftp)g
+(driv)m(er)g(uses)g(a)g(lo)s(cal)i(bu\013er)d(on)i(a)f(temp)s(orary)g
+(\014le)h(the)f(\014le)h(is)f(lo)s(cated)i(in)e(the)g(/tmp)h(direc-)0
+2893 y(tory)-8 b(.)73 b(If)40 b(y)m(ou)h(ha)m(v)m(e)h(sp)s(ecial)g(p)s
+(ermissions)d(on)i(/tmp)g(or)g(y)m(ou)g(do)f(not)i(ha)m(v)m(e)g(a)f
+(/tmp)g(directory)-8 b(,)44 b(it)e(is)e(p)s(os-)0 3006
+y(sible)d(to)h(force)g(another)g(lo)s(cation)g(setting)h(the)e(GSIFTP)p
+2068 3006 V 32 w(TMPFILE)g(en)m(vironmen)m(t)h(v)-5 b(ariable)38
+b(\(ex.)62 b(exp)s(ort)0 3119 y(GSIFTP)p 347 3119 V 32
+w(TMPFILE=/y)m(our/lo)s(cation/y)m(ourtmp\014le\).)0
+3279 y(Grid)34 b(FTP)g(supp)s(orts)f(m)m(ulti)h(c)m(hannel)h(transfer.)
+52 b(By)35 b(default)f(a)h(single)g(c)m(hannel)g(transmission)f(is)g(a)
+m(v)-5 b(ailable.)0 3392 y(Ho)m(w)m(ev)m(er,)34 b(it)d(is)h(p)s
+(ossible)e(to)i(mo)s(dify)e(this)i(b)s(eha)m(vior)f(setting)h(the)f
+(GSIFTP)p 2691 3392 V 33 w(STREAMS)f(en)m(vironmen)m(t)h(v)-5
+b(ari-)0 3505 y(able)31 b(\(ex.)41 b(exp)s(ort)30 b(GSIFTP)p
+1016 3505 V 33 w(STREAMS=8\).)0 3790 y Fb(8.2.4)112 b(Notes)37
+b(ab)s(out)i(the)e(ro)s(ot)g(\014let)m(yp)s(e)0 4009
+y Fi(The)20 b(original)j(ro)s(otd)d(serv)m(er)h(can)h(b)s(e)e(obtained)
+h(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 4122 y(it)33 b(to)h(w)m(ork)f(correctly)h(with)e
+(CFITSIO)g(one)h(has)f(to)i(use)e(a)i(mo)s(di\014ed)d(v)m(ersion)j
+(whic)m(h)e(supp)s(orts)f(a)i(command)0 4235 y(to)41
+b(return)d(the)j(length)f(of)g(the)g(\014le.)70 b(This)39
+b(mo)s(di\014ed)f(v)m(ersion)j(is)f(a)m(v)-5 b(ailable)42
+b(in)e(ro)s(otd)f(sub)s(directory)g(in)h(the)0 4348 y(CFITSIO)29
+b(ftp)h(area)h(at)286 4577 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
+4805 y Fi(This)j(small)g(serv)m(er)h(is)g(started)f(either)h(b)m(y)g
+(inetd)f(when)f(a)i(clien)m(t)h(requests)e(a)h(connection)h(to)f(a)f
+(ro)s(otd)h(serv)m(er)0 4918 y(or)30 b(b)m(y)g(hand)f(\(i.e.)42
+b(from)30 b(the)g(command)g(line\).)42 b(The)29 b(ro)s(otd)h(serv)m(er)
+h(w)m(orks)f(with)g(the)g(R)m(OOT)g(TNetFile)i(class.)0
+5031 y(It)e(allo)m(ws)g(remote)h(access)f(to)h(R)m(OOT)e(database)h
+(\014les)f(in)g(either)h(read)g(or)f(write)h(mo)s(de.)40
+b(By)30 b(default)f(TNetFile)0 5144 y(assumes)38 b(p)s(ort)g(432)h
+(\(whic)m(h)f(requires)g(ro)s(otd)g(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)h(inetd)f(add)g(the)0
+5257 y(follo)m(wing)32 b(line)f(to)g(/etc/services:)95
+5485 y Fe(rootd)238 b(432/tcp)0 5714 y Fi(and)30 b(to)h
+(/etc/inetd.conf,)i(add)d(the)g(follo)m(wing)i(line:)p
+eop end
+%%Page: 83 89
+TeXDict begin 83 88 bop 0 299 a Fg(8.2.)72 b(FILETYPE)3128
+b Fi(83)95 555 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 829 y
+Fi(F)-8 b(orce)34 b(inetd)e(to)i(reread)e(its)h(conf)f(\014le)h(with)f
+("kill)h(-HUP)g(<pid)f(inetd>".)47 b(Y)-8 b(ou)33 b(can)g(also)g(start)
+g(ro)s(otd)g(b)m(y)f(hand)0 942 y(running)j(directly)i(under)d(y)m(our)
+j(priv)-5 b(ate)37 b(accoun)m(t)g(\(no)g(ro)s(ot)g(system)f(privileges)
+h(needed\).)59 b(F)-8 b(or)37 b(example)g(to)0 1054 y(start)e(ro)s(otd)
+e(listening)i(on)f(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:)50 b(no)34 b(&)f(is)h(needed.)51
+b(Ro)s(otd)35 b(will)0 1167 y(go)c(in)m(to)h(bac)m(kground)e(b)m(y)g
+(itself.)95 1441 y Fe(Rootd)47 b(arguments:)191 1554
+y(-i)763 b(says)47 b(we)g(were)f(started)g(by)h(inetd)191
+1667 y(-p)g(port#)476 b(specifies)45 b(a)j(different)d(port)i(to)g
+(listen)f(on)191 1780 y(-d)h(level)476 b(level)46 b(of)i(debug)e(info)h
+(written)e(to)j(syslog)1050 1893 y(0)f(=)h(no)f(debug)f(\(default\))
+1050 2005 y(1)h(=)h(minimum)1050 2118 y(2)f(=)h(medium)1050
+2231 y(3)f(=)h(maximum)0 2505 y Fi(Ro)s(otd)29 b(can)f(also)h(b)s(e)f
+(con\014gured)g(for)g(anon)m(ymous)g(usage)h(\(lik)m(e)h(anon)m(ymous)e
+(ftp\).)40 b(T)-8 b(o)29 b(setup)f(ro)s(otd)g(to)h(accept)0
+2618 y(anon)m(ymous)h(logins)h(do)g(the)f(follo)m(wing)i(\(while)f(b)s
+(eing)f(logged)i(in)e(as)g(ro)s(ot\):)143 2891 y Fe(-)48
+b(Add)f(the)f(following)g(line)g(to)i(/etc/passwd:)239
+3117 y(rootd:*:71:72:Anonymous)41 b(rootd:/var/spool/rootd:/b)o(in/)o
+(fals)o(e)239 3343 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 3456
+y(to)h(suite)f(your)h(system.)143 3681 y(-)h(Add)f(the)f(following)g
+(line)g(to)i(/etc/group:)239 3907 y(rootd:*:72:rootd)239
+4133 y(where)e(the)h(gid)g(must)f(match)h(the)g(gid)g(in)g
+(/etc/passwd.)143 4359 y(-)h(Create)e(the)h(directories:)239
+4585 y(mkdir)f(/var/spool/rootd)239 4698 y(mkdir)g
+(/var/spool/rootd/tmp)239 4811 y(chmod)g(777)h(/var/spool/rootd/tmp)239
+5036 y(Where)f(/var/spool/rootd)d(must)k(match)f(the)h(rootd)g(home)f
+(directory)g(as)239 5149 y(specified)f(in)i(the)g(rootd)f(/etc/passwd)f
+(entry.)143 5375 y(-)j(To)f(make)f(writeable)g(directories)e(for)j
+(anonymous)f(do,)h(for)f(example:)239 5601 y(mkdir)g
+(/var/spool/rootd/pub)239 5714 y(chown)g(rootd:rootd)f
+(/var/spool/rootd/pub)p eop end
+%%Page: 84 90
+TeXDict begin 84 89 bop 0 299 a Fi(84)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fi(That's)42 b(all.)76 b(Sev)m(eral)43 b(additional)g(remarks:)64
+b(y)m(ou)42 b(can)g(login)h(to)g(an)f(anon)m(ymous)f(serv)m(er)i
+(either)f(with)g(the)0 668 y(names)31 b("anon)m(ymous")h(or)f("ro)s
+(otd".)43 b(The)31 b(passw)m(ord)f(should)g(b)s(e)h(of)g(t)m(yp)s(e)g
+(user@host.do.main.)43 b(Only)30 b(the)h(@)0 781 y(is)e(enforced)f(for)
+h(the)f(time)i(b)s(eing.)39 b(In)28 b(anon)m(ymous)h(mo)s(de)f(the)g
+(top)h(of)g(the)g(\014le)f(tree)i(is)e(set)h(to)h(the)e(ro)s(otd)h
+(home)0 894 y(directory)-8 b(,)39 b(therefore)e(only)f(\014les)h(b)s
+(elo)m(w)f(the)h(home)f(directory)h(can)f(b)s(e)g(accessed.)60
+b(Anon)m(ymous)36 b(mo)s(de)g(only)0 1007 y(w)m(orks)30
+b(when)g(the)g(serv)m(er)h(is)f(started)h(via)g(inetd.)0
+1296 y Fb(8.2.5)112 b(Notes)37 b(ab)s(out)i(the)e(shmem)i(\014let)m(yp)
+s(e:)0 1515 y Fi(Shared)34 b(memory)h(\014les)g(are)g(curren)m(tly)g
+(supp)s(orted)e(on)i(most)h(Unix)f(platforms,)h(where)f(the)g(shared)f
+(memory)0 1627 y(segmen)m(ts)d(are)g(managed)g(b)m(y)f(the)g(op)s
+(erating)h(system)g(k)m(ernel)f(and)g(`liv)m(e')i(indep)s(enden)m(tly)d
+(of)i(pro)s(cesses.)40 b(They)0 1740 y(are)34 b(not)g(deleted)h(\(b)m
+(y)f(default\))g(when)f(the)h(pro)s(cess)f(whic)m(h)h(created)h(them)f
+(terminates,)h(although)g(they)f(will)0 1853 y(disapp)s(ear)e(if)h(the)
+h(system)f(is)g(reb)s(o)s(oted.)49 b(Applications)34
+b(can)g(create)h(shared)d(memory)h(\014les)g(in)g(CFITSIO)f(b)m(y)0
+1966 y(calling:)143 2214 y Fe(fit_create_file\(&fitsfile)o(ptr,)41
+b("shmem://h2",)j(&status\);)0 2462 y Fi(where)25 b(the)g(ro)s(ot)h
+(`\014le')f(names)h(are)f(curren)m(tly)g(restricted)h(to)g(b)s(e)f
+('h0',)i('h1',)g('h2',)g('h3',)f(etc.,)i(up)d(to)g(a)h(maxim)m(um)0
+2575 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)22 b(of)f(SHARED)p 1746 2575 28 4 v 33 w(MAXSEG)g(\(equal)h(to)f
+(16)h(b)m(y)f(default\).)38 b(This)20 b(is)h(a)g(protot)m(yp)s(e)0
+2688 y(implemen)m(tation)30 b(of)f(the)g(shared)f(memory)g(in)m
+(terface)i(and)e(a)h(more)g(robust)f(in)m(terface,)j(whic)m(h)d(will)h
+(ha)m(v)m(e)h(few)m(er)0 2801 y(restrictions)h(on)f(the)h(n)m(um)m(b)s
+(er)e(of)i(\014les)f(and)g(on)g(their)g(names,)h(ma)m(y)g(b)s(e)f(dev)m
+(elop)s(ed)g(in)g(the)h(future.)0 2961 y(When)23 b(op)s(ening)h(an)f
+(already)h(existing)h(FITS)e(\014le)h(in)f(shared)g(memory)h(one)g
+(calls)g(the)g(usual)g(CFITSIO)e(routine:)143 3209 y
+Fe(fits_open_file\(&fitsfilep)o(tr,)41 b("shmem://h7",)j(mode,)j
+(&status\))0 3457 y Fi(The)26 b(\014le)h(mo)s(de)g(can)g(b)s(e)f(READ)m
+(WRITE)h(or)g(READONL)-8 b(Y)28 b(just)e(as)h(with)f(disk)h(\014les.)39
+b(More)28 b(than)e(one)h(pro)s(cess)0 3570 y(can)35 b(op)s(erate)g(on)f
+(READONL)-8 b(Y)35 b(mo)s(de)f(\014les)h(at)g(the)f(same)h(time.)54
+b(CFITSIO)33 b(supp)s(orts)f(prop)s(er)h(\014le)i(lo)s(c)m(king)0
+3682 y(\(b)s(oth)27 b(in)h(READONL)-8 b(Y)29 b(and)e(READ)m(WRITE)h(mo)
+s(des\),)h(so)f(calls)h(to)f(\014ts)p 2572 3682 V 33
+w(op)s(en)p 2795 3682 V 32 w(\014le)g(ma)m(y)g(b)s(e)f(lo)s(c)m(k)m(ed)
+j(out)e(un)m(til)0 3795 y(another)j(other)f(pro)s(cess)g(closes)i(the)e
+(\014le.)0 3956 y(When)g(an)g(application)i(is)e(\014nished)f
+(accessing)j(a)e(FITS)g(\014le)g(in)g(a)h(shared)e(memory)h(segmen)m
+(t,)i(it)f(ma)m(y)g(close)g(it)0 4068 y(\(and)j(the)g(\014le)g(will)g
+(remain)f(in)h(the)g(system\))g(with)g(\014ts)p 1955
+4068 V 32 w(close)p 2173 4068 V 34 w(\014le,)h(or)f(delete)h(it)g(with)
+e(\014ts)p 3191 4068 V 33 w(delete)p 3455 4068 V 34 w(\014le.)51
+b(Ph)m(ys-)0 4181 y(ical)36 b(deletion)g(is)f(p)s(ostp)s(oned)e(un)m
+(til)j(the)f(last)g(pro)s(cess)g(calls)h(\013clos/\013delt.)56
+b(\014ts)p 2801 4181 V 32 w(delete)p 3064 4181 V 34 w(\014le)35
+b(tries)h(to)f(obtain)h(a)0 4294 y(READ)m(WRITE)e(lo)s(c)m(k)g(on)f
+(the)g(\014le)h(to)g(b)s(e)e(deleted,)j(th)m(us)e(it)h(can)f(b)s(e)g
+(blo)s(c)m(k)m(ed)h(if)f(the)h(ob)5 b(ject)34 b(w)m(as)f(not)h(op)s
+(ened)0 4407 y(in)c(READ)m(WRITE)h(mo)s(de.)0 4567 y(A)i(shared)f
+(memory)h(managemen)m(t)h(utilit)m(y)g(program)f(called)h(`smem',)f(is)
+g(included)f(with)h(the)g(CFITSIO)e(dis-)0 4680 y(tribution.)39
+b(It)27 b(can)g(b)s(e)f(built)h(b)m(y)g(t)m(yping)g(`mak)m(e)h(smem';)g
+(then)f(t)m(yp)s(e)g(`smem)f(-h')h(to)h(get)g(a)f(list)g(of)g(v)-5
+b(alid)27 b(options.)0 4793 y(Executing)37 b(smem)f(without)g(an)m(y)h
+(options)g(causes)f(it)h(to)g(list)g(all)g(the)g(shared)e(memory)i
+(segmen)m(ts)g(curren)m(tly)0 4906 y(residing)c(in)g(the)g(system)h
+(and)e(managed)i(b)m(y)f(the)h(shared)e(memory)h(driv)m(er.)49
+b(T)-8 b(o)34 b(get)g(a)g(list)g(of)f(all)h(the)g(shared)0
+5019 y(memory)c(ob)5 b(jects,)32 b(run)d(the)h(system)h(utilit)m(y)g
+(program)f(`ip)s(cs)h([-a]'.)0 5351 y Fd(8.3)135 b(Base)46
+b(Filename)0 5601 y Fi(The)31 b(base)g(\014lename)h(is)f(the)h(name)f
+(of)h(the)f(\014le)h(optionally)g(including)f(the)h(director/sub)s
+(directory)f(path,)h(and)0 5714 y(in)e(the)h(case)g(of)g(`ftp',)f(`h)m
+(ttp',)i(and)d(`ro)s(ot')j(\014let)m(yp)s(es,)e(the)h(mac)m(hine)g
+(iden)m(ti\014er.)41 b(Examples:)p eop end
+%%Page: 85 91
+TeXDict begin 85 90 bop 0 299 a Fg(8.3.)72 b(BASE)30
+b(FILENAME)2830 b Fi(85)191 555 y Fe(myfile.fits)191
+668 y(!data.fits)191 781 y(/data/myfile.fits)191 894
+y(fits.gsfc.nasa.gov/ftp/s)o(ampl)o(eda)o(ta/m)o(yfil)o(e.f)o(its.)o
+(gz)0 1120 y Fi(When)29 b(creating)h(a)f(new)f(output)h(\014le)g(on)g
+(magnetic)h(disk)e(\(of)i(t)m(yp)s(e)f(\014le://\))h(if)f(the)g(base)g
+(\014lename)g(b)s(egins)f(with)0 1233 y(an)34 b(exclamation)j(p)s(oin)m
+(t)d(\(!\))54 b(then)34 b(an)m(y)g(existing)i(\014le)e(with)g(that)h
+(same)g(basename)g(will)g(b)s(e)e(deleted)i(prior)f(to)0
+1346 y(creating)h(the)f(new)g(FITS)f(\014le.)51 b(Otherwise)34
+b(if)g(the)g(\014le)g(to)g(b)s(e)g(created)h(already)f(exists,)i(then)d
+(CFITSIO)g(will)0 1459 y(return)g(an)h(error)f(and)g(will)i(not)f(o)m
+(v)m(erwrite)h(the)f(existing)h(\014le.)52 b(Note)35
+b(that)g(the)f(exclamation)i(p)s(oin)m(t,)f(')10 b(!',)36
+b(is)e(a)0 1572 y(sp)s(ecial)28 b(UNIX)g(c)m(haracter,)j(so)d(if)f(it)i
+(is)f(used)f(on)g(the)h(command)g(line)g(rather)g(than)f(en)m(tered)h
+(at)h(a)f(task)h(prompt,)0 1685 y(it)j(m)m(ust)f(b)s(e)g(preceded)g(b)m
+(y)h(a)g(bac)m(kslash)g(to)g(force)g(the)g(UNIX)g(shell)f(to)h(pass)f
+(it)i(v)m(erbatim)f(to)g(the)g(application)0 1798 y(program.)0
+1958 y(If)24 b(the)i(output)e(disk)h(\014le)g(name)g(ends)f(with)g(the)
+h(su\016x)f('.gz',)k(then)d(CFITSIO)e(will)i(compress)g(the)g(\014le)g
+(using)g(the)0 2071 y(gzip)g(compression)f(algorithm)h(b)s(efore)f
+(writing)g(it)h(to)g(disk.)38 b(This)23 b(can)i(reduce)f(the)g(amoun)m
+(t)h(of)f(disk)g(space)h(used)0 2184 y(b)m(y)34 b(the)h(\014le.)53
+b(Note)36 b(that)f(this)g(feature)g(requires)f(that)h(the)f
+(uncompressed)g(\014le)g(b)s(e)g(constructed)h(in)f(memory)0
+2297 y(b)s(efore)c(it)h(is)f(compressed)g(and)g(written)h(to)g(disk,)f
+(so)g(it)h(can)g(fail)g(if)f(there)h(is)f(insu\016cien)m(t)h(a)m(v)-5
+b(ailable)33 b(memory)-8 b(.)0 2457 y(An)45 b(input)g(FITS)f(\014le)i
+(ma)m(y)g(b)s(e)f(compressed)g(with)h(the)f(gzip)h(or)g(Unix)f
+(compress)h(algorithms,)k(in)45 b(whic)m(h)0 2570 y(case)38
+b(CFITSIO)e(will)i(uncompress)e(the)i(\014le)g(on)f(the)h(\015y)e(in)m
+(to)j(a)f(temp)s(orary)f(\014le)g(\(in)h(memory)f(or)g(on)h(disk\).)0
+2683 y(Compressed)32 b(\014les)i(ma)m(y)g(only)f(b)s(e)g(op)s(ened)f
+(with)h(read-only)h(p)s(ermission.)49 b(When)33 b(sp)s(ecifying)g(the)h
+(name)f(of)h(a)0 2796 y(compressed)h(FITS)g(\014le)h(it)g(is)g(not)g
+(necessary)g(to)g(app)s(end)e(the)i(\014le)g(su\016x)e(\(e.g.,)39
+b(`.gz')e(or)f(`.Z'\).)g(If)f(CFITSIO)0 2908 y(cannot)24
+b(\014nd)e(the)h(input)f(\014le)i(name)f(without)g(the)g(su\016x,)h
+(then)f(it)h(will)g(automatically)i(searc)m(h)e(for)f(a)g(compressed)0
+3021 y(\014le)36 b(with)f(the)h(same)g(ro)s(ot)g(name.)57
+b(In)35 b(the)h(case)h(of)f(reading)g(ftp)f(and)g(h)m(ttp)h(t)m(yp)s(e)
+g(\014les,)h(CFITSIO)e(generally)0 3134 y(lo)s(oks)j(for)g(a)g
+(compressed)g(v)m(ersion)g(of)g(the)g(\014le)g(\014rst,)h(b)s(efore)e
+(trying)h(to)h(op)s(en)e(the)h(uncompressed)e(\014le.)64
+b(By)0 3247 y(default,)37 b(CFITSIO)e(copies)h(\(and)g(uncompressed)e
+(if)i(necessary\))g(the)g(ftp)f(or)h(h)m(ttp)g(FITS)f(\014le)g(in)m(to)
+i(memory)0 3360 y(on)f(the)g(lo)s(cal)h(mac)m(hine)f(b)s(efore)g(op)s
+(ening)f(it.)58 b(This)35 b(will)h(fail)g(if)g(the)g(lo)s(cal)h(mac)m
+(hine)g(do)s(es)e(not)h(ha)m(v)m(e)h(enough)0 3473 y(memory)g(to)h
+(hold)f(the)g(whole)h(FITS)e(\014le,)k(so)d(in)g(this)g(case,)k(the)c
+(output)g(\014lename)g(sp)s(eci\014er)g(\(see)h(the)g(next)0
+3586 y(section\))32 b(can)f(b)s(e)e(used)h(to)h(further)e(con)m(trol)j
+(ho)m(w)e(CFITSIO)f(reads)h(ftp)g(and)g(h)m(ttp)g(\014les.)0
+3746 y(If)i(the)h(input)f(\014le)h(is)g(an)g(IRAF)g(image)h(\014le)f
+(\(*.imh)g(\014le\))h(then)e(CFITSIO)f(will)j(automatically)h(con)m(v)m
+(ert)g(it)e(on)0 3859 y(the)27 b(\015y)g(in)m(to)h(a)g(virtual)f(FITS)f
+(image)j(b)s(efore)e(it)g(is)g(op)s(ened)g(b)m(y)g(the)g(application)i
+(program.)39 b(IRAF)27 b(images)i(can)0 3972 y(only)h(b)s(e)g(op)s
+(ened)g(with)g(READONL)-8 b(Y)31 b(\014le)f(access.)0
+4132 y(Similarly)-8 b(,)32 b(if)f(the)g(input)f(\014le)i(is)f(a)g(ra)m
+(w)g(binary)f(data)i(arra)m(y)-8 b(,)33 b(then)d(CFITSIO)g(will)h(con)m
+(v)m(ert)i(it)e(on)g(the)h(\015y)e(in)m(to)0 4245 y(a)38
+b(virtual)g(FITS)g(image)h(with)e(the)h(basic)h(set)f(of)g(required)f
+(header)h(k)m(eyw)m(ords)g(b)s(efore)g(it)g(is)g(op)s(ened)f(b)m(y)h
+(the)0 4358 y(application)32 b(program)f(\(with)g(READONL)-8
+b(Y)31 b(access\).)44 b(In)30 b(this)h(case)h(the)f(data)g(t)m(yp)s(e)g
+(and)g(dimensions)f(of)h(the)0 4471 y(image)d(m)m(ust)f(b)s(e)f(sp)s
+(eci\014ed)g(in)h(square)g(brac)m(k)m(ets)h(follo)m(wing)g(the)f
+(\014lename)g(\(e.g.)41 b(ra)m(w\014le.dat[ib512,512]\).)j(The)0
+4584 y(\014rst)30 b(c)m(haracter)i(\(case)f(insensitiv)m(e\))h
+(de\014nes)e(the)g(datat)m(yp)s(e)h(of)g(the)g(arra)m(y:)239
+4810 y Fe(b)429 b(8-bit)46 b(unsigned)g(byte)239 4923
+y(i)381 b(16-bit)46 b(signed)g(integer)239 5036 y(u)381
+b(16-bit)46 b(unsigned)g(integer)239 5149 y(j)381 b(32-bit)46
+b(signed)g(integer)239 5262 y(r)h(or)g(f)143 b(32-bit)46
+b(floating)g(point)239 5375 y(d)381 b(64-bit)46 b(floating)g(point)0
+5601 y Fi(An)40 b(optional)h(second)f(c)m(haracter)i(sp)s(eci\014es)e
+(the)h(b)m(yte)f(order)g(of)g(the)h(arra)m(y)g(v)-5 b(alues:)60
+b(b)40 b(or)g(B)h(indicates)g(big)0 5714 y(endian)f(\(as)h(in)f(FITS)f
+(\014les)i(and)f(the)g(nativ)m(e)i(format)e(of)h(SUN)f(UNIX)h(w)m
+(orkstations)g(and)f(Mac)i(PCs\))e(and)p eop end
+%%Page: 86 92
+TeXDict begin 86 91 bop 0 299 a Fi(86)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fi(l)41 b(or)g(L)g(indicates)g(little)i(endian)e(\(nativ)m(e)h
+(format)g(of)f(DEC)f(OSF)h(w)m(orkstations)h(and)e(IBM)i(PCs\).)72
+b(If)40 b(this)0 668 y(c)m(haracter)32 b(is)e(omitted)i(then)e(the)g
+(arra)m(y)h(is)g(assumed)e(to)i(ha)m(v)m(e)h(the)f(nativ)m(e)g(b)m(yte)
+g(order)f(of)h(the)f(lo)s(cal)i(mac)m(hine.)0 781 y(These)d(datat)m(yp)
+s(e)h(c)m(haracters)h(are)e(then)g(follo)m(w)m(ed)i(b)m(y)e(a)h(series)
+f(of)g(one)h(or)f(more)g(in)m(teger)i(v)-5 b(alues)29
+b(separated)h(b)m(y)0 894 y(commas)h(whic)m(h)g(de\014ne)e(the)i(size)h
+(of)e(eac)m(h)i(dimension)e(of)h(the)g(ra)m(w)f(arra)m(y)-8
+b(.)43 b(Arra)m(ys)30 b(with)h(up)e(to)j(5)f(dimensions)0
+1007 y(are)f(curren)m(tly)g(supp)s(orted.)38 b(Finally)-8
+b(,)32 b(a)e(b)m(yte)g(o\013set)g(to)h(the)e(p)s(osition)h(of)g(the)g
+(\014rst)e(pixel)i(in)g(the)f(data)i(\014le)e(ma)m(y)0
+1120 y(b)s(e)d(sp)s(eci\014ed)g(b)m(y)h(separating)h(it)f(with)g(a)g
+(':')39 b(from)27 b(the)g(last)g(dimension)g(v)-5 b(alue.)40
+b(If)26 b(omitted,)j(it)e(is)g(assumed)f(that)0 1233
+y(the)35 b(o\013set)h(=)f(0.)54 b(This)35 b(parameter)g(ma)m(y)h(b)s(e)
+e(used)g(to)i(skip)e(o)m(v)m(er)i(an)m(y)g(header)e(information)i(in)e
+(the)h(\014le)g(that)0 1346 y(precedes)30 b(the)h(binary)f(data.)41
+b(F)-8 b(urther)30 b(examples:)95 1603 y Fe(raw.dat[b10000])521
+b(1-dimensional)45 b(10000)h(pixel)g(byte)h(array)95
+1715 y(raw.dat[rb400,400,12])233 b(3-dimensional)45 b(floating)g(point)
+h(big-endian)f(array)95 1828 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
+1941 y(a)i(FITS)e(file,)h(skipping)e(over)i(the)g(2880)g(byte)f(header)
+0 2198 y Fi(One)25 b(sp)s(ecial)g(case)h(of)f(input)f(\014le)h(is)g
+(where)g(the)g(\014lename)g(=)g(`-')h(\(a)f(dash)g(or)g(min)m(us)f
+(sign\))h(or)g('stdin')g(or)g('stdout',)0 2311 y(whic)m(h)d
+(signi\014es)h(that)h(the)f(input)e(\014le)i(is)g(to)h(b)s(e)e(read)g
+(from)h(the)g(stdin)f(stream,)j(or)e(written)f(to)i(the)f(stdout)g
+(stream)0 2424 y(if)34 b(a)g(new)g(output)f(\014le)h(is)g(b)s(eing)g
+(created.)52 b(In)33 b(the)h(case)h(of)f(reading)h(from)e(stdin,)h
+(CFITSIO)f(\014rst)g(copies)i(the)0 2537 y(whole)g(stream)h(in)m(to)g
+(a)f(temp)s(orary)g(FITS)f(\014le)i(\(in)f(memory)g(or)g(on)g(disk\),)h
+(and)f(subsequen)m(t)f(reading)h(of)h(the)0 2650 y(FITS)c(\014le)h(o)s
+(ccurs)g(in)f(this)h(cop)m(y)-8 b(.)49 b(When)33 b(writing)g(to)g
+(stdout,)h(CFITSIO)d(\014rst)h(constructs)h(the)g(whole)g(\014le)g(in)0
+2763 y(memory)h(\(since)i(random)d(access)j(is)e(required\),)i(then)e
+(\015ushes)f(it)i(out)g(to)g(the)f(stdout)h(stream)g(when)e(the)i
+(\014le)0 2876 y(is)30 b(closed.)42 b(In)29 b(addition,)i(if)f(the)g
+(output)g(\014lename)g(=)g('-.gz')i(or)e('stdout.gz')h(then)f(it)h
+(will)f(b)s(e)g(gzip)g(compressed)0 2989 y(b)s(efore)g(b)s(eing)g
+(written)g(to)h(stdout.)0 3149 y(This)25 b(abilit)m(y)j(to)e(read)g
+(and)f(write)h(on)g(the)g(stdin)g(and)f(stdout)h(steams)g(allo)m(ws)i
+(FITS)d(\014les)h(to)g(b)s(e)g(pip)s(ed)e(b)s(et)m(w)m(een)0
+3262 y(tasks)42 b(in)f(memory)g(rather)g(than)h(ha)m(ving)g(to)g
+(create)h(temp)s(orary)e(in)m(termediate)i(FITS)d(\014les)i(on)f(disk.)
+73 b(F)-8 b(or)0 3375 y(example)28 b(if)e(task1)i(creates)h(an)e
+(output)f(FITS)g(\014le,)i(and)f(task2)g(reads)g(an)g(input)f(FITS)g
+(\014le,)i(the)f(FITS)f(\014le)h(ma)m(y)0 3487 y(b)s(e)j(pip)s(ed)f(b)s
+(et)m(w)m(een)i(the)f(2)h(tasks)g(b)m(y)f(sp)s(ecifying)143
+3744 y Fe(task1)47 b(-)g(|)g(task2)g(-)0 4001 y Fi(where)30
+b(the)h(v)m(ertical)i(bar)e(is)f(the)h(Unix)g(piping)f(sym)m(b)s(ol.)42
+b(This)30 b(assumes)g(that)i(the)f(2)g(tasks)g(read)g(the)g(name)g(of)0
+4114 y(the)g(FITS)e(\014le)i(o\013)f(of)h(the)g(command)f(line.)0
+4448 y Fd(8.4)135 b(Output)45 b(File)g(Name)h(when)f(Op)t(ening)g(an)g
+(Existing)h(File)0 4698 y Fi(An)36 b(optional)i(output)e(\014lename)h
+(ma)m(y)h(b)s(e)e(sp)s(eci\014ed)g(in)g(paren)m(theses)h(immediately)h
+(follo)m(wing)g(the)f(base)g(\014le)0 4811 y(name)28
+b(to)h(b)s(e)f(op)s(ened.)39 b(This)28 b(is)g(mainly)g(useful)g(in)g
+(those)g(cases)i(where)d(CFITSIO)g(creates)j(a)e(temp)s(orary)g(cop)m
+(y)0 4924 y(of)i(the)f(input)g(FITS)f(\014le)i(b)s(efore)f(it)h(is)f
+(op)s(ened)g(and)f(passed)h(to)h(the)g(application)h(program.)40
+b(This)28 b(happ)s(ens)g(b)m(y)0 5036 y(default)i(when)g(op)s(ening)g
+(a)g(net)m(w)m(ork)h(FTP)g(or)f(HTTP-t)m(yp)s(e)g(\014le,)h(when)e
+(reading)h(a)h(compressed)f(FITS)g(\014le)g(on)0 5149
+y(a)36 b(lo)s(cal)h(disk,)g(when)e(reading)h(from)g(the)g(stdin)f
+(stream,)j(or)d(when)g(a)i(column)e(\014lter,)j(ro)m(w)e(\014lter,)h
+(or)f(binning)0 5262 y(sp)s(eci\014er)29 b(is)g(included)g(as)h(part)f
+(of)g(the)h(input)f(\014le)g(sp)s(eci\014cation.)41 b(By)30
+b(default)g(this)f(temp)s(orary)g(\014le)g(is)h(created)0
+5375 y(in)g(memory)-8 b(.)41 b(If)29 b(there)h(is)g(not)g(enough)g
+(memory)g(to)h(create)g(the)g(\014le)f(cop)m(y)-8 b(,)31
+b(then)f(CFITSIO)e(will)i(exit)h(with)f(an)0 5488 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)g(to)h(b)s(e)e(created)i(on)f(disk,)g(instead)h(of)f(a)g(temp)s
+(orary)0 5601 y(\014le)38 b(in)f(memory)-8 b(,)40 b(b)m(y)d(supplying)f
+(the)i(name)g(in)f(paren)m(theses)h(immediately)h(follo)m(wing)g(the)e
+(base)h(\014le)g(name.)0 5714 y(The)30 b(output)g(\014lename)g(can)h
+(include)f(the)h(')10 b(!')41 b(clobb)s(er)30 b(\015ag.)p
+eop end
+%%Page: 87 93
+TeXDict begin 87 92 bop 0 299 a Fg(8.4.)72 b(OUTPUT)30
+b(FILE)g(NAME)h(WHEN)g(OPENING)f(AN)h(EXISTING)e(FILE)967
+b Fi(87)0 555 y(Th)m(us,)48 b(if)d(the)g(input)f(\014lename)h(to)g
+(CFITSIO)f(is:)70 b Fe(file1.fits.gz\(file2.fit)o(s\))39
+b Fi(then)44 b(CFITSIO)g(will)0 668 y(uncompress)39 b
+(`\014le1.\014ts.gz')j(in)m(to)f(the)f(lo)s(cal)h(disk)e(\014le)h
+(`\014le2.\014ts')h(b)s(efore)f(op)s(ening)f(it.)70 b(CFITSIO)38
+b(do)s(es)i(not)0 781 y(automatically)33 b(delete)f(the)e(output)g
+(\014le,)h(so)g(it)g(will)f(still)i(exist)f(after)g(the)f(application)i
+(program)e(exits.)0 941 y(In)35 b(some)i(cases,)h(sev)m(eral)f
+(di\013eren)m(t)g(temp)s(orary)e(FITS)h(\014les)g(will)g(b)s(e)f
+(created)i(in)f(sequence,)i(for)e(instance,)i(if)0 1054
+y(one)f(op)s(ens)g(a)g(remote)h(\014le)f(using)g(FTP)-8
+b(,)37 b(then)g(\014lters)g(ro)m(ws)g(in)g(a)h(binary)e(table)i
+(extension,)i(then)c(create)j(an)0 1167 y(image)f(b)m(y)f(binning)f(a)h
+(pair)g(of)g(columns.)60 b(In)36 b(this)h(case,)j(the)d(remote)h
+(\014le)f(will)g(b)s(e)f(copied)h(to)h(a)f(temp)s(orary)0
+1280 y(lo)s(cal)j(\014le,)h(then)d(a)h(second)f(temp)s(orary)h(\014le)f
+(will)h(b)s(e)f(created)i(con)m(taining)g(the)e(\014ltered)h(ro)m(ws)f
+(of)h(the)g(table,)0 1393 y(and)c(\014nally)g(a)h(third)e(temp)s(orary)
+h(\014le)h(con)m(taining)g(the)g(binned)e(image)i(will)g(b)s(e)f
+(created.)57 b(In)34 b(cases)i(lik)m(e)h(this)0 1506
+y(where)28 b(m)m(ultiple)h(\014les)f(are)h(created,)h(the)e(out\014le)h
+(sp)s(eci\014er)f(will)g(b)s(e)g(in)m(terpreted)h(the)f(name)g(of)h
+(the)f(\014nal)g(\014le)h(as)0 1619 y(describ)s(ed)g(b)s(elo)m(w,)i(in)
+f(descending)g(priorit)m(y:)136 1869 y Fc(\017)46 b Fi(as)29
+b(the)g(name)g(of)g(the)g(\014nal)f(image)i(\014le)f(if)f(an)h(image)h
+(within)e(a)h(single)g(binary)f(table)i(cell)g(is)e(op)s(ened)g(or)h
+(if)227 1982 y(an)i(image)g(is)g(created)g(b)m(y)f(binning)g(a)g(table)
+i(column.)136 2167 y Fc(\017)46 b Fi(as)33 b(the)f(name)h(of)f(the)h
+(\014le)f(con)m(taining)i(the)e(\014ltered)g(table)i(if)e(a)h(column)f
+(\014lter)g(and/or)g(a)h(ro)m(w)f(\014lter)h(are)227
+2280 y(sp)s(eci\014ed.)136 2464 y Fc(\017)46 b Fi(as)31
+b(the)f(name)h(of)f(the)h(lo)s(cal)h(cop)m(y)f(of)f(the)h(remote)g(FTP)
+f(or)h(HTTP)e(\014le.)136 2649 y Fc(\017)46 b Fi(as)31
+b(the)g(name)g(of)g(the)f(uncompressed)g(v)m(ersion)h(of)g(the)f(FITS)g
+(\014le,)h(if)g(a)g(compressed)f(FITS)g(\014le)h(on)g(lo)s(cal)227
+2762 y(disk)f(has)g(b)s(een)g(op)s(ened.)136 2946 y Fc(\017)46
+b Fi(otherwise,)31 b(the)g(output)f(\014lename)g(is)h(ignored.)0
+3197 y(The)e(output)f(\014le)h(sp)s(eci\014er)g(is)g(useful)f(when)g
+(reading)h(FTP)g(or)g(HTTP-t)m(yp)s(e)g(FITS)f(\014les)h(since)g(it)h
+(can)f(b)s(e)g(used)0 3310 y(to)34 b(create)i(a)e(lo)s(cal)h(disk)e
+(cop)m(y)i(of)f(the)g(\014le)f(that)i(can)f(b)s(e)f(reused)g(in)g(the)h
+(future.)50 b(If)33 b(the)h(output)g(\014le)f(name)h(=)0
+3423 y(`*')i(then)e(a)i(lo)s(cal)g(\014le)f(with)g(the)g(same)g(name)g
+(as)g(the)h(net)m(w)m(ork)f(\014le)g(will)h(b)s(e)e(created.)56
+b(Note)36 b(that)f(CFITSIO)0 3535 y(will)30 b(b)s(eha)m(v)m(e)g
+(di\013eren)m(tly)h(dep)s(ending)d(on)i(whether)f(the)h(remote)g
+(\014le)g(is)g(compressed)f(or)h(not)g(as)g(sho)m(wn)f(b)m(y)h(the)0
+3648 y(follo)m(wing)i(examples:)136 3876 y Fc(\017)46
+b Fi(`ftp://remote.mac)m(hine/tmp/m)m(y\014le.\014ts.gz\(*\)')k(-)43
+b(the)g(remote)h(compressed)f(\014le)g(is)g(copied)h(to)g(the)227
+3988 y(lo)s(cal)26 b(compressed)e(\014le)g(`m)m(y\014le.\014ts.gz',)k
+(whic)m(h)c(is)g(then)h(uncompressed)e(in)h(lo)s(cal)h(memory)f(b)s
+(efore)g(b)s(eing)227 4101 y(op)s(ened)30 b(and)g(passed)g(to)h(the)f
+(application)i(program.)136 4286 y Fc(\017)46 b Fi(`ftp://remote.mac)m
+(hine/tmp/m)m(y\014le.\014ts.gz\(m)m(y\014le.\014ts\)')d(-)37
+b(the)g(remote)g(compressed)f(\014le)h(is)f(copied)227
+4399 y(and)h(uncompressed)g(in)m(to)h(the)g(lo)s(cal)h(\014le)f(`m)m
+(y\014le.\014ts'.)64 b(This)36 b(example)j(requires)e(less)h(lo)s(cal)h
+(memory)227 4512 y(than)30 b(the)h(previous)f(example)h(since)g(the)f
+(\014le)h(is)f(uncompressed)f(on)h(disk)g(instead)h(of)f(in)h(memory)-8
+b(.)136 4696 y Fc(\017)46 b Fi(`ftp://remote.mac)m(hine/tmp/m)m
+(y\014le.\014ts\(m)m(y\014le.\014ts.gz\)')28 b(-)21 b(this)g(will)h
+(usually)f(pro)s(duce)f(an)h(error)g(since)227 4809 y(CFITSIO)29
+b(itself)i(cannot)g(compress)f(\014les.)0 5036 y(The)36
+b(exact)i(b)s(eha)m(vior)e(of)h(CFITSIO)e(in)h(the)h(latter)g(case)h
+(dep)s(ends)c(on)j(the)f(t)m(yp)s(e)h(of)g(ftp)f(serv)m(er)g(running)f
+(on)0 5149 y(the)c(remote)g(mac)m(hine)g(and)f(ho)m(w)g(it)h(is)f
+(con\014gured.)40 b(In)30 b(some)h(cases,)g(if)f(the)h(\014le)f(`m)m
+(y\014le.\014ts.gz')j(exists)e(on)f(the)0 5262 y(remote)38
+b(mac)m(hine,)h(then)e(the)g(serv)m(er)g(will)h(cop)m(y)f(it)h(to)f
+(the)h(lo)s(cal)g(mac)m(hine.)61 b(In)36 b(other)h(cases)h(the)f(ftp)g
+(serv)m(er)0 5375 y(will)f(automatically)j(create)e(and)f(transmit)g(a)
+g(compressed)g(v)m(ersion)g(of)g(the)g(\014le)g(if)g(only)g(the)g
+(uncompressed)0 5488 y(v)m(ersion)27 b(exists.)41 b(This)26
+b(can)h(get)h(rather)f(confusing,)h(so)f(users)f(should)g(use)h(a)g
+(certain)h(amoun)m(t)g(of)f(caution)h(when)0 5601 y(using)34
+b(the)h(output)f(\014le)h(sp)s(eci\014er)f(with)h(FTP)f(or)h(HTTP)f
+(\014le)h(t)m(yp)s(es,)h(to)f(mak)m(e)h(sure)e(they)h(get)h(the)f(b)s
+(eha)m(vior)0 5714 y(that)c(they)g(exp)s(ect.)p eop end
+%%Page: 88 94
+TeXDict begin 88 93 bop 0 299 a Fi(88)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fd(8.5)135 b(T)-11 b(emplate)46 b(File)g(Name)f(when)g(Creating)h
+(a)g(New)f(File)0 808 y Fi(When)38 b(a)h(new)f(FITS)g(\014le)h(is)g
+(created)g(with)g(a)f(call)i(to)g(\014ts)p 2101 808 28
+4 v 32 w(create)p 2369 808 V 35 w(\014le,)g(the)f(name)g(of)g(a)g
+(template)h(\014le)e(ma)m(y)0 921 y(b)s(e)h(supplied)g(in)h(paren)m
+(theses)g(immediately)h(follo)m(wing)g(the)g(name)f(of)g(the)g(new)f
+(\014le)h(to)h(b)s(e)e(created.)71 b(This)0 1034 y(template)27
+b(is)e(used)g(to)h(de\014ne)f(the)h(structure)f(of)h(one)f(or)h(more)g
+(HDUs)g(in)f(the)h(new)f(\014le.)39 b(The)25 b(template)i(\014le)e(ma)m
+(y)0 1147 y(b)s(e)32 b(another)h(FITS)f(\014le,)i(in)f(whic)m(h)f(case)
+i(the)f(newly)g(created)h(\014le)f(will)g(ha)m(v)m(e)h(exactly)h(the)e
+(same)g(k)m(eyw)m(ords)g(in)0 1260 y(eac)m(h)25 b(HDU)g(as)g(in)f(the)g
+(template)i(FITS)d(\014le,)j(but)d(all)j(the)e(data)h(units)e(will)i(b)
+s(e)f(\014lled)g(with)f(zeros.)40 b(The)24 b(template)0
+1373 y(\014le)i(ma)m(y)h(also)g(b)s(e)e(an)h(ASCI)s(I)e(text)j(\014le,)
+g(where)f(eac)m(h)h(line)f(\(in)g(general\))i(describ)s(es)d(one)h
+(FITS)f(k)m(eyw)m(ord)i(record.)0 1486 y(The)j(format)h(of)f(the)h
+(ASCI)s(I)e(template)i(\014le)g(is)f(describ)s(ed)f(b)s(elo)m(w.)0
+1833 y Fd(8.6)135 b(Image)46 b(Tile-Compression)h(Sp)t(eci\014cation)0
+2086 y Fi(When)28 b(sp)s(ecifying)g(the)h(name)g(of)f(the)h(output)f
+(FITS)g(\014le)g(to)h(b)s(e)f(created,)i(the)f(user)f(can)g(indicate)i
+(that)f(images)0 2198 y(should)d(b)s(e)h(written)g(in)g
+(tile-compressed)h(format)g(\(see)g(section)g(5.5,)h(\\Primary)e(Arra)m
+(y)h(or)f(IMA)m(GE)h(Extension)0 2311 y(I/O)f(Routines"\))i(b)m(y)e
+(enclosing)h(the)g(compression)f(parameters)h(in)f(square)g(brac)m(k)m
+(ets)i(follo)m(wing)g(the)f(ro)s(ot)f(disk)0 2424 y(\014le)j(name.)41
+b(Here)31 b(are)g(some)g(examples)g(of)f(the)h(syn)m(tax)g(for)f(sp)s
+(ecifying)g(tile-compressed)i(output)e(images:)191 2695
+y Fe(myfile.fit[compress])185 b(-)48 b(use)f(Rice)f(algorithm)g(and)h
+(default)e(tile)i(size)191 2921 y(myfile.fit[compress)42
+b(GZIP])47 b(-)g(use)g(the)g(specified)e(compression)g(algorithm;)191
+3034 y(myfile.fit[compress)d(Rice])238 b(only)46 b(the)h(first)g
+(letter)f(of)h(the)g(algorithm)191 3147 y(myfile.fit[compress)42
+b(PLIO])238 b(name)46 b(is)i(required.)191 3373 y(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 3486 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
+3833 y Fd(8.7)135 b(HDU)46 b(Lo)t(cation)f(Sp)t(eci\014cation)0
+4086 y Fi(The)c(optional)h(HDU)h(lo)s(cation)g(sp)s(eci\014er)d
+(de\014nes)h(whic)m(h)g(HDU)h(\(Header-Data)i(Unit,)h(also)d(kno)m(wn)f
+(as)h(an)0 4199 y(`extension'\))36 b(within)d(the)i(FITS)e(\014le)h(to)
+h(initially)h(op)s(en.)51 b(It)34 b(m)m(ust)g(immediately)i(follo)m(w)f
+(the)f(base)h(\014le)f(name)0 4312 y(\(or)g(the)g(output)g(\014le)g
+(name)f(if)h(presen)m(t\).)52 b(If)33 b(it)h(is)g(not)g(sp)s(eci\014ed)
+g(then)f(the)h(\014rst)f(HDU)i(\(the)f(primary)f(arra)m(y\))0
+4425 y(is)g(op)s(ened.)46 b(The)32 b(HDU)h(lo)s(cation)h(sp)s
+(eci\014er)e(is)h(required)f(if)g(the)h(colFilter,)i(ro)m(wFilter,)g
+(or)e(binSp)s(ec)e(sp)s(eci\014ers)0 4538 y(are)f(presen)m(t,)f(b)s
+(ecause)h(the)f(primary)f(arra)m(y)i(is)f(not)h(a)f(v)-5
+b(alid)30 b(HDU)g(for)f(these)g(op)s(erations.)41 b(The)29
+b(HDU)h(ma)m(y)g(b)s(e)0 4650 y(sp)s(eci\014ed)e(either)i(b)m(y)e
+(absolute)i(p)s(osition)f(n)m(um)m(b)s(er,)f(starting)i(with)e(0)i(for)
+e(the)h(primary)f(arra)m(y)-8 b(,)31 b(or)e(b)m(y)f(reference)0
+4763 y(to)h(the)g(HDU)g(name,)g(and)f(optionally)-8 b(,)31
+b(the)e(v)m(ersion)g(n)m(um)m(b)s(er)e(and)h(the)h(HDU)g(t)m(yp)s(e)g
+(of)f(the)h(desired)f(extension.)0 4876 y(The)k(lo)s(cation)h(of)f(an)g
+(image)i(within)d(a)i(single)f(cell)i(of)e(a)g(binary)g(table)h(ma)m(y)
+f(also)h(b)s(e)f(sp)s(eci\014ed,)g(as)g(describ)s(ed)0
+4989 y(b)s(elo)m(w.)0 5149 y(The)26 b(absolute)h(p)s(osition)f(of)g
+(the)h(extension)g(is)f(sp)s(eci\014ed)f(either)i(b)m(y)f(enclosed)h
+(the)g(n)m(um)m(b)s(er)e(in)h(square)f(brac)m(k)m(ets)0
+5262 y(\(e.g.,)k(`[1]')g(=)d(the)h(\014rst)f(extension)h(follo)m(wing)i
+(the)e(primary)e(arra)m(y\))j(or)f(b)m(y)f(preceded)h(the)g(n)m(um)m(b)
+s(er)e(with)i(a)g(plus)0 5375 y(sign)37 b(\(`+1'\).)63
+b(T)-8 b(o)38 b(sp)s(ecify)f(the)g(HDU)h(b)m(y)g(name,)h(giv)m(e)g(the)
+e(name)h(of)f(the)h(desired)f(HDU)h(\(the)f(v)-5 b(alue)38
+b(of)g(the)0 5488 y(EXTNAME)e(or)g(HDUNAME)h(k)m(eyw)m(ord\))g(and)f
+(optionally)h(the)f(extension)h(v)m(ersion)f(n)m(um)m(b)s(er)f(\(v)-5
+b(alue)37 b(of)f(the)0 5601 y(EXTVER)27 b(k)m(eyw)m(ord\))i(and)e(the)h
+(extension)h(t)m(yp)s(e)e(\(v)-5 b(alue)29 b(of)f(the)g(XTENSION)f(k)m
+(eyw)m(ord:)40 b(IMA)m(GE,)29 b(ASCI)s(I)d(or)0 5714
+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)i(enclosed)g(in)f(square)g(brac)m(k)m(ets.)56
+b(If)34 b(the)h(v)-5 b(alue)p eop end
+%%Page: 89 95
+TeXDict begin 89 94 bop 0 299 a Fg(8.8.)72 b(IMA)m(GE)31
+b(SECTION)2835 b Fi(89)0 555 y(of)34 b(EXTVER)f(and)f(XTENSION)h(are)h
+(not)f(sp)s(eci\014ed,)h(then)f(the)h(\014rst)e(extension)j(with)e(the)
+g(correct)i(v)-5 b(alue)34 b(of)0 668 y(EXTNAME)39 b(is)g(op)s(ened.)67
+b(The)38 b(extension)i(name)f(and)f(t)m(yp)s(e)i(are)f(not)h(case)g
+(sensitiv)m(e,)j(and)38 b(the)h(extension)0 781 y(t)m(yp)s(e)29
+b(ma)m(y)g(b)s(e)f(abbreviated)h(to)g(a)g(single)g(letter)h(\(e.g.,)h
+(I)d(=)g(IMA)m(GE)i(extension)f(or)f(primary)g(arra)m(y)-8
+b(,)30 b(A)f(or)f(T)g(=)0 894 y(ASCI)s(I)d(table)i(extension,)h(and)e
+(B)h(=)f(binary)g(table)h(BINT)-8 b(ABLE)27 b(extension\).)41
+b(If)26 b(the)g(HDU)h(lo)s(cation)i(sp)s(eci\014er)0
+1007 y(is)h(equal)h(to)g(`[PRIMAR)-8 b(Y]')32 b(or)f(`[P]',)g(then)f
+(the)h(primary)e(arra)m(y)i(\(the)g(\014rst)f(HDU\))h(will)g(b)s(e)f
+(op)s(ened.)0 1167 y(FITS)k(images)i(are)f(most)h(commonly)f(stored)g
+(in)g(the)g(primary)f(arra)m(y)h(or)g(an)g(image)h(extension,)h(but)d
+(images)0 1280 y(can)d(also)h(b)s(e)e(stored)h(as)h(a)f(v)m(ector)h(in)
+f(a)g(single)h(cell)g(of)f(a)h(binary)e(table)i(\(i.e.)43
+b(eac)m(h)32 b(ro)m(w)f(of)g(the)h(v)m(ector)g(column)0
+1393 y(con)m(tains)d(a)g(di\013eren)m(t)f(image\).)42
+b(Suc)m(h)27 b(an)h(image)i(can)e(b)s(e)g(op)s(ened)f(with)h(CFITSIO)e
+(b)m(y)i(sp)s(ecifying)g(the)g(desired)0 1506 y(column)k(name)g(and)f
+(the)h(ro)m(w)g(n)m(um)m(b)s(er)f(after)h(the)g(binary)f(table)i(HDU)g
+(sp)s(eci\014er)e(as)h(sho)m(wn)g(in)f(the)h(follo)m(wing)0
+1619 y(examples.)71 b(The)40 b(column)g(name)h(is)f(separated)h(from)f
+(the)h(HDU)g(sp)s(eci\014er)f(b)m(y)g(a)h(semicolon)g(and)f(the)h(ro)m
+(w)0 1732 y(n)m(um)m(b)s(er)29 b(is)h(enclosed)h(in)e(paren)m(theses.)
+41 b(In)30 b(this)g(case)h(CFITSIO)d(copies)j(the)f(image)i(from)d(the)
+i(table)g(cell)g(in)m(to)0 1844 y(a)h(temp)s(orary)e(primary)h(arra)m
+(y)g(b)s(efore)g(it)h(is)f(op)s(ened.)43 b(The)30 b(application)j
+(program)e(then)g(just)g(sees)g(the)h(image)0 1957 y(in)i(the)h
+(primary)e(arra)m(y)-8 b(,)37 b(without)d(an)m(y)h(extensions.)53
+b(The)34 b(particular)g(ro)m(w)h(to)g(b)s(e)e(op)s(ened)h(ma)m(y)h(b)s
+(e)f(sp)s(eci\014ed)0 2070 y(either)28 b(b)m(y)f(giving)h(an)f
+(absolute)h(in)m(teger)h(ro)m(w)f(n)m(um)m(b)s(er)e(\(starting)i(with)f
+(1)h(for)f(the)g(\014rst)g(ro)m(w\),)i(or)e(b)m(y)g(sp)s(ecifying)0
+2183 y(a)33 b(b)s(o)s(olean)f(expression)g(that)h(ev)-5
+b(aluates)34 b(to)f(TR)m(UE)g(for)f(the)g(desired)g(ro)m(w.)47
+b(The)32 b(\014rst)f(ro)m(w)i(that)g(satis\014es)g(the)0
+2296 y(expression)28 b(will)g(b)s(e)g(used.)39 b(The)28
+b(ro)m(w)g(selection)i(expression)e(has)g(the)g(same)g(syn)m(tax)h(as)f
+(describ)s(ed)f(in)h(the)g(Ro)m(w)0 2409 y(Filter)k(Sp)s(eci\014er)d
+(section,)j(b)s(elo)m(w.)0 2569 y(Examples:)143 2811
+y Fe(myfile.fits[3])44 b(-)k(open)e(the)h(3rd)g(HDU)g(following)e(the)i
+(primary)f(array)143 2924 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
+3037 y(myfile.fits[EVENTS])f(-)k(open)g(the)g(extension)e(that)i(has)g
+(EXTNAME)e(=)j('EVENTS')143 3150 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 3263 y(myfile.fits[events,2,b])42 b(-)47 b(same,)f(but)h
+(also)g(requires)f(XTENSION)f(=)j('BINTABLE')143 3376
+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 3489 y(column)f(in)i(the)e(3rd)h
+(extension)f(of)h(the)g(file.)143 3602 y(myfile.fits[3;)d
+(images\(exposure)g(>)j(100\)])g(-)g(as)g(above,)f(but)h(opens)g(the)f
+(image)907 3714 y(in)h(the)g(first)f(row)h(that)g(has)g(an)g
+('exposure')e(column)h(value)907 3827 y(greater)g(than)g(100.)0
+4158 y Fd(8.8)135 b(Image)46 b(Section)0 4408 y Fi(A)41
+b(virtual)g(\014le)f(con)m(taining)i(a)f(rectangular)h(subsection)e(of)
+h(an)g(image)g(can)g(b)s(e)f(extracted)i(and)e(op)s(ened)g(b)m(y)0
+4521 y(sp)s(ecifying)32 b(the)h(range)g(of)g(pixels)g(\(start:end\))g
+(along)h(eac)m(h)g(axis)f(to)g(b)s(e)f(extracted)i(from)e(the)h
+(original)g(image.)0 4634 y(One)d(can)h(also)h(sp)s(ecify)e(an)h
+(optional)h(pixel)f(incremen)m(t)g(\(start:end:step\))h(for)f(eac)m(h)h
+(axis)f(of)g(the)g(input)e(image.)0 4747 y(A)f(pixel)f(step)h(=)f(1)h
+(will)g(b)s(e)f(assumed)f(if)i(it)g(is)f(not)h(sp)s(eci\014ed.)39
+b(If)27 b(the)h(start)g(pixel)g(is)f(larger)i(then)e(the)h(end)e
+(pixel,)0 4860 y(then)32 b(the)g(image)h(will)f(b)s(e)f(\015ipp)s(ed)f
+(\(pro)s(ducing)h(a)h(mirror)g(image\))h(along)g(that)f(dimension.)45
+b(An)32 b(asterisk,)h('*',)0 4973 y(ma)m(y)39 b(b)s(e)e(used)h(to)h(sp)
+s(ecify)f(the)g(en)m(tire)h(range)g(of)f(an)h(axis,)i(and)c('-*')j
+(will)e(\015ip)g(the)g(en)m(tire)h(axis.)65 b(The)38
+b(input)0 5086 y(image)31 b(can)f(b)s(e)f(in)g(the)h(primary)f(arra)m
+(y)-8 b(,)31 b(in)e(an)g(image)i(extension,)g(or)f(con)m(tained)g(in)g
+(a)g(v)m(ector)h(cell)g(of)f(a)g(binary)0 5199 y(table.)40
+b(In)25 b(the)h(later)h(2)f(cases)h(the)f(extension)h(name)f(or)f(n)m
+(um)m(b)s(er)g(m)m(ust)h(b)s(e)f(sp)s(eci\014ed)g(b)s(efore)h(the)g
+(image)h(section)0 5312 y(sp)s(eci\014er.)0 5472 y(Examples:)95
+5714 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)p eop end
+%%Page: 90 96
+TeXDict begin 90 95 bop 0 299 a Fi(90)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)668
+555 y Fe(consisting)45 b(of)i(the)g(odd)g(numbered)f(columns)g(\(1st)g
+(axis\))h(and)668 668 y(the)g(even)g(numbered)e(rows)i(\(2nd)g(axis\))f
+(of)h(the)g(image)f(in)i(the)668 781 y(primary)e(array)g(of)i(the)e
+(file.)95 1007 y(myfile.fits[*,)e(512:256])i(-)h(open)g(an)g(image)g
+(consisting)e(of)i(all)g(the)g(columns)668 1120 y(in)g(the)g(input)g
+(image,)f(but)h(only)f(rows)h(256)g(through)f(512.)668
+1233 y(The)h(image)f(will)h(be)g(flipped)f(along)g(the)h(2nd)g(axis)g
+(since)668 1346 y(the)g(starting)f(pixel)g(is)h(greater)f(than)h(the)g
+(ending)f(pixel.)95 1571 y(myfile.fits[*:2,)e(512:256:2])h(-)i(same)g
+(as)g(above)f(but)h(keeping)f(only)668 1684 y(every)h(other)f(row)h
+(and)g(column)f(in)h(the)g(input)f(image.)95 1910 y(myfile.fits[-*,)e
+(*])j(-)h(copy)e(the)h(entire)f(image,)g(flipping)g(it)h(along)668
+2023 y(the)g(first)f(axis.)95 2249 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
+2362 y(is)g(in)h(the)e(3rd)h(extension)f(of)h(the)g(file.)95
+2588 y(myfile.fits[4;)d(images\(12\)][1:10,1:10])e(-)48
+b(open)e(an)h(image)g(consisting)286 2700 y(of)h(the)e(first)h(10)g
+(pixels)f(in)h(both)g(dimensions.)e(The)i(original)286
+2813 y(image)g(resides)f(in)h(the)g(12th)f(row)h(of)g(the)g('images')f
+(vector)286 2926 y(column)g(in)i(the)f(table)f(in)h(the)g(4th)g
+(extension)e(of)i(the)g(file.)0 3203 y Fi(When)23 b(CFITSIO)f(op)s(ens)
+h(an)g(image)h(section)h(it)f(\014rst)f(creates)h(a)g(temp)s(orary)f
+(\014le)h(con)m(taining)h(the)e(image)i(section)0 3315
+y(plus)32 b(a)i(cop)m(y)g(of)g(an)m(y)g(other)f(HDUs)h(in)f(the)h
+(\014le.)50 b(This)32 b(temp)s(orary)h(\014le)h(is)f(then)g(op)s(ened)g
+(b)m(y)g(the)h(application)0 3428 y(program,)28 b(so)g(it)g(is)f(not)h
+(p)s(ossible)f(to)h(write)g(to)g(or)g(mo)s(dify)f(the)g(input)g(\014le)
+g(when)g(sp)s(ecifying)g(an)h(image)h(section.)0 3541
+y(Note)39 b(that)f(CFITSIO)e(automatically)k(up)s(dates)d(the)g(w)m
+(orld)h(co)s(ordinate)g(system)g(k)m(eyw)m(ords)f(in)g(the)h(header)0
+3654 y(of)33 b(the)h(image)g(section,)h(if)e(they)h(exist,)h(so)e(that)
+h(the)f(co)s(ordinate)h(asso)s(ciated)h(with)e(eac)m(h)h(pixel)f(in)g
+(the)h(image)0 3767 y(section)e(will)e(b)s(e)g(computed)g(correctly)-8
+b(.)0 4120 y Fd(8.9)135 b(Image)46 b(T)-11 b(ransform)45
+b(Filters)0 4374 y Fi(CFITSIO)33 b(can)h(apply)g(a)h(user-sp)s
+(eci\014ed)e(mathematical)j(function)e(to)h(the)g(v)-5
+b(alue)34 b(of)h(ev)m(ery)g(pixel)f(in)g(a)h(FITS)0 4487
+y(image,)29 b(th)m(us)e(creating)h(a)g(new)e(virtual)h(image)i(in)d
+(computer)h(memory)g(that)h(is)f(then)f(op)s(ened)h(and)f(read)h(b)m(y)
+g(the)0 4600 y(application)32 b(program.)40 b(The)30
+b(original)i(FITS)d(image)j(is)e(not)h(mo)s(di\014ed)e(b)m(y)h(this)h
+(pro)s(cess.)0 4760 y(The)20 b(image)j(transformation)e(sp)s(eci\014er)
+f(is)h(app)s(ended)e(to)j(the)f(input)f(FITS)h(\014le)g(name)g(and)f
+(is)h(enclosed)h(in)e(square)0 4873 y(brac)m(k)m(ets.)42
+b(It)29 b(b)s(egins)f(with)h(the)g(letters)i('PIX')e(to)h(distinguish)e
+(it)i(from)e(other)i(t)m(yp)s(es)f(of)g(FITS)f(\014le)h(\014lters)g
+(that)0 4986 y(are)36 b(recognized)i(b)m(y)e(CFITSIO.)e(The)i(image)h
+(transforming)f(function)f(ma)m(y)i(use)f(an)m(y)g(of)g(the)h
+(mathematical)0 5099 y(op)s(erators)44 b(listed)h(in)f(the)h(follo)m
+(wing)h('Ro)m(w)f(Filtering)g(Sp)s(eci\014cation')g(section)h(of)e
+(this)h(do)s(cumen)m(t.)82 b(Some)0 5212 y(examples)31
+b(of)f(image)i(transform)e(\014lters)g(are:)48 5488 y
+Fe([pix)46 b(X)i(*)f(2.0])715 b(-)48 b(multiply)d(each)i(pixel)f(by)h
+(2.0)48 5601 y([pix)f(sqrt\(X\)])714 b(-)48 b(take)e(the)h(square)f
+(root)h(of)g(each)g(pixel)48 5714 y([pix)f(X)i(+)f(#ZEROPT)571
+b(-)48 b(add)e(the)h(value)g(of)g(the)g(ZEROPT)f(keyword)p
+eop end
+%%Page: 91 97
+TeXDict begin 91 96 bop 0 299 a Fg(8.9.)72 b(IMA)m(GE)31
+b(TRANSF)m(ORM)g(FIL)-8 b(TERS)2237 b Fi(91)48 555 y
+Fe([pix)46 b(X>0)h(?)h(log10\(X\))d(:)j(-99.])e(-)i(if)f(the)g(pixel)f
+(value)g(is)i(greater)1480 668 y(than)e(0,)h(compute)f(the)h(base)g(10)
+g(log,)1480 781 y(else)f(set)h(the)g(pixel)f(=)i(-99.)0
+1013 y Fi(Use)24 b(the)g(letter)h('X')f(in)f(the)h(expression)g(to)g
+(represen)m(t)g(the)g(curren)m(t)f(pixel)h(v)-5 b(alue)24
+b(in)f(the)h(image.)40 b(The)23 b(expression)0 1126 y(is)38
+b(ev)-5 b(aluated)39 b(indep)s(enden)m(tly)e(for)g(eac)m(h)i(pixel)f
+(in)g(the)g(image)h(and)e(ma)m(y)h(b)s(e)g(a)g(function)f(of)h(1\))h
+(the)f(original)0 1239 y(pixel)32 b(v)-5 b(alue,)32 b(2\))g(the)f(v)-5
+b(alue)32 b(of)f(other)h(pixels)f(in)g(the)g(image)i(at)f(a)f(giv)m(en)
+i(relativ)m(e)g(o\013set)f(from)f(the)g(p)s(osition)h(of)0
+1352 y(the)d(pixel)f(that)h(is)g(b)s(eing)f(ev)-5 b(aluated,)30
+b(and)e(3\))h(the)g(v)-5 b(alue)29 b(of)f(an)m(y)h(header)f(k)m(eyw)m
+(ords.)41 b(Header)29 b(k)m(eyw)m(ord)g(v)-5 b(alues)0
+1465 y(are)31 b(represen)m(ted)f(b)m(y)g(the)h(name)f(of)h(the)f(k)m
+(eyw)m(ord)h(preceded)f(b)m(y)h(the)f('#')h(sign.)0 1625
+y(T)-8 b(o)35 b(access)h(the)f(the)g(v)-5 b(alue)35 b(of)g(adjacen)m(t)
+h(pixels)f(in)f(the)h(image,)i(sp)s(ecify)e(the)g(\(1-D\))h(o\013set)g
+(from)e(the)h(curren)m(t)0 1738 y(pixel)c(in)f(curly)g(brac)m(k)m(ets.)
+42 b(F)-8 b(or)31 b(example)48 1970 y Fe([pix)94 b(\(x{-1})46
+b(+)i(x)f(+)h(x{+1}\))e(/)h(3])0 2202 y Fi(will)25 b(replace)g(eac)m(h)
+h(pixel)f(v)-5 b(alue)25 b(with)f(the)h(running)e(mean)i(of)f(the)h(v)
+-5 b(alues)25 b(of)g(that)g(pixel)g(and)f(it's)h(2)g(neigh)m(b)s(oring)
+0 2314 y(pixels.)40 b(Note)30 b(that)g(in)e(this)g(notation)i(the)f
+(image)h(is)f(treated)g(as)g(a)g(1-D)h(arra)m(y)-8 b(,)30
+b(where)e(eac)m(h)i(ro)m(w)f(of)g(the)g(image)0 2427
+y(\(or)c(higher)f(dimensional)g(cub)s(e\))h(is)f(app)s(ended)f(one)h
+(after)h(another)g(in)f(one)h(long)g(arra)m(y)g(of)f(pixels.)39
+b(It)25 b(is)f(p)s(ossible)0 2540 y(to)35 b(refer)f(to)h(pixels)f(in)g
+(the)g(ro)m(ws)g(ab)s(o)m(v)m(e)h(or)g(b)s(elo)m(w)f(the)g(curren)m(t)g
+(pixel)h(b)m(y)f(using)f(the)h(v)-5 b(alue)35 b(of)f(the)h(NAXIS1)0
+2653 y(header)30 b(k)m(eyw)m(ord.)41 b(F)-8 b(or)32 b(example)48
+2885 y Fe([pix)46 b(\(x{-#NAXIS1})f(+)i(x)h(+)f(x{#NAXIS1}\))e(/)i(3])0
+3117 y Fi(will)34 b(compute)f(the)h(mean)f(of)g(eac)m(h)i(image)f
+(pixel)g(and)e(the)i(pixels)f(immediately)i(ab)s(o)m(v)m(e)f(and)f(b)s
+(elo)m(w)g(it)h(in)f(the)0 3230 y(adjacen)m(t)27 b(ro)m(ws)f(of)g(the)f
+(image.)41 b(The)25 b(follo)m(wing)i(more)f(complex)h(example)f
+(creates)h(a)f(smo)s(othed)g(virtual)g(image)0 3343 y(where)k(eac)m(h)h
+(pixel)g(is)g(a)f(3)h(x)f(3)h(b)s(o)m(xcar)g(a)m(v)m(erage)i(of)d(the)h
+(input)e(image)j(pixels:)95 3575 y Fe([pix)47 b(\(X)g(+)h(X{-1})e(+)i
+(X{+1})286 3688 y(+)g(X{-#NAXIS1})d(+)i(X{-#NAXIS1)e(-)i(1})h(+)f
+(X{-#NAXIS1)e(+)j(1})286 3801 y(+)g(X{#NAXIS1})d(+)i(X{#NAXIS1)f(-)h
+(1})g(+)h(X{#NAXIS1)d(+)i(1}\))g(/)h(9.])0 4033 y Fi(If)31
+b(the)h(pixel)g(o\013set)h(extends)f(b)s(ey)m(ond)f(the)h(\014rst)f(or)
+h(last)h(pixel)f(in)f(the)h(image,)i(the)e(function)g(will)g(ev)-5
+b(aluate)33 b(to)0 4145 y(unde\014ned,)28 b(or)j(NULL.)0
+4306 y(F)-8 b(or)39 b(complex)g(or)g(commonly)g(used)e(image)j
+(\014ltering)f(op)s(erations,)i(one)d(can)h(write)g(the)f(expression)h
+(in)m(to)g(an)0 4419 y(external)i(text)h(\014le)f(and)f(then)g(imp)s
+(ort)g(it)h(in)m(to)h(the)e(\014lter)h(using)f(the)h(syn)m(tax)g('[pix)
+g(@\014lename.txt]'.)72 b(The)0 4531 y(mathematical)29
+b(expression)e(can)g(extend)g(o)m(v)m(er)i(m)m(ultiple)e(lines)g(of)h
+(text)g(in)e(the)h(\014le.)40 b(An)m(y)27 b(lines)g(in)g(the)g
+(external)0 4644 y(text)h(\014le)e(that)i(b)s(egin)e(with)g(2)h(slash)f
+(c)m(haracters)i(\('//'\))h(will)e(b)s(e)f(ignored)h(and)f(ma)m(y)h(b)s
+(e)f(used)g(to)h(add)f(commen)m(ts)0 4757 y(in)m(to)31
+b(the)g(\014le.)0 4917 y(By)c(default,)g(the)f(datat)m(yp)s(e)i(of)e
+(the)g(resulting)h(image)g(will)g(b)s(e)e(the)i(same)f(as)h(the)f
+(original)i(image,)g(but)e(one)g(ma)m(y)0 5030 y(force)31
+b(a)g(di\013eren)m(t)g(datat)m(yp)s(e)g(b)m(y)f(app)s(ended)f(a)h(co)s
+(de)h(letter)h(to)f(the)f('pix')h(k)m(eyw)m(ord:)286
+5262 y Fe(pixb)95 b(-)g(8-bit)46 b(byte)190 b(image)46
+b(with)h(BITPIX)f(=)143 b(8)286 5375 y(pixi)95 b(-)47
+b(16-bit)f(integer)g(image)g(with)h(BITPIX)f(=)95 b(16)286
+5488 y(pixj)g(-)47 b(32-bit)f(integer)g(image)g(with)h(BITPIX)f(=)95
+b(32)286 5601 y(pixr)g(-)47 b(32-bit)f(float)142 b(image)46
+b(with)h(BITPIX)f(=)i(-32)286 5714 y(pixd)95 b(-)47 b(64-bit)f(float)
+142 b(image)46 b(with)h(BITPIX)f(=)i(-64)p eop end
+%%Page: 92 98
+TeXDict begin 92 97 bop 0 299 a Fi(92)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fi(Also)23 b(b)m(y)f(default,)j(an)m(y)d(other)h(HDUs)g(in)f(the)
+g(input)g(\014le)g(will)h(b)s(e)e(copied)i(without)g(c)m(hange)g(to)g
+(the)g(output)f(virtual)0 668 y(FITS)k(\014le,)h(but)f(one)g(ma)m(y)h
+(discard)f(the)h(other)f(HDUs)h(b)m(y)f(adding)g(the)h(n)m(um)m(b)s(er)
+e('1')i(to)g(the)g('pix')f(k)m(eyw)m(ord)h(\(and)0 781
+y(follo)m(wing)32 b(an)m(y)f(optional)g(datat)m(yp)s(e)g(co)s(de)g
+(letter\).)42 b(F)-8 b(or)32 b(example:)239 1044 y Fe
+(myfile.fits[3][pixr1)90 b(sqrt\(X\)])0 1307 y Fi(will)23
+b(create)i(a)e(virtual)g(FITS)f(\014le)h(con)m(taining)h(only)f(a)g
+(primary)f(arra)m(y)i(image)g(with)e(32-bit)i(\015oating)g(p)s(oin)m(t)
+f(pixels)0 1420 y(that)29 b(ha)m(v)m(e)h(a)f(v)-5 b(alue)30
+b(equal)f(to)g(the)g(square)g(ro)s(ot)g(of)g(the)g(pixels)f(in)h(the)g
+(image)h(that)f(is)g(in)f(the)h(3rd)f(extension)i(of)0
+1533 y(the)h('m)m(y\014le.\014ts')g(\014le.)0 1870 y
+Fd(8.10)136 b(Column)45 b(and)f(Keyw)l(ord)i(Filtering)g(Sp)t
+(eci\014cation)0 2121 y Fi(The)27 b(optional)i(column/k)m(eyw)m(ord)g
+(\014ltering)f(sp)s(eci\014er)f(is)h(used)f(to)i(mo)s(dify)e(the)h
+(column)g(structure)f(and/or)h(the)0 2234 y(header)38
+b(k)m(eyw)m(ords)h(in)f(the)h(HDU)g(that)h(w)m(as)f(selected)h(with)e
+(the)h(previous)f(HDU)h(lo)s(cation)h(sp)s(eci\014er.)65
+b(This)0 2347 y(\014ltering)42 b(sp)s(eci\014er)f(m)m(ust)h(b)s(e)f
+(enclosed)i(in)e(square)h(brac)m(k)m(ets)h(and)e(can)h(b)s(e)f
+(distinguished)g(from)h(a)g(general)0 2460 y(ro)m(w)d(\014lter)g(sp)s
+(eci\014er)f(\(describ)s(ed)g(b)s(elo)m(w\))h(b)m(y)g(the)g(fact)h
+(that)f(it)g(b)s(egins)f(with)h(the)g(string)g('col)h(')f(and)f(is)h
+(not)0 2573 y(immediately)30 b(follo)m(w)m(ed)g(b)m(y)e(an)g(equals)h
+(sign.)40 b(The)28 b(original)h(\014le)f(is)h(not)f(c)m(hanged)h(b)m(y)
+f(this)h(\014ltering)f(op)s(eration,)0 2686 y(and)40
+b(instead)h(the)g(mo)s(di\014cations)g(are)g(made)f(on)h(a)g(cop)m(y)g
+(of)g(the)g(input)f(FITS)g(\014le)g(\(usually)h(in)f(memory\),)0
+2799 y(whic)m(h)33 b(also)h(con)m(tains)g(a)f(cop)m(y)h(of)f(all)h(the)
+g(other)f(HDUs)h(in)e(the)h(\014le.)49 b(This)33 b(temp)s(orary)f
+(\014le)h(is)g(passed)g(to)h(the)0 2912 y(application)f(program)f(and)f
+(will)h(p)s(ersist)f(only)h(un)m(til)g(the)g(\014le)g(is)g(closed)h(or)
+f(un)m(til)g(the)g(program)f(exits,)j(unless)0 3025 y(the)d(out\014le)f
+(sp)s(eci\014er)g(\(see)h(ab)s(o)m(v)m(e\))h(is)f(also)g(supplied.)0
+3185 y(The)g(column/k)m(eyw)m(ord)h(\014lter)f(can)g(b)s(e)g(used)f(to)
+i(p)s(erform)e(the)i(follo)m(wing)g(op)s(erations.)44
+b(More)32 b(than)f(one)g(op)s(er-)0 3298 y(ation)g(ma)m(y)g(b)s(e)f(sp)
+s(eci\014ed)g(b)m(y)g(separating)h(them)f(with)h(commas)f(or)h
+(semi-colons.)136 3561 y Fc(\017)46 b Fi(Cop)m(y)36 b(only)g(a)g(sp)s
+(eci\014ed)g(list)g(of)g(columns)g(columns)f(to)i(the)f(\014ltered)g
+(input)f(\014le.)57 b(The)36 b(list)g(of)g(column)227
+3673 y(name)c(should)f(b)s(e)h(separated)g(b)m(y)g(semi-colons.)48
+b(Wild)32 b(card)g(c)m(haracters)i(ma)m(y)e(b)s(e)g(used)f(in)h(the)g
+(column)227 3786 y(names)37 b(to)h(matc)m(h)g(m)m(ultiple)g(columns.)61
+b(If)37 b(the)g(expression)g(con)m(tains)i(b)s(oth)d(a)i(list)f(of)h
+(columns)f(to)h(b)s(e)227 3899 y(included)h(and)f(columns)h(to)g(b)s(e)
+g(deleted,)j(then)c(all)i(the)f(columns)g(in)g(the)g(original)h(table)g
+(except)g(the)227 4012 y(explicitly)32 b(deleted)f(columns)f(will)g
+(app)s(ear)g(in)g(the)g(\014ltered)g(table)h(\(i.e.,)h(there)e(is)h(no)
+f(need)f(to)i(explicitly)227 4125 y(list)g(the)g(columns)f(to)h(b)s(e)f
+(included)f(if)i(an)m(y)f(columns)g(are)h(b)s(eing)f(deleted\).)136
+4316 y Fc(\017)46 b Fi(Delete)32 b(a)d(column)g(or)g(k)m(eyw)m(ord)h(b)
+m(y)f(listing)h(the)f(name)g(preceded)g(b)m(y)g(a)g(min)m(us)g(sign)g
+(or)g(an)g(exclamation)227 4429 y(mark)c(\(!\),)h(e.g.,)i('-TIME')d
+(will)g(delete)h(the)e(TIME)h(column)f(if)g(it)i(exists,)g(otherwise)f
+(the)g(TIME)f(k)m(eyw)m(ord.)227 4542 y(An)35 b(error)f(is)h(returned)e
+(if)i(neither)f(a)i(column)e(nor)g(k)m(eyw)m(ord)h(with)g(this)f(name)h
+(exists.)54 b(Note)36 b(that)g(the)227 4655 y(exclamation)27
+b(p)s(oin)m(t,)g(')10 b(!',)27 b(is)e(a)g(sp)s(ecial)h(UNIX)f(c)m
+(haracter,)j(so)d(if)g(it)h(is)f(used)f(on)h(the)g(command)g(line)g
+(rather)227 4768 y(than)33 b(en)m(tered)h(at)g(a)g(task)g(prompt,)f(it)
+h(m)m(ust)f(b)s(e)g(preceded)g(b)m(y)g(a)h(bac)m(kslash)g(to)g(force)g
+(the)f(UNIX)h(shell)227 4881 y(to)d(ignore)g(it.)136
+5071 y Fc(\017)46 b Fi(Rename)29 b(an)g(existing)g(column)f(or)h(k)m
+(eyw)m(ord)g(with)f(the)h(syn)m(tax)g('NewName)h(==)e(OldName'.)40
+b(An)28 b(error)227 5184 y(is)j(returned)e(if)h(neither)h(a)f(column)g
+(nor)g(k)m(eyw)m(ord)h(with)f(this)h(name)f(exists.)136
+5375 y Fc(\017)46 b Fi(App)s(end)37 b(a)j(new)f(column)f(or)i(k)m(eyw)m
+(ord)f(to)h(the)f(table.)68 b(T)-8 b(o)40 b(create)g(a)g(column,)h(giv)
+m(e)g(the)e(new)g(name,)227 5488 y(optionally)e(follo)m(w)m(ed)g(b)m(y)
+e(the)g(datat)m(yp)s(e)h(in)f(paren)m(theses,)i(follo)m(w)m(ed)g(b)m(y)
+e(a)h(single)g(equals)f(sign)g(and)g(an)227 5601 y(expression)g(to)h(b)
+s(e)e(used)g(to)i(compute)f(the)g(v)-5 b(alue)35 b(\(e.g.,)j('new)m
+(col\(1J\))f(=)e(0')g(will)h(create)g(a)f(new)g(32-bit)227
+5714 y(in)m(teger)k(column)e(called)i('new)m(col')f(\014lled)g(with)f
+(zeros\).)62 b(The)37 b(datat)m(yp)s(e)h(is)g(sp)s(eci\014ed)e(using)h
+(the)h(same)p eop end
+%%Page: 93 99
+TeXDict begin 93 98 bop 0 299 a Fg(8.10.)73 b(COLUMN)30
+b(AND)h(KEYW)m(ORD)g(FIL)-8 b(TERING)30 b(SPECIFICA)-8
+b(TION)1075 b Fi(93)227 555 y(syn)m(tax)28 b(that)h(is)e(allo)m(w)m(ed)
+j(for)d(the)h(v)-5 b(alue)28 b(of)g(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
+668 y(for)37 b(binary)f(tables,)k(and)c('I8',)k(F12.3',)h('E20.12',)g
+(etc.)62 b(for)37 b(ASCI)s(I)e(tables\).)62 b(If)37 b(the)g(datat)m(yp)
+s(e)h(is)f(not)227 781 y(sp)s(eci\014ed)24 b(then)f(an)h(appropriate)h
+(datat)m(yp)s(e)g(will)f(b)s(e)g(c)m(hosen)g(dep)s(ending)f(on)h(the)g
+(form)g(of)g(the)g(expression)227 894 y(\(ma)m(y)f(b)s(e)d(a)i(c)m
+(haracter)h(string,)h(logical,)h(bit,)f(long)e(in)m(teger,)j(or)c
+(double)g(column\).)38 b(An)21 b(appropriate)g(v)m(ector)227
+1007 y(coun)m(t)31 b(\(in)g(the)f(case)i(of)e(binary)g(tables\))h(will)
+g(also)g(b)s(e)f(added)g(if)g(not)h(explicitly)h(sp)s(eci\014ed.)227
+1156 y(When)26 b(creating)h(a)f(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)
+h('#',)j(and)227 1269 y(the)h(expression)f(m)m(ust)g(ev)-5
+b(aluate)30 b(to)f(a)g(scalar)g(\(i.e.,)h(cannot)f(ha)m(v)m(e)h(a)f
+(column)f(name)g(in)g(the)h(expression\).)227 1382 y(The)j(commen)m(t)i
+(string)f(for)f(the)h(k)m(eyw)m(ord)h(ma)m(y)f(b)s(e)f(sp)s(eci\014ed)g
+(in)g(paren)m(theses)h(immediately)h(follo)m(wing)227
+1495 y(the)29 b(k)m(eyw)m(ord)f(name)g(\(instead)h(of)f(supplying)f(a)h
+(datat)m(yp)s(e)h(as)g(in)e(the)i(case)g(of)f(creating)h(a)g(new)f
+(column\).)227 1608 y(If)c(the)h(k)m(eyw)m(ord)g(name)f(ends)g(with)g
+(a)h(p)s(ound)d(sign)i('#',)i(then)e(c\014tsio)i(will)e(substitute)h
+(the)f(n)m(um)m(b)s(er)f(of)i(the)227 1720 y(most)31
+b(recen)m(tly)h(referenced)e(column)h(for)f(the)h(#)f(c)m(haracter)i(.)
+41 b(This)29 b(is)i(esp)s(ecially)h(useful)d(when)h(writing)227
+1833 y(a)c(column-related)g(k)m(eyw)m(ord)g(lik)m(e)g(TUNITn)e(for)h(a)
+h(newly)f(created)h(column,)g(as)g(sho)m(wn)e(in)h(the)g(follo)m(wing)
+227 1946 y(examples.)136 2131 y Fc(\017)46 b Fi(Recompute)f(\(o)m(v)m
+(erwrite\))i(the)d(v)-5 b(alues)44 b(in)g(an)g(existing)i(column)e(or)g
+(k)m(eyw)m(ord)g(b)m(y)g(giving)i(the)e(name)227 2244
+y(follo)m(w)m(ed)32 b(b)m(y)f(an)f(equals)h(sign)f(and)g(an)g
+(arithmetic)i(expression.)0 2497 y(The)23 b(expression)g(that)i(is)e
+(used)g(when)g(app)s(ending)f(or)h(recomputing)h(columns)f(or)h(k)m
+(eyw)m(ords)g(can)g(b)s(e)f(arbitrarily)0 2610 y(complex)36
+b(and)g(ma)m(y)g(b)s(e)f(a)h(function)g(of)g(other)g(header)g(k)m(eyw)m
+(ord)g(v)-5 b(alues)36 b(and)f(other)h(columns)g(\(in)g(the)g(same)0
+2723 y(ro)m(w\).)63 b(The)37 b(full)g(syn)m(tax)i(and)e(a)m(v)-5
+b(ailable)40 b(functions)d(for)g(the)h(expression)f(are)h(describ)s(ed)
+f(b)s(elo)m(w)h(in)f(the)h(ro)m(w)0 2836 y(\014lter)30
+b(sp)s(eci\014cation)i(section.)0 2996 y(If)27 b(the)h(expression)g
+(con)m(tains)g(b)s(oth)f(a)h(list)h(of)f(columns)f(to)h(b)s(e)g
+(included)e(and)i(columns)f(to)h(b)s(e)f(deleted,)j(then)d(all)0
+3109 y(the)34 b(columns)g(in)g(the)g(original)h(table)g(except)g(the)f
+(explicitly)i(deleted)f(columns)e(will)i(app)s(ear)e(in)h(the)g
+(\014ltered)0 3222 y(table.)40 b(If)26 b(no)g(columns)f(to)i(b)s(e)f
+(deleted)g(are)h(sp)s(eci\014ed,)f(then)g(only)g(the)h(columns)e(that)i
+(are)f(explicitly)i(listed)f(will)0 3335 y(b)s(e)k(included)g(in)g(the)
+h(\014ltered)f(output)h(table.)45 b(T)-8 b(o)32 b(include)f(all)i(the)e
+(columns,)h(add)f(the)h('*')g(wildcard)g(sp)s(eci\014er)0
+3447 y(at)f(the)g(end)e(of)i(the)f(list,)i(as)e(sho)m(wn)g(in)g(the)h
+(examples.)0 3608 y(F)-8 b(or)30 b(complex)h(or)e(commonly)h(used)f(op)
+s(erations,)i(one)e(can)h(also)h(place)g(the)e(op)s(erations)h(in)m(to)
+h(an)e(external)i(text)0 3720 y(\014le)g(and)f(imp)s(ort)g(it)h(in)m
+(to)h(the)f(column)g(\014lter)f(using)h(the)g(syn)m(tax)g('[col)h
+(@\014lename.txt]'.)43 b(The)31 b(op)s(erations)g(can)0
+3833 y(extend)26 b(o)m(v)m(er)i(m)m(ultiple)f(lines)g(of)f(the)h
+(\014le,)h(but)d(m)m(ultiple)i(op)s(erations)g(m)m(ust)f(still)i(b)s(e)
+d(separated)i(b)m(y)g(semicolons.)0 3946 y(An)m(y)h(lines)h(in)f(the)g
+(external)i(text)f(\014le)f(that)h(b)s(egin)f(with)g(2)h(slash)f(c)m
+(haracters)i(\('//'\))g(will)f(b)s(e)e(ignored)i(and)e(ma)m(y)0
+4059 y(b)s(e)j(used)f(to)i(add)f(commen)m(ts)h(in)m(to)h(the)e(\014le.)
+0 4219 y(Examples:)143 4472 y Fe([col)47 b(Time;)f(rate])667
+b(-)47 b(only)g(the)g(Time)g(and)g(rate)f(columns)g(will)1670
+4585 y(appear)h(in)g(the)g(filtered)e(input)i(file.)143
+4811 y([col)g(Time,)f(*raw])667 b(-)47 b(include)f(the)h(Time)g(column)
+f(and)h(any)g(other)1670 4924 y(columns)f(whose)h(name)f(ends)h(with)g
+('raw'.)143 5149 y([col)g(-TIME;)f(Good)h(==)g(STATUS])141
+b(-)47 b(deletes)f(the)h(TIME)g(column)f(and)1670 5262
+y(renames)g(the)h(status)f(column)g(to)i('Good')143 5488
+y([col)f(PI=PHA)f(*)h(1.1)g(+)h(0.2;)e(#TUNIT#\(column)e(units\))i(=)i
+('counts';*])1575 5601 y(-)f(creates)f(new)h(PI)g(column)f(from)h(PHA)g
+(values)1670 5714 y(and)g(also)g(writes)f(the)h(TUNITn)f(keyword)p
+eop end
+%%Page: 94 100
+TeXDict begin 94 99 bop 0 299 a Fi(94)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)1670
+555 y Fe(for)47 b(the)g(new)g(column.)94 b(The)47 b(final)f('*')1670
+668 y(expression)f(means)i(preserve)e(all)i(the)1670
+781 y(columns)f(in)h(the)g(input)g(table)f(in)h(the)1670
+894 y(virtual)f(output)g(table;)94 b(without)46 b(the)h('*')1670
+1007 y(the)g(output)f(table)h(would)f(only)h(contain)1670
+1120 y(the)g(single)f('PI')h(column.)143 1346 y([col)g(rate)f(=)i
+(rate/exposure;)c(TUNIT#\(&\))h(=)j('counts/s';*])1575
+1458 y(-)f(recomputes)e(the)i(rate)g(column)f(by)h(dividing)1670
+1571 y(it)h(by)f(the)g(EXPOSURE)e(keyword)h(value.)g(This)1670
+1684 y(also)h(modifies)f(the)h(value)f(of)h(the)g(TUNITn)1670
+1797 y(keyword)f(for)h(this)g(column.)f(The)h(use)f(of)i(the)1670
+1910 y('&')f(character)f(for)h(the)f(keyword)g(comment)1670
+2023 y(string)h(means)f(preserve)f(the)i(existing)1670
+2136 y(comment)f(string)g(for)h(that)g(keyword.)e(The)1670
+2249 y(final)i('*')g(preserves)e(all)i(the)g(columns)1670
+2362 y(in)h(the)f(input)f(table)g(in)h(the)g(virtual)1670
+2475 y(output)g(table.)0 2816 y Fd(8.11)136 b(Ro)l(w)45
+b(Filtering)h(Sp)t(eci\014cation)0 3068 y Fi(When)29
+b(en)m(tering)h(the)f(name)g(of)g(a)g(FITS)f(table)i(that)g(is)e(to)i
+(b)s(e)e(op)s(ened)h(b)m(y)f(a)i(program,)f(an)g(optional)h(ro)m(w)f
+(\014lter)0 3181 y(ma)m(y)i(b)s(e)g(sp)s(eci\014ed)f(to)h(select)h(a)g
+(subset)e(of)h(the)g(ro)m(ws)f(in)h(the)g(table.)43 b(A)31
+b(temp)s(orary)f(new)g(FITS)g(\014le)h(is)g(created)0
+3294 y(on)25 b(the)h(\015y)e(whic)m(h)h(con)m(tains)h(only)g(those)g
+(ro)m(ws)f(for)g(whic)m(h)g(the)g(ro)m(w)g(\014lter)h(expression)f(ev)
+-5 b(aluates)26 b(to)g(true.)39 b(\(The)0 3407 y(primary)26
+b(arra)m(y)h(and)f(an)m(y)g(other)h(extensions)g(in)f(the)h(input)f
+(\014le)g(are)h(also)h(copied)f(to)g(the)f(temp)s(orary)h(\014le\).)39
+b(The)0 3520 y(original)30 b(FITS)f(\014le)g(is)g(closed)h(and)e(the)i
+(new)e(virtual)i(\014le)f(is)g(op)s(ened)f(b)m(y)h(the)h(application)g
+(program.)40 b(The)29 b(ro)m(w)0 3633 y(\014lter)37 b(expression)g(is)h
+(enclosed)g(in)f(square)g(brac)m(k)m(ets)i(follo)m(wing)g(the)e(\014le)
+h(name)f(and)g(extension)h(name)f(\(e.g.,)0 3745 y('\014le.\014ts[ev)m
+(en)m(ts][GRADE==50]')29 b(selects)d(only)f(those)h(ro)m(ws)f(where)f
+(the)h(GRADE)h(column)f(v)-5 b(alue)25 b(equals)g(50\).)0
+3858 y(When)33 b(dealing)h(with)f(tables)g(where)g(eac)m(h)h(ro)m(w)f
+(has)g(an)g(asso)s(ciated)i(time)f(and/or)f(2D)g(spatial)i(p)s
+(osition,)f(the)0 3971 y(ro)m(w)e(\014lter)h(expression)e(can)i(also)g
+(b)s(e)f(used)f(to)i(select)h(ro)m(ws)e(based)g(on)g(the)g(times)h(in)f
+(a)g(Go)s(o)s(d)g(Time)g(In)m(terv)-5 b(als)0 4084 y(\(GTI\))31
+b(extension,)g(or)f(on)h(spatial)g(p)s(osition)g(as)f(giv)m(en)i(in)e
+(a)g(SA)m(O-st)m(yle)i(region)f(\014le.)0 4383 y Fb(8.11.1)113
+b(General)38 b(Syn)m(tax)0 4603 y Fi(The)32 b(ro)m(w)h(\014ltering)g
+(expression)g(can)g(b)s(e)f(an)h(arbitrarily)g(complex)g(series)g(of)g
+(op)s(erations)g(p)s(erformed)f(on)g(con-)0 4716 y(stan)m(ts,)39
+b(k)m(eyw)m(ord)e(v)-5 b(alues,)38 b(and)e(column)g(data)i(tak)m(en)f
+(from)f(the)h(sp)s(eci\014ed)e(FITS)h(T)-8 b(ABLE)37
+b(extension.)59 b(The)0 4829 y(expression)37 b(m)m(ust)h(ev)-5
+b(aluate)39 b(to)g(a)f(b)s(o)s(olean)g(v)-5 b(alue)38
+b(for)f(eac)m(h)i(ro)m(w)f(of)g(the)f(table,)k(where)c(a)h(v)-5
+b(alue)39 b(of)e(F)-10 b(ALSE)0 4942 y(means)30 b(that)h(the)g(ro)m(w)f
+(will)h(b)s(e)f(excluded.)0 5102 y(F)-8 b(or)34 b(complex)g(or)g
+(commonly)f(used)g(\014lters,)h(one)g(can)g(place)g(the)g(expression)f
+(in)m(to)h(a)g(text)g(\014le)g(and)f(imp)s(ort)f(it)0
+5215 y(in)m(to)38 b(the)e(ro)m(w)h(\014lter)g(using)f(the)h(syn)m(tax)g
+('[@\014lename.txt]'.)61 b(The)36 b(expression)h(can)f(b)s(e)g
+(arbitrarily)h(complex)0 5328 y(and)27 b(extend)i(o)m(v)m(er)g(m)m
+(ultiple)g(lines)f(of)g(the)h(\014le.)40 b(An)m(y)28
+b(lines)g(in)g(the)g(external)h(text)g(\014le)f(that)h(b)s(egin)f(with)
+g(2)g(slash)0 5441 y(c)m(haracters)k(\('//'\))g(will)f(b)s(e)f(ignored)
+g(and)g(ma)m(y)h(b)s(e)f(used)f(to)i(add)f(commen)m(ts)h(in)m(to)h(the)
+e(\014le.)0 5601 y(Keyw)m(ord)37 b(and)f(column)g(data)i(are)f
+(referenced)g(b)m(y)g(name.)60 b(An)m(y)37 b(string)f(of)h(c)m
+(haracters)i(not)e(surrounded)d(b)m(y)0 5714 y(quotes)41
+b(\(ie,)j(a)d(constan)m(t)h(string\))f(or)f(follo)m(w)m(ed)i(b)m(y)f
+(an)f(op)s(en)g(paren)m(theses)h(\(ie,)j(a)d(function)f(name\))h(will)g
+(b)s(e)p eop end
+%%Page: 95 101
+TeXDict begin 95 100 bop 0 299 a Fg(8.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)30 b(SPECIFICA)-8 b(TION)2027 b Fi(95)0
+555 y(initially)38 b(in)m(terpreted)e(as)h(a)g(column)f(name)g(and)g
+(its)h(con)m(ten)m(ts)h(for)e(the)h(curren)m(t)f(ro)m(w)g(inserted)g
+(in)m(to)i(the)e(ex-)0 668 y(pression.)k(If)28 b(no)h(suc)m(h)g(column)
+g(exists,)h(a)g(k)m(eyw)m(ord)f(of)h(that)f(name)g(will)h(b)s(e)e
+(searc)m(hed)i(for)f(and)f(its)i(v)-5 b(alue)29 b(used,)0
+781 y(if)36 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)h(as)g(a)g(k)m(eyw)m(ord)g(\(in)g(case)g(there)g
+(is)g(b)s(oth)f(a)h(column)g(and)0 894 y(k)m(eyw)m(ord)41
+b(with)e(the)i(same)f(name\),)j(precede)d(the)h(k)m(eyw)m(ord)f(name)g
+(with)g(a)h(single)f(p)s(ound)e(sign,)43 b('#',)g(as)d(in)0
+1007 y('#NAXIS2'.)g(Due)27 b(to)g(the)f(generalities)j(of)d(FITS)g
+(column)g(and)g(k)m(eyw)m(ord)h(names,)g(if)f(the)h(column)f(or)g(k)m
+(eyw)m(ord)0 1120 y(name)33 b(con)m(tains)h(a)f(space)h(or)f(a)g(c)m
+(haracter)h(whic)m(h)f(migh)m(t)h(app)s(ear)e(as)h(an)g(arithmetic)h
+(term)f(then)g(enclose)h(the)0 1233 y(name)c(in)g('$')i(c)m(haracters)g
+(as)e(in)g($MAX)i(PHA$)f(or)f(#$MAX-PHA$.)43 b(Names)31
+b(are)f(case)i(insensitiv)m(e.)0 1393 y(T)-8 b(o)32 b(access)g(a)g
+(table)g(en)m(try)g(in)f(a)h(ro)m(w)f(other)h(than)f(the)g(curren)m(t)g
+(one,)h(follo)m(w)h(the)e(column's)h(name)f(with)g(a)h(ro)m(w)0
+1506 y(o\013set)37 b(within)e(curly)g(braces.)57 b(F)-8
+b(or)36 b(example,)i('PHA)p Fc(f)p Fi(-3)p Fc(g)p Fi(')g(will)e(ev)-5
+b(aluate)38 b(to)e(the)g(v)-5 b(alue)36 b(of)g(column)f(PHA,)i(3)0
+1619 y(ro)m(ws)28 b(ab)s(o)m(v)m(e)i(the)e(ro)m(w)h(curren)m(tly)f(b)s
+(eing)g(pro)s(cessed.)40 b(One)28 b(cannot)h(sp)s(ecify)f(an)g
+(absolute)h(ro)m(w)f(n)m(um)m(b)s(er,)g(only)h(a)0 1732
+y(relativ)m(e)j(o\013set.)42 b(Ro)m(ws)31 b(that)g(fall)g(outside)g
+(the)f(table)h(will)g(b)s(e)f(treated)h(as)g(unde\014ned,)d(or)j
+(NULLs.)0 1892 y(Bo)s(olean)h(op)s(erators)f(can)g(b)s(e)f(used)f(in)i
+(the)f(expression)h(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 2005 y(b)s(o)s(olean)g
+(op)s(erators)h(are)g(a)m(v)-5 b(ailable:)191 2247 y
+Fe("equal")428 b(.eq.)46 b(.EQ.)h(==)95 b("not)46 b(equal")476
+b(.ne.)94 b(.NE.)h(!=)191 2360 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 2473 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 2585 y("or")572 b(.or.)46 b(.OR.)h(||)95
+b("and")762 b(.and.)46 b(.AND.)h(&&)191 2698 y("negation")236
+b(.not.)46 b(.NOT.)h(!)95 b("approx.)45 b(equal\(1e-7\)")92
+b(~)0 2940 y Fi(Note)32 b(that)g(the)f(exclamation)i(p)s(oin)m(t,)e(')
+10 b(!',)33 b(is)e(a)g(sp)s(ecial)g(UNIX)h(c)m(haracter,)h(so)e(if)g
+(it)g(is)g(used)f(on)h(the)g(command)0 3053 y(line)i(rather)f(than)h
+(en)m(tered)g(at)g(a)g(task)g(prompt,)g(it)g(m)m(ust)f(b)s(e)g
+(preceded)h(b)m(y)f(a)h(bac)m(kslash)g(to)h(force)f(the)g(UNIX)0
+3166 y(shell)e(to)g(ignore)g(it.)0 3326 y(The)h(expression)g(ma)m(y)i
+(also)f(include)f(arithmetic)i(op)s(erators)f(and)f(functions.)47
+b(T)-8 b(rigonometric)34 b(functions)e(use)0 3439 y(radians,)23
+b(not)g(degrees.)38 b(The)22 b(follo)m(wing)h(arithmetic)g(op)s
+(erators)g(and)e(functions)g(can)i(b)s(e)e(used)g(in)h(the)g
+(expression)0 3552 y(\(function)38 b(names)f(are)h(case)g(insensitiv)m
+(e\).)64 b(A)37 b(n)m(ull)h(v)-5 b(alue)38 b(will)f(b)s(e)g(returned)g
+(in)g(case)h(of)g(illegal)i(op)s(erations)0 3665 y(suc)m(h)30
+b(as)h(divide)f(b)m(y)g(zero,)i(sqrt\(negativ)m(e\))h(log\(negativ)m
+(e\),)h(log10\(negativ)m(e\),)i(arccos\(.gt.)43 b(1\),)32
+b(arcsin\(.gt.)42 b(1\).)191 3907 y Fe("addition")522
+b(+)477 b("subtraction")d(-)191 4020 y("multiplication")234
+b(*)477 b("division")618 b(/)191 4133 y("negation")522
+b(-)477 b("exponentiation")330 b(**)143 b(^)191 4246
+y("absolute)45 b(value")237 b(abs\(x\))g("cosine")714
+b(cos\(x\))191 4359 y("sine")g(sin\(x\))237 b("tangent")666
+b(tan\(x\))191 4472 y("arc)47 b(cosine")427 b(arccos\(x\))93
+b("arc)47 b(sine")619 b(arcsin\(x\))191 4585 y("arc)47
+b(tangent")379 b(arctan\(x\))93 b("arc)47 b(tangent")475
+b(arctan2\(y,x\))191 4698 y("hyperbolic)45 b(cos")237
+b(cosh\(x\))189 b("hyperbolic)45 b(sin")333 b(sinh\(x\))191
+4811 y("hyperbolic)45 b(tan")237 b(tanh\(x\))189 b("round)46
+b(to)h(nearest)f(int")h(round\(x\))191 4924 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 5036 y("exponential")378 b(exp\(x\))237
+b("square)46 b(root")476 b(sqrt\(x\))191 5149 y("natural)45
+b(log")381 b(log\(x\))237 b("common)46 b(log")524 b(log10\(x\))191
+5262 y("modulus")570 b(x)48 b(\045)f(y)286 b("random)46
+b(#)h([0.0,1.0\)")141 b(random\(\))191 5375 y("random)46
+b(Gaussian")188 b(randomn\(\))93 b("random)46 b(Poisson")332
+b(randomp\(x\))191 5488 y("minimum")570 b(min\(x,y\))141
+b("maximum")666 b(max\(x,y\))191 5601 y("cumulative)45
+b(sum")237 b(accum\(x\))93 b("sequential)45 b(difference")g
+(seqdiff\(x\))191 5714 y("if-then-else")330 b(b?x:y)p
+eop end
+%%Page: 96 102
+TeXDict begin 96 101 bop 0 299 a Fi(96)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)191
+555 y Fe("angular)45 b(separation")93 b(angsep\(ra1,dec1,ra2,de2\))41
+b(\(all)47 b(in)g(degrees\))191 668 y("substring")283
+b(strmid\(s,p,n\))44 b("string)i(search")428 b(strstr\(s,r\))0
+907 y Fi(Three)30 b(di\013eren)m(t)h(random)f(n)m(um)m(b)s(er)f
+(functions)h(are)h(pro)m(vided:)41 b(random\(\),)30 b(with)h(no)f
+(argumen)m(ts,)h(pro)s(duces)f(a)0 1020 y(uniform)g(random)f(deviate)k
+(b)s(et)m(w)m(een)e(0)g(and)f(1;)i(randomn\(\),)e(also)i(with)e(no)h
+(argumen)m(ts,)g(pro)s(duces)f(a)h(normal)0 1133 y(\(Gaussian\))k
+(random)e(deviate)j(with)e(zero)h(mean)f(and)g(unit)f(standard)h
+(deviation;)j(randomp\(x\))d(pro)s(duces)f(a)0 1245 y(P)m(oisson)27
+b(random)f(deviate)h(whose)f(exp)s(ected)h(n)m(um)m(b)s(er)e(of)h(coun)
+m(ts)h(is)g(X.)f(X)h(ma)m(y)g(b)s(e)e(an)m(y)i(p)s(ositiv)m(e)g(real)g
+(n)m(um)m(b)s(er)0 1358 y(of)k(exp)s(ected)f(coun)m(ts,)h(including)f
+(fractional)i(v)-5 b(alues,)31 b(but)f(the)g(return)g(v)-5
+b(alue)31 b(is)f(an)g(in)m(teger.)0 1519 y(When)d(the)g(random)g
+(functions)f(are)i(used)e(in)h(a)h(v)m(ector)g(expression,)g(b)m(y)f
+(default)h(the)f(same)h(random)e(v)-5 b(alue)28 b(will)0
+1631 y(b)s(e)g(used)f(when)h(ev)-5 b(aluating)30 b(eac)m(h)f(elemen)m
+(t)h(of)f(the)g(v)m(ector.)41 b(If)28 b(di\013eren)m(t)h(random)f(n)m
+(um)m(b)s(ers)f(are)i(desired,)f(then)0 1744 y(the)37
+b(name)g(of)g(a)g(v)m(ector)i(column)e(should)e(b)s(e)i(supplied)e(as)i
+(the)h(single)f(argumen)m(t)g(to)h(the)f(random)f(function)0
+1857 y(\(e.g.,)31 b("\015ux)c(+)h(0.1)h(*)g(random\(\015ux\)",)f(where)
+g("\015ux')g(is)g(the)g(name)h(of)f(a)h(v)m(ector)h(column\).)40
+b(This)27 b(will)i(create)h(a)0 1970 y(v)m(ector)d(of)f(random)f(n)m
+(um)m(b)s(ers)f(that)i(will)g(b)s(e)f(used)f(in)i(sequence)g(when)e(ev)
+-5 b(aluating)27 b(eac)m(h)g(elemen)m(t)g(of)f(the)f(v)m(ector)0
+2083 y(expression.)0 2243 y(An)31 b(alternate)i(syn)m(tax)f(for)f(the)g
+(min)g(and)g(max)g(functions)g(has)g(only)g(a)h(single)g(argumen)m(t)g
+(whic)m(h)f(should)f(b)s(e)h(a)0 2356 y(v)m(ector)g(v)-5
+b(alue)30 b(\(see)g(b)s(elo)m(w\).)41 b(The)29 b(result)g(will)h(b)s(e)
+e(the)i(minim)m(um/maxim)m(um)f(elemen)m(t)h(con)m(tained)h(within)e
+(the)0 2469 y(v)m(ector.)0 2629 y(The)35 b(accum\(x\))i(function)f
+(forms)f(the)h(cum)m(ulativ)m(e)i(sum)d(of)h(x,)h(elemen)m(t)h(b)m(y)e
+(elemen)m(t.)58 b(V)-8 b(ector)38 b(columns)e(are)0 2742
+y(supp)s(orted)h(simply)h(b)m(y)g(p)s(erforming)f(the)i(summation)g
+(pro)s(cess)f(through)f(all)j(the)f(v)-5 b(alues.)65
+b(Null)39 b(v)-5 b(alues)39 b(are)0 2855 y(treated)30
+b(as)f(0.)41 b(The)29 b(seqdi\013\(x\))h(function)e(forms)h(the)g
+(sequen)m(tial)i(di\013erence)e(of)h(x,)f(elemen)m(t)i(b)m(y)e(elemen)m
+(t.)41 b(The)0 2968 y(\014rst)36 b(v)-5 b(alue)38 b(of)f(seqdi\013)g
+(is)g(the)g(\014rst)g(v)-5 b(alue)37 b(of)g(x.)61 b(A)37
+b(single)h(n)m(ull)f(v)-5 b(alue)38 b(in)e(x)h(causes)h(a)f(pair)g(of)g
+(n)m(ulls)g(in)g(the)0 3081 y(output.)55 b(The)35 b(seqdi\013)g(and)g
+(accum)g(functions)g(are)h(functional)f(in)m(v)m(erses,)j(i.e.,)g
+(seqdi\013\(accum\(x\)\))f(==)e(x)g(as)0 3194 y(long)c(as)g(no)f(n)m
+(ull)g(v)-5 b(alues)31 b(are)g(presen)m(t.)0 3354 y(In)36
+b(the)h(if-then-else)i(expression,)f("b?x:y",)i(b)c(is)h(an)g(explicit)
+h(b)s(o)s(olean)f(v)-5 b(alue)37 b(or)g(expression.)61
+b(There)36 b(is)h(no)0 3467 y(automatic)d(t)m(yp)s(e)e(con)m(v)m
+(ersion)h(from)e(n)m(umeric)h(to)g(b)s(o)s(olean)g(v)-5
+b(alues,)33 b(so)f(one)g(needs)f(to)i(use)e("iV)-8 b(al!=0")35
+b(instead)0 3580 y(of)30 b(merely)g("iV)-8 b(al")32 b(as)e(the)g(b)s(o)
+s(olean)g(argumen)m(t.)41 b(x)30 b(and)f(y)h(can)g(b)s(e)f(an)m(y)h
+(scalar)h(data)g(t)m(yp)s(e)f(\(including)f(string\).)0
+3740 y(The)22 b(angsep)g(function)f(computes)i(the)f(angular)g
+(separation)h(in)e(degrees)i(b)s(et)m(w)m(een)g(2)f(celestial)j(p)s
+(ositions,)e(where)0 3853 y(the)36 b(\014rst)f(2)h(parameters)g(giv)m
+(e)h(the)f(RA-lik)m(e)i(and)d(Dec-lik)m(e)j(co)s(ordinates)f(\(in)f
+(decimal)g(degrees\))h(of)f(the)g(\014rst)0 3966 y(p)s(osition,)31
+b(and)e(the)i(3rd)f(and)g(4th)g(parameters)h(giv)m(e)h(the)e(co)s
+(ordinates)i(of)e(the)h(second)f(p)s(osition.)0 4126
+y(The)38 b(substring)f(function)i(strmid\(S,P)-8 b(,N\))39
+b(extracts)g(a)g(substring)f(from)g(S,)g(starting)h(at)g(string)g(p)s
+(osition)f(P)-8 b(,)0 4239 y(with)33 b(a)h(substring)f(length)h(N.)g
+(The)f(\014rst)g(c)m(haracter)j(p)s(osition)d(in)h(S)f(is)h(lab)s(eled)
+g(as)g(1.)51 b(If)33 b(P)g(is)h(0,)h(or)f(refers)f(to)0
+4352 y(a)i(p)s(osition)g(b)s(ey)m(ond)f(the)h(end)e(of)i(S,)g(then)f
+(the)h(extracted)h(substring)d(will)i(b)s(e)f(NULL.)h(S,)f(P)-8
+b(,)36 b(and)e(N)g(ma)m(y)i(b)s(e)0 4465 y(functions)30
+b(of)g(other)h(columns.)0 4625 y(The)39 b(string)h(searc)m(h)h
+(function)e(strstr\(S,R\))h(searc)m(hes)h(for)f(the)g(\014rst)f(o)s
+(ccurrence)h(of)g(the)g(substring)f(R)h(in)f(S.)0 4738
+y(The)c(result)h(is)f(an)h(in)m(teger,)i(indicating)f(the)e(c)m
+(haracter)i(p)s(osition)f(of)g(the)g(\014rst)e(matc)m(h)j(\(where)e(1)h
+(is)g(the)g(\014rst)0 4851 y(c)m(haracter)c(p)s(osition)e(of)h(S\).)f
+(If)g(no)h(matc)m(h)g(is)f(found,)g(then)g(strstr\(\))g(returns)f(a)i
+(NULL)f(v)-5 b(alue.)0 5011 y(The)37 b(follo)m(wing)i(t)m(yp)s(e)f
+(casting)g(op)s(erators)g(are)g(a)m(v)-5 b(ailable,)42
+b(where)37 b(the)h(enclosing)g(paren)m(theses)g(are)g(required)0
+5124 y(and)30 b(tak)m(en)h(from)f(the)h(C)f(language)h(usage.)42
+b(Also,)31 b(the)g(in)m(teger)g(to)h(real)f(casts)g(v)-5
+b(alues)30 b(to)i(double)e(precision:)764 5362 y Fe("real)46
+b(to)h(integer")189 b(\(int\))46 b(x)239 b(\(INT\))46
+b(x)764 5475 y("integer)f(to)i(real")190 b(\(float\))46
+b(i)143 b(\(FLOAT\))45 b(i)0 5714 y Fi(In)30 b(addition,)g(sev)m(eral)i
+(constan)m(ts)g(are)f(built)f(in)g(for)g(use)g(in)g(n)m(umerical)h
+(expressions:)p eop end
+%%Page: 97 103
+TeXDict begin 97 102 bop 0 299 a Fg(8.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)30 b(SPECIFICA)-8 b(TION)2027 b Fi(97)382
+555 y Fe(#pi)667 b(3.1415...)284 b(#e)620 b(2.7182...)382
+668 y(#deg)f(#pi/180)380 b(#row)524 b(current)46 b(row)h(number)382
+781 y(#null)428 b(undefined)45 b(value)142 b(#snull)428
+b(undefined)45 b(string)0 1040 y Fi(A)40 b(string)f(constan)m(t)i(m)m
+(ust)e(b)s(e)g(enclosed)h(in)g(quotes)g(as)f(in)h('Crab'.)67
+b(The)39 b("n)m(ull")i(constan)m(ts)f(are)g(useful)f(for)0
+1153 y(conditionally)g(setting)g(table)g(v)-5 b(alues)38
+b(to)g(a)g(NULL,)g(or)g(unde\014ned,)f(v)-5 b(alue)39
+b(\(eg.,)i("col1==-99)f(?)62 b(#NULL)38 b(:)0 1266 y(col1"\).)0
+1426 y(There)27 b(is)g(also)i(a)e(function)g(for)h(testing)g(if)f(t)m
+(w)m(o)i(v)-5 b(alues)28 b(are)g(close)g(to)h(eac)m(h)f(other,)h(i.e.,)
+g(if)e(they)h(are)g("near")g(eac)m(h)0 1539 y(other)c(to)h(within)e(a)h
+(user)g(sp)s(eci\014ed)f(tolerance.)40 b(The)24 b(argumen)m(ts,)h(v)-5
+b(alue)p 2502 1539 28 4 v 34 w(1)24 b(and)f(v)-5 b(alue)p
+2979 1539 V 33 w(2)25 b(can)f(b)s(e)f(in)m(teger)i(or)f(real)0
+1652 y(and)32 b(represen)m(t)h(the)g(t)m(w)m(o)h(v)-5
+b(alues)33 b(who's)f(pro)m(ximit)m(y)i(is)f(b)s(eing)f(tested)h(to)h(b)
+s(e)e(within)g(the)h(sp)s(eci\014ed)f(tolerance,)0 1765
+y(also)f(an)g(in)m(teger)g(or)g(real:)955 2023 y Fe(near\(value_1,)44
+b(value_2,)h(tolerance\))0 2282 y Fi(When)24 b(a)i(NULL,)e(or)h
+(unde\014ned,)f(v)-5 b(alue)25 b(is)g(encoun)m(tered)g(in)g(the)f(FITS)
+g(table,)j(the)e(expression)g(will)g(ev)-5 b(aluate)26
+b(to)0 2395 y(NULL)31 b(unless)f(the)h(unde\014ned)e(v)-5
+b(alue)31 b(is)g(not)g(actually)h(required)e(for)h(ev)-5
+b(aluation,)33 b(e.g.)43 b("TR)m(UE)31 b(.or.)43 b(NULL")0
+2508 y(ev)-5 b(aluates)32 b(to)f(TR)m(UE.)g(The)f(follo)m(wing)h(t)m(w)
+m(o)h(functions)e(allo)m(w)i(some)f(NULL)f(detection)i(and)e(handling:)
+430 2767 y Fe("a)47 b(null)f(value?")667 b(ISNULL\(x\))430
+2880 y("define)45 b(a)j(value)e(for)h(null")190 b(DEFNULL\(x,y\))0
+3139 y Fi(The)36 b(former)h(returns)e(a)i(b)s(o)s(olean)g(v)-5
+b(alue)37 b(of)g(TR)m(UE)g(if)g(the)g(argumen)m(t)g(x)g(is)g(NULL.)g
+(The)f(later)i("de\014nes")f(a)0 3252 y(v)-5 b(alue)35
+b(to)g(b)s(e)e(substituted)h(for)g(NULL)g(v)-5 b(alues;)37
+b(it)e(returns)e(the)h(v)-5 b(alue)35 b(of)f(x)g(if)g(x)h(is)f(not)g
+(NULL,)h(otherwise)f(it)0 3365 y(returns)29 b(the)i(v)-5
+b(alue)31 b(of)f(y)-8 b(.)0 3655 y Fb(8.11.2)113 b(Bit)36
+b(Masks)0 3874 y Fi(Bit)g(masks)f(can)h(b)s(e)f(used)f(to)i(select)h
+(out)e(ro)m(ws)h(from)e(bit)i(columns)f(\(TF)m(ORMn)g(=)g(#X\))h(in)f
+(FITS)f(\014les.)55 b(T)-8 b(o)0 3987 y(represen)m(t)30
+b(the)h(mask,)g(binary)-8 b(,)30 b(o)s(ctal,)i(and)e(hex)g(formats)g
+(are)h(allo)m(w)m(ed:)811 4246 y Fe(binary:)142 b
+(b0110xx1010000101xxxx00)o(01)811 4359 y(octal:)190 b(o720x1)46
+b(->)h(\(b111010000xxx001\))811 4471 y(hex:)286 b(h0FxD)94
+b(->)47 b(\(b00001111xxxx1101\))0 4730 y Fi(In)22 b(all)i(the)f
+(represen)m(tations,)j(an)c(x)h(or)g(X)g(is)g(allo)m(w)m(ed)i(in)d(the)
+h(mask)g(as)g(a)h(wild)e(card.)38 b(Note)25 b(that)e(the)g(x)g
+(represen)m(ts)0 4843 y(a)k(di\013eren)m(t)h(n)m(um)m(b)s(er)e(of)h
+(wild)f(card)h(bits)g(in)g(eac)m(h)h(represen)m(tation.)41
+b(All)27 b(represen)m(tations)h(are)g(case)g(insensitiv)m(e.)0
+5003 y(T)-8 b(o)28 b(construct)g(the)g(b)s(o)s(olean)f(expression)h
+(using)f(the)h(mask)f(as)h(the)g(b)s(o)s(olean)f(equal)h(op)s(erator)g
+(describ)s(ed)f(ab)s(o)m(v)m(e)0 5116 y(on)34 b(a)h(bit)g(table)h
+(column.)53 b(F)-8 b(or)35 b(example,)i(if)d(y)m(ou)h(had)f(a)h(7)g
+(bit)g(column)f(named)g(\015ags)h(in)f(a)h(FITS)f(table)i(and)0
+5229 y(w)m(an)m(ted)31 b(all)g(ro)m(ws)g(ha)m(ving)g(the)f(bit)h
+(pattern)f(0010011,)k(the)c(selection)j(expression)d(w)m(ould)g(b)s(e:)
+1336 5488 y Fe(flags)47 b(==)g(b0010011)191 5601 y(or)1336
+5714 y(flags)g(.eq.)f(b10011)p eop end
+%%Page: 98 104
+TeXDict begin 98 103 bop 0 299 a Fi(98)1618 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)0
+555 y Fi(It)35 b(is)g(also)h(p)s(ossible)e(to)i(test)g(if)f(a)g(range)g
+(of)g(bits)g(is)g(less)g(than,)h(less)f(than)g(equal,)i(greater)f(than)
+e(and)h(greater)0 668 y(than)30 b(equal)h(to)g(a)g(particular)g(b)s(o)s
+(olean)f(v)-5 b(alue:)1336 922 y Fe(flags)47 b(<=)g(bxxx010xx)1336
+1035 y(flags)g(.gt.)f(bxxx100xx)1336 1148 y(flags)h(.le.)f(b1xxxxxxx)0
+1402 y Fi(Notice)32 b(the)f(use)f(of)h(the)f(x)g(bit)h(v)-5
+b(alue)31 b(to)g(limit)g(the)f(range)h(of)g(bits)f(b)s(eing)g
+(compared.)0 1563 y(It)i(is)h(not)f(necessary)h(to)g(sp)s(ecify)f(the)h
+(leading)g(\(most)g(signi\014can)m(t\))h(zero)f(\(0\))g(bits)f(in)g
+(the)h(mask,)g(as)g(sho)m(wn)e(in)0 1675 y(the)g(second)f(expression)g
+(ab)s(o)m(v)m(e.)0 1836 y(Bit)44 b(wise)f(AND,)h(OR)e(and)g(NOT)h(op)s
+(erations)g(are)g(also)h(p)s(ossible)e(on)h(t)m(w)m(o)h(or)f(more)g
+(bit)g(\014elds)f(using)h(the)0 1949 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)34 b(of)f(these)h(op)s(erators)g(result)f(in)h
+(a)g(bit)f(\014eld)g(whic)m(h)0 2061 y(can)e(then)f(b)s(e)f(used)h
+(with)g(the)h(equal)g(op)s(erator.)41 b(F)-8 b(or)31
+b(example:)1241 2316 y Fe(\(!flags\))45 b(==)j(b1101100)1241
+2429 y(\(flags)e(&)h(b1000001\))f(==)h(bx000001)0 2683
+y Fi(Bit)35 b(\014elds)f(can)g(b)s(e)f(app)s(ended)g(as)h(w)m(ell)h
+(using)f(the)g('+')g(op)s(erator.)53 b(Strings)33 b(can)i(b)s(e)e
+(concatenated)j(this)e(w)m(a)m(y)-8 b(,)0 2796 y(to)s(o.)0
+3086 y Fb(8.11.3)113 b(V)-9 b(ector)36 b(Columns)0 3304
+y Fi(V)-8 b(ector)37 b(columns)e(can)h(also)g(b)s(e)f(used)f(in)h
+(building)g(the)g(expression.)56 b(No)36 b(sp)s(ecial)g(syn)m(tax)f(is)
+h(required)e(if)i(one)0 3417 y(w)m(an)m(ts)46 b(to)f(op)s(erate)h(on)f
+(all)h(elemen)m(ts)g(of)f(the)h(v)m(ector.)86 b(Simply)44
+b(use)h(the)g(column)g(name)g(as)g(for)g(a)g(scalar)0
+3530 y(column.)d(V)-8 b(ector)32 b(columns)f(can)g(b)s(e)f(freely)h(in)
+m(termixed)h(with)e(scalar)i(columns)e(or)h(constan)m(ts)h(in)f
+(virtually)g(all)0 3643 y(expressions.)40 b(The)29 b(result)g(will)g(b)
+s(e)g(of)g(the)g(same)h(dimension)e(as)i(the)f(v)m(ector.)42
+b(Tw)m(o)29 b(v)m(ectors)i(in)e(an)g(expression,)0 3756
+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)h(and)e(ha)m(v)m(e)j(the)e(same)g(dimensions.)39
+b(The)26 b(only)h(places)0 3869 y(a)35 b(v)m(ector)h(column)e(cannot)h
+(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)h(functions)f(and)f(the)i(NEAR)0 3982 y(b)s(o)s(olean)30
+b(function.)0 4142 y(Arithmetic)24 b(and)e(logical)k(op)s(erations)d
+(are)h(all)g(p)s(erformed)d(on)i(an)g(elemen)m(t)h(b)m(y)f(elemen)m(t)i
+(basis.)38 b(Comparing)23 b(t)m(w)m(o)0 4255 y(v)m(ector)32
+b(columns,)e(eg)h("COL1)f(==)g(COL2",)g(th)m(us)g(results)g(in)g
+(another)g(v)m(ector)i(of)e(b)s(o)s(olean)h(v)-5 b(alues)30
+b(indicating)0 4368 y(whic)m(h)g(elemen)m(ts)i(of)e(the)h(t)m(w)m(o)h
+(v)m(ectors)f(are)g(equal.)0 4528 y(Eigh)m(t)g(functions)f(are)h(a)m(v)
+-5 b(ailable)33 b(that)e(op)s(erate)g(on)f(a)h(v)m(ector)h(and)d
+(return)h(a)g(scalar)i(result:)191 4782 y Fe("minimum")284
+b(MIN\(V\))475 b("maximum")714 b(MAX\(V\))191 4895 y("average")284
+b(AVERAGE\(V\))f("median")762 b(MEDIAN\(V\))191 5008
+y("summation")188 b(SUM\(V\))475 b("standard)46 b(deviation")188
+b(STDDEV\(V\))191 5121 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
+5375 y Fi(where)40 b(V)h(represen)m(ts)g(the)g(name)g(of)h(a)f(v)m
+(ector)h(column)f(or)g(a)h(man)m(ually)f(constructed)g(v)m(ector)i
+(using)d(curly)0 5488 y(brac)m(k)m(ets)27 b(as)f(describ)s(ed)e(b)s
+(elo)m(w.)39 b(The)25 b(\014rst)g(6)h(of)g(these)g(functions)f(ignore)h
+(an)m(y)g(n)m(ull)f(v)-5 b(alues)26 b(in)f(the)h(v)m(ector)h(when)0
+5601 y(computing)k(the)f(result.)41 b(The)30 b(STDDEV\(\))h(function)g
+(computes)f(the)h(sample)g(standard)e(deviation,)j(i.e.)42
+b(it)31 b(is)0 5714 y(prop)s(ortional)f(to)h(1/SQR)-8
+b(T\(N-1\))32 b(instead)f(of)g(1/SQR)-8 b(T\(N\),)31
+b(where)f(N)h(is)f(NV)-10 b(ALID\(V\).)p eop end
+%%Page: 99 105
+TeXDict begin 99 104 bop 0 299 a Fg(8.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)30 b(SPECIFICA)-8 b(TION)2027 b Fi(99)0
+555 y(The)32 b(SUM)h(function)f(literally)j(sums)c(all)j(the)f(elemen)m
+(ts)h(in)f(x,)g(returning)f(a)h(scalar)h(v)-5 b(alue.)48
+b(If)32 b(x)h(is)g(a)g(b)s(o)s(olean)0 668 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.)
+60 b(The)36 b(NELEM)g(function)g(returns)f(the)h(n)m(um)m(b)s(er)0
+781 y(of)i(elemen)m(ts)h(in)f(v)m(ector)h(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)f(elemen)
+m(ts)j(in)d(the)h(v)m(ector.)0 894 y(\(NELEM)28 b(also)h(op)s(erates)f
+(on)g(bit)f(and)g(string)h(columns,)g(returning)f(their)h(column)f
+(widths.\))40 b(As)27 b(an)h(example,)0 1007 y(to)42
+b(test)g(whether)f(all)h(elemen)m(ts)h(of)f(t)m(w)m(o)g(v)m(ectors)h
+(satisfy)f(a)g(giv)m(en)g(logical)i(comparison,)g(one)e(can)g(use)f
+(the)0 1120 y(expression)668 1374 y Fe(SUM\()47 b(COL1)f(>)i(COL2)f(\))
+g(==)g(NELEM\()f(COL1)h(\))0 1629 y Fi(whic)m(h)32 b(will)g(return)f
+(TR)m(UE)h(if)g(all)h(elemen)m(ts)g(of)f(COL1)g(are)g(greater)h(than)f
+(their)g(corresp)s(onding)f(elemen)m(ts)i(in)0 1742 y(COL2.)0
+1902 y(T)-8 b(o)32 b(sp)s(ecify)f(a)i(single)f(elemen)m(t)h(of)f(a)g(v)
+m(ector,)i(giv)m(e)f(the)f(column)f(name)h(follo)m(w)m(ed)h(b)m(y)f(a)g
+(comma-separated)h(list)0 2015 y(of)c(co)s(ordinates)g(enclosed)h(in)e
+(square)h(brac)m(k)m(ets.)41 b(F)-8 b(or)30 b(example,)g(if)e(a)h(v)m
+(ector)i(column)d(named)h(PHAS)f(exists)h(in)0 2128 y(the)e(table)g(as)
+g(a)g(one)g(dimensional,)h(256)g(comp)s(onen)m(t)f(list)g(of)g(n)m(um)m
+(b)s(ers)e(from)h(whic)m(h)h(y)m(ou)g(w)m(an)m(ted)g(to)g(select)i(the)
+0 2241 y(57th)j(comp)s(onen)m(t)g(for)f(use)g(in)g(the)h(expression,)f
+(then)h(PHAS[57])g(w)m(ould)f(do)h(the)f(tric)m(k.)45
+b(Higher)32 b(dimensional)0 2354 y(arra)m(ys)41 b(of)h(data)f(ma)m(y)h
+(app)s(ear)f(in)f(a)i(column.)73 b(But)41 b(in)g(order)f(to)i(in)m
+(terpret)f(them,)j(the)e(TDIMn)e(k)m(eyw)m(ord)0 2466
+y(m)m(ust)34 b(app)s(ear)g(in)g(the)g(header.)52 b(Assuming)34
+b(that)h(a)f(\(4,4,4,4\))k(arra)m(y)c(is)h(pac)m(k)m(ed)g(in)m(to)g
+(eac)m(h)h(ro)m(w)e(of)g(a)h(column)0 2579 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)
+g(of)g(eac)m(h)g(ro)m(w)g(is)f(accessed)i(b)m(y)e(ARRA)-8
+b(Y4D[1,2,3,4].)0 2692 y(Arra)m(ys)33 b(up)e(to)j(dimension)e(5)h(are)f
+(curren)m(tly)h(supp)s(orted.)46 b(Eac)m(h)33 b(v)m(ector)h(index)e
+(can)h(itself)g(b)s(e)f(an)h(expression,)0 2805 y(although)39
+b(it)g(m)m(ust)g(ev)-5 b(aluate)40 b(to)f(an)g(in)m(teger)h(v)-5
+b(alue)39 b(within)f(the)h(b)s(ounds)d(of)j(the)g(v)m(ector.)67
+b(V)-8 b(ector)40 b(columns)0 2918 y(whic)m(h)31 b(con)m(tain)h(spaces)
+g(or)f(arithmetic)h(op)s(erators)g(m)m(ust)f(ha)m(v)m(e)h(their)f
+(names)g(enclosed)h(in)f("$")h(c)m(haracters)h(as)0 3031
+y(with)d($ARRA)-8 b(Y-4D$[1,2,3,4].)0 3191 y(A)45 b(more)f(C-lik)m(e)i
+(syn)m(tax)g(for)e(sp)s(ecifying)g(v)m(ector)j(indices)d(is)h(also)h(a)
+m(v)-5 b(ailable.)85 b(The)45 b(elemen)m(t)h(used)d(in)i(the)0
+3304 y(preceding)28 b(example)h(alternativ)m(ely)i(could)d(b)s(e)g(sp)s
+(eci\014ed)g(with)f(the)i(syn)m(tax)g(ARRA)-8 b(Y4D[4][3][2][1].)45
+b(Note)30 b(the)0 3417 y(rev)m(erse)40 b(order)f(of)h(indices)f(\(as)h
+(in)f(C\),)h(as)f(w)m(ell)i(as)e(the)h(fact)g(that)g(the)g(v)-5
+b(alues)40 b(are)f(still)i(ones-based)e(\(as)h(in)0 3530
+y(F)-8 b(ortran)39 b({)g(adopted)g(to)g(a)m(v)m(oid)h(am)m(biguit)m(y)g
+(for)f(1D)g(v)m(ectors\).)67 b(With)39 b(this)g(syn)m(tax,)i(one)e(do)s
+(es)f(not)h(need)f(to)0 3643 y(sp)s(ecify)30 b(all)h(of)g(the)f
+(indices.)41 b(T)-8 b(o)31 b(extract)h(a)f(3D)g(slice)g(of)g(this)f(4D)
+h(arra)m(y)-8 b(,)32 b(use)e(ARRA)-8 b(Y4D[4].)0 3803
+y(V)g(ariable-length)33 b(v)m(ector)f(columns)e(are)g(not)h(supp)s
+(orted.)0 3963 y(V)-8 b(ectors)24 b(can)e(b)s(e)f(man)m(ually)h
+(constructed)h(within)e(the)h(expression)g(using)f(a)h(comma-separated)
+i(list)f(of)f(elemen)m(ts)0 4076 y(surrounded)35 b(b)m(y)j(curly)g
+(braces)h(\(')p Fc(fg)p Fi('\).)66 b(F)-8 b(or)38 b(example,)j(')p
+Fc(f)p Fi(1,3,6,1)p Fc(g)p Fi(')h(is)d(a)f(4-elemen)m(t)i(v)m(ector)g
+(con)m(taining)g(the)0 4189 y(v)-5 b(alues)26 b(1,)h(3,)g(6,)g(and)e
+(1.)40 b(The)25 b(v)m(ector)i(can)f(con)m(tain)h(only)f(b)s(o)s(olean,)
+g(in)m(teger,)j(and)c(real)h(v)-5 b(alues)26 b(\(or)g(expressions\).)0
+4302 y(The)e(elemen)m(ts)h(will)g(b)s(e)f(promoted)g(to)h(the)g
+(highest)f(datat)m(yp)s(e)h(presen)m(t.)39 b(An)m(y)24
+b(elemen)m(ts)i(whic)m(h)e(are)h(themselv)m(es)0 4415
+y(v)m(ectors,)40 b(will)d(b)s(e)f(expanded)g(out)h(with)g(eac)m(h)g(of)
+g(its)g(elemen)m(ts)i(b)s(ecoming)d(an)h(elemen)m(t)h(in)f(the)g
+(constructed)0 4528 y(v)m(ector.)0 4818 y Fb(8.11.4)113
+b(Go)s(o)s(d)38 b(Time)g(In)m(terv)-6 b(al)37 b(Filtering)0
+5036 y Fi(A)44 b(common)g(\014ltering)h(metho)s(d)e(in)m(v)m(olv)m(es)j
+(selecting)g(ro)m(ws)e(whic)m(h)f(ha)m(v)m(e)j(a)e(time)h(v)-5
+b(alue)44 b(whic)m(h)g(lies)g(within)0 5149 y(what)37
+b(is)g(called)i(a)f(Go)s(o)s(d)f(Time)g(In)m(terv)-5
+b(al)38 b(or)f(GTI.)g(The)g(time)h(in)m(terv)-5 b(als)38
+b(are)g(de\014ned)e(in)h(a)g(separate)i(FITS)0 5262 y(table)i
+(extension)g(whic)m(h)e(con)m(tains)i(2)g(columns)f(giving)g(the)h
+(start)f(and)g(stop)g(time)g(of)g(eac)m(h)i(go)s(o)s(d)e(in)m(terv)-5
+b(al.)0 5375 y(The)34 b(\014ltering)h(op)s(eration)h(accepts)g(only)e
+(those)i(ro)m(ws)e(of)h(the)g(input)f(table)i(whic)m(h)e(ha)m(v)m(e)i
+(an)f(asso)s(ciated)h(time)0 5488 y(whic)m(h)f(falls)i(within)e(one)h
+(of)g(the)g(time)g(in)m(terv)-5 b(als)37 b(de\014ned)e(in)g(the)h(GTI)g
+(extension.)57 b(A)36 b(high)g(lev)m(el)h(function,)0
+5601 y(gti\014lter\(a,b,c,d\),)44 b(is)c(a)m(v)-5 b(ailable)42
+b(whic)m(h)d(ev)-5 b(aluates)41 b(eac)m(h)g(ro)m(w)e(of)h(the)f(input)g
+(table)h(and)f(returns)f(TR)m(UE)i(or)0 5714 y(F)-10
+b(ALSE)30 b(dep)s(ending)f(whether)h(the)g(ro)m(w)h(is)f(inside)g(or)g
+(outside)h(the)g(go)s(o)s(d)f(time)h(in)m(terv)-5 b(al.)42
+b(The)30 b(syn)m(tax)h(is)p eop end
+%%Page: 100 106
+TeXDict begin 100 105 bop 0 299 a Fi(100)1573 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)286
+555 y Fe(gtifilter\()45 b([)j("gtifile")d([,)i(expr)g([,)g("STARTCOL",)
+e("STOPCOL")g(])j(])f(])g(\))0 799 y Fi(where)20 b(eac)m(h)h("[]")h
+(demarks)e(optional)h(parameters.)38 b(Note)21 b(that)g(the)g(quotes)f
+(around)g(the)g(gti\014le)i(and)d(ST)-8 b(AR)g(T/STOP)0
+912 y(column)33 b(are)h(required.)50 b(Either)34 b(single)g(or)g
+(double)f(quotes)h(ma)m(y)g(b)s(e)f(used.)50 b(In)33
+b(cases)h(where)g(this)f(expression)0 1024 y(is)d(en)m(tered)g(on)g
+(the)g(Unix)g(command)g(line,)g(enclose)h(the)f(en)m(tire)h(expression)
+f(in)f(double)h(quotes,)g(and)g(then)f(use)0 1137 y(single)c(quotes)g
+(within)e(the)i(expression)f(to)h(enclose)g(the)g('gti\014le')h(and)d
+(other)i(terms.)38 b(It)25 b(is)f(also)h(usually)f(p)s(ossible)0
+1250 y(to)38 b(do)e(the)h(rev)m(erse,)j(and)c(enclose)i(the)f(whole)g
+(expression)g(in)f(single)i(quotes)f(and)f(then)h(use)f(double)g
+(quotes)0 1363 y(within)d(the)g(expression.)50 b(The)33
+b(gti\014le,)i(if)f(sp)s(eci\014ed,)f(can)h(b)s(e)f(blank)g(\(""\))i
+(whic)m(h)e(will)g(mean)h(to)g(use)f(the)h(\014rst)0
+1476 y(extension)g(with)g(the)f(name)h("*GTI*")h(in)f(the)f(curren)m(t)
+h(\014le,)h(a)f(plain)f(extension)h(sp)s(eci\014er)f(\(eg,)j("+2",)g
+("[2]",)0 1589 y(or)30 b("[STDGTI]"\))i(whic)m(h)e(will)h(b)s(e)f(used)
+f(to)j(select)g(an)e(extension)h(in)f(the)h(curren)m(t)f(\014le,)h(or)f
+(a)h(regular)g(\014lename)0 1702 y(with)f(or)h(without)f(an)h
+(extension)g(sp)s(eci\014er)f(whic)m(h)g(in)g(the)h(latter)h(case)f
+(will)g(mean)f(to)i(use)e(the)h(\014rst)e(extension)0
+1815 y(with)37 b(an)g(extension)g(name)h("*GTI*".)62
+b(Expr)36 b(can)h(b)s(e)g(an)m(y)g(arithmetic)i(expression,)f
+(including)f(simply)g(the)0 1928 y(time)f(column)g(name.)57
+b(A)36 b(v)m(ector)h(time)g(expression)e(will)h(pro)s(duce)f(a)h(v)m
+(ector)h(b)s(o)s(olean)f(result.)57 b(ST)-8 b(AR)g(TCOL)0
+2041 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)i(in)f(the)h(GTI)g(extension.)41
+b(If)27 b(one)h(of)g(them)0 2154 y(is)i(sp)s(eci\014ed,)g(they)h(b)s
+(oth)f(m)m(ust)g(b)s(e.)0 2314 y(In)21 b(its)h(simplest)g(form,)i(no)d
+(parameters)h(need)g(to)h(b)s(e)e(pro)m(vided)g({)h(default)g(v)-5
+b(alues)22 b(will)h(b)s(e)e(used.)37 b(The)21 b(expression)0
+2427 y("gti\014lter\(\)")33 b(is)e(equiv)-5 b(alen)m(t)31
+b(to)334 2670 y Fe(gtifilter\()45 b("",)i(TIME,)f("*START*",)f
+("*STOP*")h(\))0 2913 y Fi(This)31 b(will)g(searc)m(h)h(the)g(curren)m
+(t)f(\014le)g(for)g(a)h(GTI)f(extension,)h(\014lter)g(the)f(TIME)g
+(column)g(in)g(the)h(curren)m(t)f(table,)0 3026 y(using)j(ST)-8
+b(AR)g(T/STOP)34 b(times)i(tak)m(en)f(from)g(columns)f(in)h(the)g(GTI)g
+(extension)g(with)g(names)f(con)m(taining)j(the)0 3139
+y(strings)32 b("ST)-8 b(AR)g(T")33 b(and)e("STOP".)46
+b(The)32 b(wildcards)f(\('*'\))j(allo)m(w)g(sligh)m(t)f(v)-5
+b(ariations)33 b(in)f(naming)g(con)m(v)m(en)m(tions)0
+3252 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)g(v)-5 b(alues)38
+b(apply)g(for)g(unsp)s(eci\014ed)f(parame-)0 3365 y(ters)f(when)f(the)h
+(\014rst)f(one)i(or)f(t)m(w)m(o)h(parameters)f(are)h(sp)s(eci\014ed.)56
+b(The)36 b(function)f(automatically)k(searc)m(hes)e(for)0
+3478 y(TIMEZER)m(O/I/F)g(k)m(eyw)m(ords)f(in)g(the)h(curren)m(t)f(and)g
+(GTI)g(extensions,)i(applying)f(a)f(relativ)m(e)j(time)e(o\013set,)i
+(if)0 3591 y(necessary)-8 b(.)0 3879 y Fb(8.11.5)113
+b(Spatial)38 b(Region)g(Filtering)0 4098 y Fi(Another)g(common)g
+(\014ltering)g(metho)s(d)f(selects)i(ro)m(ws)f(based)g(on)f(whether)h
+(the)g(spatial)h(p)s(osition)e(asso)s(ciated)0 4211 y(with)32
+b(eac)m(h)i(ro)m(w)e(is)h(lo)s(cated)h(within)e(a)h(giv)m(en)g
+(2-dimensional)g(region.)48 b(The)32 b(syn)m(tax)h(for)f(this)h
+(high-lev)m(el)h(\014lter)0 4324 y(is)334 4567 y Fe(regfilter\()45
+b("regfilename")f([)k(,)f(Xexpr,)f(Yexpr)h([)g(,)h("wcs)e(cols")h(])g
+(])g(\))0 4811 y Fi(where)22 b(eac)m(h)i("[]")g(demarks)e(optional)i
+(parameters.)38 b(The)22 b(region)h(\014le)g(name)f(is)h(required)f
+(and)g(m)m(ust)g(b)s(e)g(enclosed)0 4924 y(in)34 b(quotes.)51
+b(The)33 b(remaining)h(parameters)h(are)f(optional.)52
+b(There)33 b(are)i(2)f(supp)s(orted)e(formats)i(for)f(the)h(region)0
+5036 y(\014le:)62 b(ASCI)s(I)39 b(\014le)h(or)h(FITS)f(binary)g(table.)
+73 b(The)40 b(region)h(\014le)g(con)m(tains)h(a)f(list)g(of)g(one)g(or)
+g(more)g(geometric)0 5149 y(shap)s(es)30 b(\(circle,)j(ellipse,)g(b)s
+(o)m(x,)e(etc.\))44 b(whic)m(h)31 b(de\014nes)f(a)i(region)g(on)f(the)g
+(celestial)j(sphere)c(or)h(an)g(area)h(within)f(a)0 5262
+y(particular)36 b(2D)g(image.)57 b(The)35 b(region)h(\014le)f(is)g(t)m
+(ypically)j(generated)e(using)f(an)g(image)i(displa)m(y)e(program)g
+(suc)m(h)0 5375 y(as)e(fv/PO)m(W)g(\(distribute)f(b)m(y)h(the)f(HEASAR)
+m(C\),)h(or)g(ds9)f(\(distributed)g(b)m(y)g(the)h(Smithsonian)f
+(Astroph)m(ysical)0 5488 y(Observ)-5 b(atory\).)69 b(Users)39
+b(should)g(refer)g(to)h(the)g(do)s(cumen)m(tation)h(pro)m(vided)e(with)
+g(these)h(programs)f(for)h(more)0 5601 y(details)29 b(on)f(the)g(syn)m
+(tax)h(used)e(in)h(the)h(region)f(\014les.)40 b(The)28
+b(FITS)f(region)i(\014le)f(format)h(is)f(de\014ned)f(in)h(a)g(do)s
+(cumen)m(t)0 5714 y(a)m(v)-5 b(ailable)33 b(from)d(the)g(FITS)g(Supp)s
+(ort)e(O\016ce)j(at)g(h)m(ttp://\014ts.gsfc.nasa.go)m(v/)k(registry/)c
+(region.h)m(tml)p eop end
+%%Page: 101 107
+TeXDict begin 101 106 bop 0 299 a Fg(8.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)30 b(SPECIFICA)-8 b(TION)1982 b Fi(101)0
+555 y(In)21 b(its)h(simplest)g(form,)i(\(e.g.,)h
+(reg\014lter\("region.reg"\))h(\))c(the)g(co)s(ordinates)g(in)g(the)g
+(default)g('X')h(and)e('Y')h(columns)0 668 y(will)43
+b(b)s(e)g(used)f(to)i(determine)f(if)g(eac)m(h)h(ro)m(w)f(is)g(inside)g
+(or)g(outside)g(the)g(area)h(sp)s(eci\014ed)e(in)h(the)g(region)h
+(\014le.)0 781 y(Alternate)32 b(p)s(osition)e(column)g(names,)h(or)f
+(expressions,)h(ma)m(y)g(b)s(e)e(en)m(tered)i(if)g(needed,)f(as)h(in)
+382 1039 y Fe(regfilter\("region.reg",)41 b(XPOS,)47
+b(YPOS\))0 1297 y Fi(Region)37 b(\014ltering)f(can)g(b)s(e)f(applied)g
+(most)h(unam)m(biguously)f(if)h(the)g(p)s(ositions)g(in)f(the)h(region)
+g(\014le)g(and)f(in)h(the)0 1410 y(table)g(to)g(b)s(e)e(\014ltered)h
+(are)h(b)s(oth)e(giv)m(e)j(in)e(terms)g(of)g(absolute)h(celestial)i(co)
+s(ordinate)e(units.)54 b(In)35 b(this)g(case)h(the)0
+1523 y(lo)s(cations)26 b(and)d(sizes)i(of)g(the)f(geometric)i(shap)s
+(es)e(in)g(the)g(region)h(\014le)f(are)h(sp)s(eci\014ed)f(in)g(angular)
+g(units)g(on)g(the)g(sky)0 1636 y(\(e.g.,)32 b(p)s(ositions)e(giv)m(en)
+i(in)e(R.A.)g(and)g(Dec.)42 b(and)30 b(sizes)h(in)f(arcseconds)g(or)h
+(arcmin)m(utes\).)41 b(Similarly)-8 b(,)31 b(eac)m(h)h(ro)m(w)0
+1749 y(of)h(the)h(\014ltered)f(table)h(will)f(ha)m(v)m(e)i(a)e
+(celestial)j(co)s(ordinate)e(asso)s(ciated)g(with)f(it.)50
+b(This)32 b(asso)s(ciation)j(is)e(usually)0 1862 y(implemen)m(ted)39
+b(using)e(a)i(set)g(of)f(so-called)i('W)-8 b(orld)39
+b(Co)s(ordinate)g(System')f(\(or)h(W)m(CS\))f(FITS)g(k)m(eyw)m(ords)g
+(that)0 1975 y(de\014ne)27 b(the)g(co)s(ordinate)h(transformation)g
+(that)g(m)m(ust)f(b)s(e)f(applied)h(to)h(the)g(v)-5 b(alues)27
+b(in)g(the)h('X')g(and)e('Y')i(columns)0 2088 y(to)j(calculate)i(the)d
+(co)s(ordinate.)0 2248 y(Alternativ)m(ely)-8 b(,)30 b(one)d(can)g(p)s
+(erform)e(spatial)j(\014ltering)e(using)g(unitless)h('pixel')g(co)s
+(ordinates)h(for)e(the)h(regions)g(and)0 2361 y(ro)m(w)33
+b(p)s(ositions.)49 b(In)33 b(this)g(case)h(the)f(user)g(m)m(ust)g(b)s
+(e)f(careful)h(to)h(ensure)f(that)g(the)h(p)s(ositions)f(in)g(the)g(2)g
+(\014les)h(are)0 2474 y(self-consisten)m(t.)54 b(A)34
+b(t)m(ypical)i(problem)d(is)h(that)h(the)f(region)h(\014le)f(ma)m(y)h
+(b)s(e)e(generated)j(using)d(a)i(binned)d(image,)0 2587
+y(but)g(the)h(un)m(binned)e(co)s(ordinates)i(are)g(giv)m(en)h(in)e(the)
+h(ev)m(en)m(t)i(table.)48 b(The)32 b(R)m(OSA)-8 b(T)33
+b(ev)m(en)m(ts)h(\014les,)g(for)e(example,)0 2700 y(ha)m(v)m(e)f(X)f
+(and)f(Y)g(pixel)h(co)s(ordinates)g(that)h(range)f(from)f(1)h(-)g
+(15360.)42 b(These)30 b(co)s(ordinates)g(are)g(t)m(ypically)h(binned)0
+2812 y(b)m(y)i(a)h(factor)g(of)f(32)h(to)g(pro)s(duce)e(a)i(480x480)i
+(pixel)d(image.)51 b(If)32 b(one)i(then)f(uses)g(a)g(region)h(\014le)f
+(generated)h(from)0 2925 y(this)c(image)i(\(in)f(image)g(pixel)g
+(units\))g(to)g(\014lter)f(the)h(R)m(OSA)-8 b(T)30 b(ev)m(en)m(ts)i
+(\014le,)f(then)f(the)h(X)g(and)f(Y)g(column)h(v)-5 b(alues)0
+3038 y(m)m(ust)30 b(b)s(e)g(con)m(v)m(erted)i(to)f(corresp)s(onding)e
+(pixel)i(units)f(as)g(in:)382 3296 y Fe(regfilter\("rosat.reg",)42
+b(X/32.+.5,)j(Y/32.+.5\))0 3555 y Fi(Note)h(that)f(this)f(binning)f
+(con)m(v)m(ersion)j(is)e(not)h(necessary)g(if)f(the)h(region)g(\014le)f
+(is)h(sp)s(eci\014ed)e(using)h(celestial)0 3668 y(co)s(ordinate)h
+(units)f(instead)g(of)g(pixel)h(units)f(b)s(ecause)g(CFITSIO)e(is)j
+(then)e(able)i(to)g(directly)g(compare)g(the)0 3780 y(celestial)30
+b(co)s(ordinate)f(of)e(eac)m(h)i(ro)m(w)f(in)f(the)h(table)g(with)g
+(the)f(celestial)k(co)s(ordinates)d(in)f(the)h(region)g(\014le)g
+(without)0 3893 y(ha)m(ving)j(to)g(kno)m(w)f(an)m(ything)h(ab)s(out)f
+(ho)m(w)h(the)f(image)i(ma)m(y)f(ha)m(v)m(e)g(b)s(een)f(binned.)0
+4054 y(The)f(last)h("w)m(cs)g(cols")h(parameter)f(should)e(rarely)h(b)s
+(e)g(needed.)40 b(If)29 b(supplied,)f(this)i(string)f(con)m(tains)i
+(the)e(names)0 4166 y(of)37 b(the)g(2)h(columns)f(\(space)h(or)f(comma)
+g(separated\))h(whic)m(h)f(ha)m(v)m(e)h(the)g(asso)s(ciated)g(W)m(CS)f
+(k)m(eyw)m(ords.)61 b(If)37 b(not)0 4279 y(supplied,)f(the)g(\014lter)g
+(will)h(scan)f(the)g(X)g(and)f(Y)h(expressions)g(for)g(column)f(names.)
+58 b(If)35 b(only)h(one)h(is)f(found)e(in)0 4392 y(eac)m(h)e
+(expression,)e(those)h(columns)f(will)h(b)s(e)e(used,)h(otherwise)h(an)
+f(error)g(will)h(b)s(e)f(returned.)0 4552 y(These)g(region)h(shap)s(es)
+f(are)g(supp)s(orted)f(\(names)h(are)h(case)h(insensitiv)m(e\):)334
+4811 y Fe(Point)428 b(\()48 b(X1,)f(Y1)g(\))715 b(<-)48
+b(One)f(pixel)f(square)g(region)334 4924 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 5036 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 5149 y(Rectangle)236
+b(\()48 b(X1,)f(Y1,)g(X2,)f(Y2,)h(A)h(\))334 b(|)47 b(boundaries)e
+(considered)334 5262 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 5375 y(Diamond)332
+b(\()48 b(Xc,)f(Yc,)g(Wdth,)f(Hght,)g(A)i(\))334 5488
+y(Circle)380 b(\()48 b(Xc,)f(Yc,)g(R)g(\))334 5601 y(Annulus)332
+b(\()48 b(Xc,)f(Yc,)g(Rin,)f(Rout)h(\))334 5714 y(Ellipse)332
+b(\()48 b(Xc,)f(Yc,)g(Rx,)f(Ry,)h(A)h(\))p eop end
+%%Page: 102 108
+TeXDict begin 102 107 bop 0 299 a Fi(102)1573 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)334
+555 y Fe(Elliptannulus)44 b(\()k(Xc,)f(Yc,)g(Rinx,)f(Riny,)g(Routx,)g
+(Routy,)g(Ain,)h(Aout)g(\))334 668 y(Sector)380 b(\()48
+b(Xc,)f(Yc,)g(Amin,)f(Amax)h(\))0 1111 y Fi(where)28
+b(\(Xc,Yc\))j(is)d(the)h(co)s(ordinate)h(of)e(the)h(shap)s(e's)f(cen)m
+(ter;)j(\(X#,Y#\))e(are)g(the)g(co)s(ordinates)g(of)g(the)g(shap)s(e's)
+0 1224 y(edges;)36 b(Rxxx)d(are)h(the)f(shap)s(es')g(v)-5
+b(arious)34 b(Radii)f(or)h(semi-ma)5 b(jor/minor)34 b(axes;)i(and)d
+(Axxx)g(are)h(the)f(angles)i(of)0 1337 y(rotation)e(\(or)e(b)s(ounding)
+f(angles)i(for)f(Sector\))h(in)f(degrees.)44 b(F)-8 b(or)32
+b(rotated)h(shap)s(es,)e(the)g(rotation)i(angle)f(can)g(b)s(e)0
+1450 y(left)g(o\013,)h(indicating)f(no)f(rotation.)46
+b(Common)31 b(alternate)i(names)e(for)h(the)f(regions)h(can)g(also)h(b)
+s(e)d(used:)43 b(rotb)s(o)m(x)0 1563 y(=)29 b(b)s(o)m(x;)g
+(rotrectangle)i(=)e(rectangle;)i(\(rot\)rhom)m(bus)e(=)f
+(\(rot\)diamond;)j(and)d(pie)h(=)f(sector.)42 b(When)28
+b(a)i(shap)s(e's)0 1676 y(name)e(is)g(preceded)f(b)m(y)h(a)g(min)m(us)g
+(sign,)g('-',)i(the)e(de\014ned)e(region)j(is)f(instead)g(the)g(area)h
+(*outside*)g(its)f(b)s(oundary)0 1789 y(\(ie,)36 b(the)e(region)h(is)f
+(in)m(v)m(erted\).)53 b(All)34 b(the)g(shap)s(es)f(within)h(a)g(single)
+h(region)f(\014le)h(are)f(OR'd)f(together)j(to)e(create)0
+1902 y(the)29 b(region,)i(and)d(the)i(order)f(is)g(signi\014can)m(t.)41
+b(The)29 b(o)m(v)m(erall)i(w)m(a)m(y)g(of)e(lo)s(oking)h(at)g(region)g
+(\014les)f(is)g(that)h(if)f(the)h(\014rst)0 2015 y(region)f(is)g(an)g
+(excluded)g(region)g(then)f(a)i(dumm)m(y)d(included)h(region)i(of)f
+(the)g(whole)g(detector)h(is)f(inserted)f(in)h(the)0
+2128 y(fron)m(t.)40 b(Then)25 b(eac)m(h)j(region)f(sp)s(eci\014cation)h
+(as)f(it)g(is)g(pro)s(cessed)f(o)m(v)m(errides)h(an)m(y)g(selections)i
+(inside)d(of)h(that)g(region)0 2240 y(sp)s(eci\014ed)36
+b(b)m(y)g(previous)g(regions.)59 b(Another)37 b(w)m(a)m(y)g(of)g
+(thinking)f(ab)s(out)g(this)g(is)h(that)g(if)f(a)h(previous)f(excluded)
+0 2353 y(region)31 b(is)f(completely)i(inside)f(of)f(a)h(subsequen)m(t)
+e(included)h(region)h(the)g(excluded)f(region)h(is)f(ignored.)0
+2514 y(The)44 b(p)s(ositional)i(co)s(ordinates)g(ma)m(y)f(b)s(e)g(giv)m
+(en)h(either)f(in)g(pixel)g(units,)j(decimal)e(degrees)g(or)f
+(hh:mm:ss.s,)0 2626 y(dd:mm:ss.s)25 b(units.)38 b(The)26
+b(shap)s(e)f(sizes)i(ma)m(y)f(b)s(e)g(giv)m(en)h(in)e(pixels,)j
+(degrees,)f(arcmin)m(utes,)h(or)e(arcseconds.)40 b(Lo)s(ok)0
+2739 y(at)31 b(examples)g(of)f(region)h(\014le)g(pro)s(duced)d(b)m(y)i
+(fv/PO)m(W)h(or)g(ds9)f(for)g(further)f(details)i(of)g(the)f(region)h
+(\014le)f(format.)0 2900 y(There)37 b(are)g(three)g(functions)g(that)g
+(are)h(primarily)f(for)f(use)h(with)g(SA)m(O)g(region)g(\014les)g(and)g
+(the)g(FSA)m(OI)g(task,)0 3012 y(but)e(they)h(can)h(b)s(e)e(used)g
+(directly)-8 b(.)59 b(They)36 b(return)f(a)h(b)s(o)s(olean)g(true)g(or)
+g(false)g(dep)s(ending)f(on)h(whether)f(a)i(t)m(w)m(o)0
+3125 y(dimensional)31 b(p)s(oin)m(t)f(is)g(in)g(the)h(region)g(or)f
+(not:)191 3569 y Fe("point)46 b(in)h(a)h(circular)d(region")477
+3681 y(circle\(xcntr,ycntr,radius)o(,Xco)o(lumn)o(,Yc)o(olum)o(n\))191
+3907 y("point)h(in)h(an)g(elliptical)e(region")430 4020
+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 4246 y("point)h(in)h(a)h
+(rectangular)c(region")620 4359 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
+4585 y(where)334 4698 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
+4811 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 4924 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
+5036 y(\(radius\))f(is)h(half)f(the)h(diameter)f(of)h(the)g(circle)334
+5149 y(\(rotation\))e(is)i(the)g(angle\(degrees\))d(that)j(the)g
+(region)f(is)h(rotated)f(with)620 5262 y(respect)g(to)h
+(\(xcntr,ycntr\))334 5375 y(\(Xcoord,Ycoord\))d(are)j(the)g(\(x,y\))f
+(coordinates)f(to)i(test,)f(usually)g(column)620 5488
+y(names)334 5601 y(NOTE:)g(each)h(parameter)e(can)i(itself)f(be)i(an)f
+(expression,)d(not)j(merely)f(a)620 5714 y(column)h(name)f(or)h
+(constant.)p eop end
+%%Page: 103 109
+TeXDict begin 103 108 bop 0 299 a Fg(8.11.)73 b(R)m(O)m(W)31
+b(FIL)-8 b(TERING)30 b(SPECIFICA)-8 b(TION)1982 b Fi(103)0
+555 y Fb(8.11.6)113 b(Example)38 b(Ro)m(w)f(Filters)191
+859 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 972
+y(than)94 b(fifth)47 b(magnitude)e(\(note)h(that)1766
+1085 y(the)h(initial)f(space)g(is)h(necessary)e(to)1766
+1197 y(prevent)h(it)h(from)g(being)f(treated)g(as)h(a)1766
+1310 y(binning)f(specification\))191 1536 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 1762 y([IMAGE[4,5])f(.gt.)h(100])476 b(-)48
+b(Extract)e(all)h(rows)f(that)h(have)g(the)1766 1875
+y(\(4,5\))f(component)g(of)h(the)g(IMAGE)f(column)1766
+1988 y(greater)g(than)g(100)191 2214 y([abs\(sin\(theta)e(*)j(#deg\)\))
+f(<)i(0.5])e(-)i(Extract)e(all)h(rows)f(having)g(the)1766
+2327 y(absolute)f(value)i(of)g(the)g(sine)g(of)g(theta)1766
+2439 y(less)94 b(than)47 b(a)g(half)g(where)f(the)h(angles)1766
+2552 y(are)g(tabulated)e(in)i(degrees)191 2778 y([SUM\()f(SPEC)h(>)g
+(3*BACKGRND)e(\)>=1])94 b(-)48 b(Extract)e(all)h(rows)f(containing)f(a)
+1766 2891 y(spectrum,)g(held)i(in)g(vector)f(column)1766
+3004 y(SPEC,)g(with)h(at)g(least)f(one)h(value)g(3)1766
+3117 y(times)f(greater)g(than)h(the)g(background)1766
+3230 y(level)f(held)h(in)g(a)h(keyword,)d(BACKGRND)191
+3456 y([VCOL=={1,4,2}])759 b(-)48 b(Extract)e(all)h(rows)f(whose)h
+(vector)f(column)1766 3569 y(VCOL)h(contains)e(the)i(3-elements)e(1,)i
+(4,)g(and)1766 3681 y(2.)191 3907 y([@rowFilter.txt])711
+b(-)48 b(Extract)e(rows)g(using)h(the)g(expression)1766
+4020 y(contained)e(within)h(the)h(text)g(file)1766 4133
+y(rowFilter.txt)191 4359 y([gtifilter\(\)])855 b(-)48
+b(Search)e(the)h(current)f(file)g(for)h(a)h(GTI)239 4472
+y(extension,)92 b(filter)i(the)47 b(TIME)239 4585 y(column)f(in)h(the)g
+(current)f(table,)g(using)239 4698 y(START/STOP)f(times)h(taken)g(from)
+239 4811 y(columns)f(in)j(the)f(GTI)94 b(extension)191
+5036 y([regfilter\("pow.reg"\)])423 b(-)48 b(Extract)e(rows)g(which)h
+(have)f(a)i(coordinate)1766 5149 y(\(as)f(given)f(in)h(the)g(X)h(and)f
+(Y)g(columns\))1766 5262 y(within)f(the)h(spatial)f(region)g(specified)
+1766 5375 y(in)h(the)g(pow.reg)f(region)g(file.)191 5601
+y([regfilter\("pow.reg",)c(Xs,)47 b(Ys\)])f(-)i(Same)f(as)g(above,)f
+(except)g(that)h(the)1766 5714 y(Xs)g(and)g(Ys)g(columns)f(will)h(be)g
+(used)f(to)p eop end
+%%Page: 104 110
+TeXDict begin 104 109 bop 0 299 a Fi(104)1573 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)1766
+555 y Fe(determine)45 b(the)i(coordinate)e(of)i(each)1766
+668 y(row)g(in)g(the)g(table.)0 1001 y Fd(8.12)180 b(Binning)45
+b(or)g(Histogramming)i(Sp)t(eci\014cation)0 1252 y Fi(The)22
+b(optional)i(binning)e(sp)s(eci\014er)g(is)h(enclosed)h(in)f(square)f
+(brac)m(k)m(ets)j(and)d(can)h(b)s(e)f(distinguished)g(from)h(a)g
+(general)0 1365 y(ro)m(w)32 b(\014lter)h(sp)s(eci\014cation)g(b)m(y)f
+(the)h(fact)g(that)g(it)g(b)s(egins)f(with)g(the)g(k)m(eyw)m(ord)h
+('bin')f(not)h(immediately)g(follo)m(w)m(ed)0 1477 y(b)m(y)41
+b(an)f(equals)i(sign.)72 b(When)41 b(binning)e(is)i(sp)s(eci\014ed,)i
+(a)e(temp)s(orary)g(N-dimensional)g(FITS)f(primary)g(arra)m(y)0
+1590 y(is)j(created)h(b)m(y)f(computing)h(the)f(histogram)h(of)f(the)g
+(v)-5 b(alues)44 b(in)e(the)i(sp)s(eci\014ed)e(columns)h(of)g(a)h(FITS)
+e(table)0 1703 y(extension.)f(After)30 b(the)f(histogram)h(is)g
+(computed)f(the)h(input)e(FITS)h(\014le)h(con)m(taining)h(the)e(table)i
+(is)e(then)g(closed)0 1816 y(and)34 b(the)h(temp)s(orary)f(FITS)g
+(primary)g(arra)m(y)h(is)g(op)s(ened)f(and)g(passed)g(to)h(the)g
+(application)h(program.)54 b(Th)m(us,)0 1929 y(the)39
+b(application)h(program)f(nev)m(er)g(sees)g(the)g(original)h(FITS)e
+(table)i(and)e(only)h(sees)h(the)f(image)h(in)e(the)h(new)0
+2042 y(temp)s(orary)32 b(\014le)h(\(whic)m(h)g(has)f(no)h(additional)g
+(extensions\).)49 b(Ob)m(viously)-8 b(,)34 b(the)f(application)h
+(program)e(m)m(ust)h(b)s(e)0 2155 y(exp)s(ecting)e(to)g(op)s(en)f(a)h
+(FITS)e(image)j(and)e(not)g(a)h(FITS)f(table)h(in)f(this)g(case.)0
+2315 y(The)g(data)h(t)m(yp)s(e)f(of)h(the)f(FITS)g(histogram)g(image)i
+(ma)m(y)f(b)s(e)f(sp)s(eci\014ed)f(b)m(y)h(app)s(ending)f('b')h(\(for)h
+(8-bit)g(b)m(yte\),)g('i')0 2428 y(\(for)g(16-bit)g(in)m(tegers\),)h
+('j')f(\(for)g(32-bit)g(in)m(teger\),)i('r')d(\(for)h(32-bit)g
+(\015oating)h(p)s(oin)m(ts\),)e(or)h('d')f(\(for)h(64-bit)g(double)0
+2541 y(precision)d(\015oating)h(p)s(oin)m(t\))g(to)f(the)h('bin')e(k)m
+(eyw)m(ord)i(\(e.g.)41 b('[binr)28 b(X]')g(creates)i(a)e(real)h
+(\015oating)g(p)s(oin)m(t)f(image\).)41 b(If)0 2654 y(the)26
+b(datat)m(yp)s(e)h(is)f(not)g(explicitly)i(sp)s(eci\014ed)d(then)h(a)g
+(32-bit)h(in)m(teger)h(image)f(will)f(b)s(e)f(created)i(b)m(y)f
+(default,)i(unless)0 2767 y(the)h(w)m(eigh)m(ting)h(option)f(is)g(also)
+h(sp)s(eci\014ed)e(in)g(whic)m(h)h(case)g(the)g(image)h(will)f(ha)m(v)m
+(e)h(a)f(32-bit)h(\015oating)g(p)s(oin)m(t)e(data)0 2880
+y(t)m(yp)s(e)j(b)m(y)f(default.)0 3040 y(The)24 b(histogram)g(image)i
+(ma)m(y)f(ha)m(v)m(e)g(from)f(1)g(to)h(4)g(dimensions)e(\(axes\),)k
+(dep)s(ending)c(on)h(the)g(n)m(um)m(b)s(er)f(of)h(columns)0
+3153 y(that)31 b(are)g(sp)s(eci\014ed.)40 b(The)30 b(general)h(form)f
+(of)g(the)h(binning)e(sp)s(eci\014cation)i(is:)48 3410
+y Fe([bin{bijrd})92 b(Xcol=min:max:binsize,)42 b(Ycol=)47
+b(...,)f(Zcol=...,)f(Tcol=...;)h(weight])0 3668 y Fi(in)39
+b(whic)m(h)g(up)f(to)i(4)g(columns,)h(eac)m(h)f(corresp)s(onding)e(to)i
+(an)g(axis)f(of)h(the)f(image,)k(are)d(listed.)67 b(The)39
+b(column)0 3781 y(names)27 b(are)h(case)h(insensitiv)m(e,)g(and)e(the)h
+(column)f(n)m(um)m(b)s(er)f(ma)m(y)i(b)s(e)f(giv)m(en)h(instead)g(of)g
+(the)g(name,)g(preceded)f(b)m(y)0 3894 y(a)32 b(p)s(ound)e(sign)i
+(\(e.g.,)i([bin)d(#4=1:512]\).)47 b(If)31 b(the)h(column)g(name)g(is)f
+(not)h(sp)s(eci\014ed,)g(then)f(CFITSIO)g(will)h(\014rst)0
+4007 y(try)37 b(to)h(use)f(the)g('preferred)f(column')i(as)f(sp)s
+(eci\014ed)g(b)m(y)g(the)g(CPREF)g(k)m(eyw)m(ord)h(if)f(it)g(exists)h
+(\(e.g.,)j('CPREF)0 4120 y(=)i('DETX,DETY'\),)h(otherwise)g(column)f
+(names)g('X',)h('Y',)g('Z',)f(and)f('T')i(will)f(b)s(e)f(assumed)h(for)
+g(eac)m(h)h(of)0 4233 y(the)37 b(4)h(axes,)i(resp)s(ectiv)m(ely)-8
+b(.)62 b(In)37 b(cases)h(where)e(the)i(column)f(name)g(could)g(b)s(e)f
+(confused)h(with)g(an)g(arithmetic)0 4346 y(expression,)30
+b(enclose)i(the)f(column)f(name)g(in)g(paren)m(theses)h(to)g(force)g
+(the)f(name)h(to)g(b)s(e)f(in)m(terpreted)g(literally)-8
+b(.)0 4506 y(Eac)m(h)33 b(column)f(name)g(ma)m(y)h(b)s(e)f(follo)m(w)m
+(ed)h(b)m(y)g(an)f(equals)g(sign)h(and)e(then)h(the)g(lo)m(w)m(er)i
+(and)e(upp)s(er)e(range)i(of)h(the)0 4619 y(histogram,)f(and)e(the)h
+(size)h(of)f(the)g(histogram)h(bins,)e(separated)h(b)m(y)g(colons.)43
+b(Spaces)31 b(are)g(allo)m(w)m(ed)i(b)s(efore)e(and)0
+4731 y(after)e(the)g(equals)g(sign)f(but)g(not)h(within)f(the)h
+('min:max:binsize')g(string.)40 b(The)29 b(min,)f(max)h(and)f(binsize)h
+(v)-5 b(alues)0 4844 y(ma)m(y)32 b(b)s(e)e(in)m(teger)i(or)f
+(\015oating)h(p)s(oin)m(t)f(n)m(um)m(b)s(ers,)f(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)g(the)g(header)g(of)0
+4957 y(the)g(table.)41 b(If)30 b(the)h(latter,)h(then)e(the)g(v)-5
+b(alue)31 b(of)g(that)g(k)m(eyw)m(ord)f(is)h(substituted)f(in)m(to)h
+(the)g(expression.)0 5117 y(Default)37 b(v)-5 b(alues)36
+b(for)g(the)g(min,)h(max)f(and)g(binsize)g(quan)m(tities)h(will)f(b)s
+(e)f(used)h(if)f(not)i(explicitly)g(giv)m(en)g(in)f(the)0
+5230 y(binning)29 b(expression)h(as)h(sho)m(wn)f(in)g(these)h
+(examples:)191 5488 y Fe([bin)47 b(x)g(=)g(:512:2])94
+b(-)47 b(use)g(default)f(minimum)g(value)191 5601 y([bin)h(x)g(=)g
+(1::2])190 b(-)47 b(use)g(default)f(maximum)g(value)191
+5714 y([bin)h(x)g(=)g(1:512])142 b(-)47 b(use)g(default)f(bin)h(size)p
+eop end
+%%Page: 105 111
+TeXDict begin 105 110 bop 0 299 a Fg(8.12.)113 b(BINNING)31
+b(OR)f(HISTOGRAMMING)h(SPECIFICA)-8 b(TION)1268 b Fi(105)191
+555 y Fe([bin)47 b(x)g(=)g(1:])286 b(-)47 b(use)g(default)f(maximum)g
+(value)g(and)h(bin)g(size)191 668 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
+781 y([bin)g(x)g(=)g(2])334 b(-)47 b(use)g(default)f(minimum)g(and)h
+(maximum)f(values)191 894 y([bin)h(x])524 b(-)47 b(use)g(default)f
+(minimum,)g(maximum)g(and)g(bin)h(size)191 1007 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 1120 y([bin])619 b(-)47 b(default)f(2-D)h(image)0
+1374 y Fi(CFITSIO)31 b(will)i(use)f(the)h(v)-5 b(alue)33
+b(of)g(the)g(TLMINn,)f(TLMAXn,)h(and)f(TDBINn)h(k)m(eyw)m(ords,)h(if)e
+(they)h(exist,)h(for)0 1487 y(the)j(default)f(min,)i(max,)g(and)e
+(binsize,)i(resp)s(ectiv)m(ely)-8 b(.)61 b(If)36 b(they)h(do)f(not)h
+(exist)g(then)f(CFITSIO)f(will)i(use)f(the)0 1600 y(actual)d(minim)m
+(um)e(and)h(maxim)m(um)g(v)-5 b(alues)32 b(in)g(the)g(column)f(for)h
+(the)g(histogram)h(min)e(and)h(max)g(v)-5 b(alues.)45
+b(The)0 1713 y(default)34 b(binsize)f(will)h(b)s(e)f(set)h(to)h(1,)g
+(or)e(\(max)h(-)g(min\))f(/)h(10.,)i(whic)m(hev)m(er)e(is)g(smaller,)h
+(so)e(that)i(the)e(histogram)0 1826 y(will)e(ha)m(v)m(e)g(at)g(least)h
+(10)f(bins)f(along)h(eac)m(h)h(axis.)0 1986 y(A)41 b(shortcut)g
+(notation)h(is)f(allo)m(w)m(ed)i(if)e(all)h(the)f(columns/axes)h(ha)m
+(v)m(e)g(the)f(same)g(binning)f(sp)s(eci\014cation.)74
+b(In)0 2099 y(this)33 b(case)g(all)h(the)f(column)f(names)h(ma)m(y)g(b)
+s(e)f(listed)h(within)f(paren)m(theses,)i(follo)m(w)m(ed)h(b)m(y)d(the)
+h(\(single\))h(binning)0 2212 y(sp)s(eci\014cation,)d(as)g(in:)191
+2466 y Fe([bin)47 b(\(X,Y\)=1:512:2])191 2579 y([bin)g(\(X,Y\))f(=)h
+(5])0 2834 y Fi(The)31 b(optional)i(w)m(eigh)m(ting)h(factor)e(is)g
+(the)g(last)g(item)h(in)e(the)h(binning)f(sp)s(eci\014er)g(and,)h(if)f
+(presen)m(t,)i(is)e(separated)0 2947 y(from)38 b(the)g(list)h(of)f
+(columns)g(b)m(y)g(a)h(semi-colon.)65 b(As)39 b(the)f(histogram)h(is)f
+(accum)m(ulated,)k(this)c(w)m(eigh)m(t)i(is)e(used)0
+3059 y(to)d(incremen)m(ted)f(the)g(v)-5 b(alue)35 b(of)f(the)g
+(appropriated)f(bin)h(in)f(the)h(histogram.)52 b(If)34
+b(the)g(w)m(eigh)m(ting)i(factor)f(is)f(not)0 3172 y(sp)s(eci\014ed,)24
+b(then)f(the)g(default)g(w)m(eigh)m(t)i(=)d(1)i(is)f(assumed.)37
+b(The)23 b(w)m(eigh)m(ting)i(factor)f(ma)m(y)f(b)s(e)g(a)g(constan)m(t)
+i(in)m(teger)f(or)0 3285 y(\015oating)30 b(p)s(oin)m(t)f(n)m(um)m(b)s
+(er,)f(or)h(the)g(name)g(of)g(a)g(k)m(eyw)m(ord)h(con)m(taining)g(the)g
+(w)m(eigh)m(ting)g(v)-5 b(alue.)41 b(Or)28 b(the)h(w)m(eigh)m(ting)0
+3398 y(factor)g(ma)m(y)g(b)s(e)e(the)h(name)g(of)h(a)f(table)h(column)f
+(in)g(whic)m(h)f(case)j(the)e(v)-5 b(alue)28 b(in)g(that)h(column,)f
+(on)g(a)h(ro)m(w)f(b)m(y)g(ro)m(w)0 3511 y(basis,)i(will)h(b)s(e)f
+(used.)0 3671 y(In)35 b(some)h(cases,)i(the)d(column)h(or)f(k)m(eyw)m
+(ord)h(ma)m(y)g(giv)m(e)h(the)f(recipro)s(cal)g(of)g(the)g(actual)h(w)m
+(eigh)m(t)g(v)-5 b(alue)36 b(that)g(is)0 3784 y(needed.)49
+b(In)32 b(this)h(case,)i(precede)e(the)h(w)m(eigh)m(t)g(k)m(eyw)m(ord)g
+(or)f(column)g(name)g(b)m(y)g(a)g(slash)g('/')h(to)g(tell)g(CFITSIO)0
+3897 y(to)d(use)f(the)h(recipro)s(cal)g(of)f(the)h(v)-5
+b(alue)31 b(when)e(constructing)i(the)g(histogram.)0
+4057 y(F)-8 b(or)35 b(complex)f(or)g(commonly)g(used)f(histograms,)j
+(one)e(can)g(also)h(place)g(its)f(description)g(in)m(to)h(a)f(text)h
+(\014le)f(and)0 4170 y(imp)s(ort)44 b(it)g(in)m(to)i(the)e(binning)f
+(sp)s(eci\014cation)i(using)f(the)h(syn)m(tax)f('[bin)g
+(@\014lename.txt]'.)84 b(The)44 b(\014le's)g(con-)0 4283
+y(ten)m(ts)37 b(can)e(extend)h(o)m(v)m(er)h(m)m(ultiple)f(lines,)i
+(although)e(it)g(m)m(ust)f(still)i(conform)f(to)g(the)g(no-spaces)g
+(rule)f(for)h(the)0 4396 y(min:max:binsize)h(syn)m(tax)h(and)e(eac)m(h)
+i(axis)g(sp)s(eci\014cation)g(m)m(ust)f(still)g(b)s(e)g
+(comma-separated.)62 b(An)m(y)37 b(lines)g(in)0 4509
+y(the)32 b(external)h(text)g(\014le)f(that)h(b)s(egin)e(with)h(2)g
+(slash)g(c)m(haracters)h(\('//'\))h(will)e(b)s(e)g(ignored)g(and)f(ma)m
+(y)i(b)s(e)e(used)g(to)0 4622 y(add)f(commen)m(ts)h(in)m(to)g(the)g
+(\014le.)0 4782 y(Examples:)191 5036 y Fe([bini)46 b(detx,)h(dety])762
+b(-)47 b(2-D,)g(16-bit)f(integer)g(histogram)1861 5149
+y(of)i(DETX)e(and)h(DETY)g(columns,)e(using)1861 5262
+y(default)h(values)g(for)h(the)g(histogram)1861 5375
+y(range)g(and)g(binsize)191 5601 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
+5714 y(and)g(DETY)g(columns)f(with)g(a)i(bin)f(size)f(=)i(16)p
+eop end
+%%Page: 106 112
+TeXDict begin 106 111 bop 0 299 a Fi(106)1573 b Fg(CHAPTER)30
+b(8.)112 b(EXTENDED)30 b(FILE)h(NAME)f(SYNT)-8 b(AX)1861
+555 y Fe(in)48 b(both)e(axes.)h(The)f(histogram)g(values)1861
+668 y(are)h(divided)f(by)h(the)g(EXPOSURE)f(keyword)1861
+781 y(value.)191 1007 y([bin)h(time=TSTART:TSTOP:0.1])280
+b(-)47 b(1-D)g(lightcurve,)e(range)h(determined)f(by)1861
+1120 y(the)i(TSTART)f(and)h(TSTOP)g(keywords,)1861 1233
+y(with)g(0.1)g(unit)g(size)f(bins.)191 1458 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 1571 y(of)i(the)e(PHA)h(column)f(for)h(the)g(X)h(axis,)
+1861 1684 y(and)f(1000)g(bins)g(in)g(the)g(range)1861
+1797 y(8000.)g(to)g(8100.)f(for)h(the)g(Y)h(axis.)191
+2023 y([bin)f(@binFilter.txt])616 b(-)47 b(Use)g(the)g(contents)f(of)h
+(the)g(text)f(file)1861 2136 y(binFilter.txt)f(for)h(the)h(binning)1861
+2249 y(specifications.)p eop end
+%%Page: 107 113
+TeXDict begin 107 112 bop 0 1225 a Ff(Chapter)65 b(9)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)h(is)g(created)g(with)g(a)f(call)i(to)g
+(\014ts)p 2101 2180 28 4 v 32 w(create)p 2369 2180 V
+35 w(\014le,)g(the)f(name)g(of)g(a)g(template)h(\014le)e(ma)m(y)0
+2293 y(b)s(e)h(supplied)g(in)h(paren)m(theses)g(immediately)h(follo)m
+(wing)g(the)g(name)f(of)g(the)g(new)f(\014le)h(to)h(b)s(e)e(created.)71
+b(This)0 2406 y(template)27 b(is)e(used)g(to)h(de\014ne)f(the)h
+(structure)f(of)h(one)f(or)h(more)g(HDUs)g(in)f(the)h(new)f(\014le.)39
+b(The)25 b(template)i(\014le)e(ma)m(y)0 2518 y(b)s(e)32
+b(another)h(FITS)f(\014le,)i(in)f(whic)m(h)f(case)i(the)f(newly)g
+(created)h(\014le)f(will)g(ha)m(v)m(e)h(exactly)h(the)e(same)g(k)m(eyw)
+m(ords)g(in)0 2631 y(eac)m(h)25 b(HDU)g(as)g(in)f(the)g(template)i
+(FITS)d(\014le,)j(but)d(all)j(the)e(data)h(units)e(will)i(b)s(e)f
+(\014lled)g(with)f(zeros.)40 b(The)24 b(template)0 2744
+y(\014le)i(ma)m(y)h(also)g(b)s(e)e(an)h(ASCI)s(I)e(text)j(\014le,)g
+(where)f(eac)m(h)h(line)f(\(in)g(general\))i(describ)s(es)d(one)h(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)i(\014le)g(is)f(describ)s(ed)f(in)i(the)f(follo)m(wing)i
+(sections.)0 3188 y Fd(9.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)k(line)f(closely)h(follo)
+m(ws)f(the)g(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)f(sign)h(ma)m(y)f(app)s(ear)g(at)h(an)m(y)g
+(p)s(osition)f(in)g(the)h(line\))g(and)0 4039 y(T)-8
+b(AB)34 b(c)m(haracters)g(are)g(allo)m(w)m(ed)h(and)e(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)g(are)h
+(optional.)43 b(The)30 b(equals)h(sign)f(c)m(haracter)j(is)d(also)i
+(optional,)g(but)e(it)h(is)f(recommended)0 4264 y(that)42
+b(it)f(b)s(e)g(included)f(for)h(clarit)m(y)-8 b(.)75
+b(An)m(y)41 b(template)i(line)e(that)h(b)s(egins)f(with)f(the)i(p)s
+(ound)d('#')i(c)m(haracter)i(is)0 4377 y(ignored)30 b(b)m(y)h(the)f
+(template)i(parser)e(and)g(ma)m(y)h(b)s(e)e(use)h(to)h(insert)g(commen)
+m(ts)g(in)m(to)g(the)g(template)h(\014le)e(itself.)0
+4538 y(The)c(KEYW)m(ORD)g(name)g(\014eld)g(is)g(limited)h(to)g(8)f(c)m
+(haracters)h(in)f(length)h(and)e(only)h(the)g(letters)i(A-Z,)e(digits)h
+(0-9,)0 4650 y(and)h(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)h(an)m(y)f(em)m(b)s
+(edded)g(spaces.)40 b(Lo)m(w)m(ercase)0 4763 y(letters)22
+b(in)f(the)h(template)g(k)m(eyw)m(ord)g(name)f(will)g(b)s(e)g(con)m(v)m
+(erted)i(to)f(upp)s(ercase.)36 b(Leading)22 b(spaces)f(in)g(the)h
+(template)0 4876 y(line)k(preceding)g(the)f(k)m(eyw)m(ord)h(name)g(are)
+g(generally)h(ignored,)g(except)f(if)g(the)g(\014rst)f(8)h(c)m
+(haracters)h(of)f(a)g(template)0 4989 y(line)f(are)h(all)g(blank,)g
+(then)f(the)g(en)m(tire)h(line)g(is)f(treated)h(as)f(a)h(FITS)e(commen)
+m(t)i(k)m(eyw)m(ord)g(\(with)f(a)h(blank)e(k)m(eyw)m(ord)0
+5102 y(name\))31 b(and)f(is)g(copied)h(v)m(erbatim)g(in)m(to)g(the)g
+(FITS)e(header.)0 5262 y(The)37 b(KEYV)-10 b(ALUE)37
+b(\014eld)g(ma)m(y)h(ha)m(v)m(e)g(an)m(y)g(allo)m(w)m(ed)h(FITS)e(data)
+h(t)m(yp)s(e:)54 b(c)m(haracter)39 b(string,)h(logical,)h(in)m(teger,)0
+5375 y(real,)34 b(complex)f(in)m(teger,)i(or)d(complex)i(real.)47
+b(The)32 b(c)m(haracter)j(string)d(v)-5 b(alues)33 b(need)f(not)h(b)s
+(e)f(enclosed)h(in)f(single)0 5488 y(quote)d(c)m(haracters)h(unless)e
+(they)g(are)h(necessary)g(to)g(distinguish)e(the)i(string)f(from)g(a)h
+(di\013eren)m(t)g(data)g(t)m(yp)s(e)f(\(e.g.)0 5601 y(2.0)h(is)e(a)h
+(real)h(but)e('2.0')i(is)f(a)g(string\).)40 b(The)27
+b(k)m(eyw)m(ord)h(has)f(an)h(unde\014ned)d(\(n)m(ull\))j(v)-5
+b(alue)29 b(if)e(the)h(template)h(record)0 5714 y(only)h(con)m(tains)i
+(blanks)e(follo)m(wing)i(the)e("=")h(or)g(b)s(et)m(w)m(een)g(the)f("=")
+h(and)f(the)g("/")i(commen)m(t)g(\014eld)d(delimiter.)1882
+5942 y(107)p eop end
+%%Page: 108 114
+TeXDict begin 108 113 bop 0 299 a Fi(108)2295 b Fg(CHAPTER)30
+b(9.)71 b(TEMPLA)-8 b(TE)30 b(FILES)0 555 y Fi(String)c(k)m(eyw)m(ord)h
+(v)-5 b(alues)27 b(longer)g(than)f(68)h(c)m(haracters)h(\(the)f(maxim)m
+(um)f(length)h(that)g(will)g(\014t)f(in)g(a)h(single)g(FITS)0
+668 y(k)m(eyw)m(ord)41 b(record\))g(are)g(p)s(ermitted)f(using)g(the)h
+(CFITSIO)e(long)i(string)g(con)m(v)m(en)m(tion.)74 b(They)40
+b(can)h(either)g(b)s(e)0 781 y(sp)s(eci\014ed)28 b(as)i(a)f(single)h
+(long)f(line)h(in)e(the)i(template,)h(or)e(b)m(y)f(using)h(m)m(ultiple)
+h(lines)f(where)f(the)i(con)m(tin)m(uing)g(lines)0 894
+y(con)m(tain)i(the)e('CONTINUE')g(k)m(eyw)m(ord,)h(as)g(in)f(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)h(lines)e(with)h(CONTINUE)e
+(k)m(eyw)m(ord)i(is)g(v)m(ery)g(strict:)41 b(3)30 b(spaces)g(m)m(ust)f
+(follo)m(w)i(CON-)0 1610 y(TINUE)f(and)g(the)g(rest)h(of)f(the)h(line)g
+(is)f(copied)h(v)m(erbatim)g(to)g(the)g(FITS)e(\014le.)0
+1771 y(The)i(start)h(of)g(the)f(optional)i(COMMENT)e(\014eld)g(m)m(ust)
+h(b)s(e)e(preceded)i(b)m(y)f("/",)i(whic)m(h)e(is)h(used)f(to)h
+(separate)g(it)0 1883 y(from)e(the)g(k)m(eyw)m(ord)h(v)-5
+b(alue)30 b(\014eld.)41 b(Exceptions)30 b(are)h(if)f(the)h(KEYW)m(ORD)g
+(name)f(\014eld)g(con)m(tains)h(COMMENT,)0 1996 y(HISTOR)-8
+b(Y,)30 b(CONTINUE,)g(or)g(if)g(the)h(\014rst)f(8)g(c)m(haracters)i(of)
+f(the)f(template)i(line)f(are)g(blanks.)0 2157 y(More)c(than)f(one)h
+(Header-Data)i(Unit)e(\(HDU\))g(ma)m(y)g(b)s(e)f(de\014ned)f(in)h(the)h
+(template)h(\014le.)39 b(The)26 b(start)h(of)g(an)f(HDU)0
+2269 y(de\014nition)k(is)g(denoted)h(with)f(a)h(SIMPLE)e(or)i(XTENSION)
+e(template)j(line:)0 2430 y(1\))i(SIMPLE)f(b)s(egins)g(a)h(Primary)g
+(HDU)g(de\014nition.)50 b(SIMPLE)33 b(ma)m(y)h(only)g(app)s(ear)f(as)h
+(the)g(\014rst)f(k)m(eyw)m(ord)h(in)0 2543 y(the)e(template)i(\014le.)
+45 b(If)32 b(the)g(template)i(\014le)e(b)s(egins)f(with)h(XTENSION)f
+(instead)h(of)g(SIMPLE,)g(then)f(a)i(default)0 2655 y(empt)m(y)d
+(Primary)e(HDU)i(is)g(created,)h(and)d(the)i(template)h(is)e(then)g
+(assumed)f(to)i(de\014ne)f(the)h(k)m(eyw)m(ords)f(starting)0
+2768 y(with)h(the)h(\014rst)e(extension)i(follo)m(wing)h(the)f(Primary)
+f(HDU.)0 2928 y(2\))35 b(XTENSION)e(marks)g(the)i(b)s(eginning)e(of)h
+(a)h(new)e(extension)i(HDU)f(de\014nition.)52 b(The)33
+b(previous)h(HDU)h(will)0 3041 y(b)s(e)30 b(closed)h(at)g(this)f(p)s
+(oin)m(t)h(and)e(pro)s(cessing)i(of)f(the)h(next)f(extension)h(b)s
+(egins.)0 3373 y Fd(9.2)135 b(Auto-indexing)45 b(of)h(Keyw)l(ords)0
+3623 y Fi(If)31 b(a)h(template)g(k)m(eyw)m(ord)g(name)f(ends)g(with)g
+(a)g("#")h(c)m(haracter,)i(it)e(is)f(said)g(to)h(b)s(e)f
+('auto-indexed'.)44 b(Eac)m(h)32 b("#")0 3736 y(c)m(haracter)i(will)f
+(b)s(e)f(replaced)i(b)m(y)e(the)h(curren)m(t)g(in)m(teger)h(index)e(v)
+-5 b(alue,)34 b(whic)m(h)f(gets)g(reset)h(=)e(1)h(at)h(the)e(start)i
+(of)0 3849 y(eac)m(h)h(new)f(HDU)g(in)g(the)g(\014le)g(\(or)g(7)h(in)e
+(the)h(sp)s(ecial)h(case)g(of)f(a)g(GR)m(OUP)h(de\014nition\).)51
+b(The)33 b(FIRST)g(indexed)0 3962 y(k)m(eyw)m(ord)c(in)f(eac)m(h)h
+(template)h(HDU)f(de\014nition)f(is)g(used)f(as)i(the)f('incremen)m
+(tor';)j(eac)m(h)e(subsequen)m(t)f(o)s(ccurrence)0 4075
+y(of)k(this)f(SAME)g(k)m(eyw)m(ord)h(will)g(cause)g(the)g(index)f(v)-5
+b(alue)32 b(to)g(b)s(e)f(incremen)m(ted.)44 b(This)31
+b(b)s(eha)m(vior)g(can)h(b)s(e)f(rather)0 4188 y(subtle,)d(as)g
+(illustrated)h(in)e(the)h(follo)m(wing)h(examples)f(in)f(whic)m(h)h
+(the)g(TTYPE)e(k)m(eyw)m(ord)i(is)g(the)g(incremen)m(tor)g(in)0
+4300 y(b)s(oth)i(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)26 b(create)i(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)g(the)g(template)h(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
+end
+%%Page: 109 115
+TeXDict begin 109 114 bop 0 299 a Fg(9.3.)72 b(TEMPLA)-8
+b(TE)30 b(P)-8 b(ARSER)30 b(DIRECTIVES)2028 b Fi(109)0
+555 y(this)31 b(results)f(in)h(a)g(FITS)f(\014les)h(with)f(TTYPE1,)h
+(TTYPE2,)g(TF)m(ORM2,)h(and)e(TF)m(ORM2,)i(whic)m(h)f(is)g(probably)0
+668 y(not)g(what)f(w)m(as)h(in)m(tended!)0 1000 y Fd(9.3)135
+b(T)-11 b(emplate)46 b(P)l(arser)g(Directiv)l(es)0 1251
+y Fi(In)29 b(addition)i(to)f(the)g(template)i(lines)e(whic)m(h)g
+(de\014ne)f(individual)h(k)m(eyw)m(ords,)g(the)g(template)i(parser)d
+(recognizes)0 1363 y(3)h(sp)s(ecial)h(directiv)m(es)g(whic)m(h)f(are)g
+(eac)m(h)h(preceded)f(b)m(y)f(the)h(bac)m(kslash)h(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')h(directiv)m(e)i(m)m(ust)
+d(b)s(e)h(follo)m(w)m(ed)h(b)m(y)f(a)g(\014lename.)63
+b(It)38 b(forces)g(the)g(parser)f(to)i(temp)s(orarily)f(stop)0
+1749 y(reading)d(the)g(curren)m(t)g(template)h(\014le)f(and)f(b)s(egin)
+h(reading)g(the)g(include)f(\014le.)55 b(Once)35 b(the)g(parser)f(reac)
+m(hes)i(the)0 1862 y(end)f(of)h(the)g(include)f(\014le)h(it)g(con)m
+(tin)m(ues)g(parsing)g(the)f(curren)m(t)h(template)h(\014le.)56
+b(Include)35 b(\014les)h(can)g(b)s(e)f(nested,)0 1975
+y(and)30 b(HDU)h(de\014nitions)f(can)g(span)g(m)m(ultiple)h(template)h
+(\014les.)0 2135 y(The)f(start)h(of)g(a)g(GR)m(OUP)h(de\014nition)e(is)
+h(denoted)g(with)f(the)h('group')g(directiv)m(e,)h(and)f(the)f(end)h
+(of)f(a)i(GR)m(OUP)0 2248 y(de\014nition)k(is)h(denoted)f(with)g(the)h
+('end')f(directiv)m(e.)63 b(Eac)m(h)39 b(GR)m(OUP)e(con)m(tains)i(0)f
+(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)i(of)f(t)m(yp)s
+(e)g(GR)m(OUP)g(can)g(con)m(tain)h(their)f(o)m(wn)g(mem)m(b)s(er)f(blo)
+s(c)m(ks.)0 2474 y(The)32 b(GR)m(OUP)g(de\014nition)g(itself)h(o)s
+(ccupies)g(one)f(FITS)g(\014le)g(HDU)h(of)f(sp)s(ecial)h(t)m(yp)s(e)f
+(\(GR)m(OUP)h(HDU\),)h(so)e(if)h(a)0 2587 y(template)f(sp)s(eci\014es)e
+(1)h(group)e(with)h(1)h(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)g(with)g(3)h(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)32 b(sp)s(eaking,)e(the)f(GR)m
+(OUP)i(HDU)f(is)g(a)g(BINT)-8 b(ABLE)30 b(with)g(6)g(columns.)40
+b(Applications)31 b(can)f(de\014ne)0 4382 y(additional)23
+b(columns)f(in)f(a)i(GR)m(OUP)f(HDU)h(using)f(TF)m(ORMn)f(and)h(TTYPEn)
+f(\(where)g(n)h(is)g(7,)i(8,)h(....\))39 b(k)m(eyw)m(ords)0
+4494 y(or)30 b(their)h(auto-indexing)g(equiv)-5 b(alen)m(ts.)0
+4655 y(F)d(or)26 b(a)f(more)g(complicated)h(example)f(of)g(a)h
+(template)g(\014le)f(using)f(the)h(group)f(directiv)m(es,)k(lo)s(ok)d
+(at)g(the)g(sample.tpl)0 4767 y(\014le)30 b(that)h(is)g(included)e(in)i
+(the)f(CFITSIO)f(distribution.)0 5100 y Fd(9.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)i(syn)m(tax)f(can)f(formally)h(b)s(e)f(de\014ned)f
+(as)i(follo)m(ws:)191 5601 y Fe(TEMPLATE)45 b(=)j(BLOCK)e([)i(BLOCK)e
+(...)h(])p eop end
+%%Page: 110 116
+TeXDict begin 110 115 bop 0 299 a Fi(110)2295 b Fg(CHAPTER)30
+b(9.)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,)i(the)e(template)i
+(de\014nes)c(1)j(or)e(more)h(template)h(blo)s(c)m(ks.)49
+b(Blo)s(c)m(ks)34 b(can)f(b)s(e)f(either)h(HDU)0 2050
+y(\(Header)27 b(Data)h(Unit\))g(or)e(a)h(GR)m(OUP)-8
+b(.)28 b(F)-8 b(or)27 b(eac)m(h)g(blo)s(c)m(k)g(the)g(parser)f(creates)
+i(1)f(\(or)g(more)f(for)h(GR)m(OUPs\))g(FITS)0 2163 y(\014le)j(HDUs.)0
+2495 y Fd(9.5)135 b(Errors)0 2745 y Fi(In)24 b(general)h(the)f(\014ts)p
+692 2745 28 4 v 33 w(execute)p 1019 2745 V 34 w(template\(\))i
+(function)e(tries)h(to)g(b)s(e)f(as)g(atomic)i(as)f(p)s(ossible,)g(so)f
+(either)h(ev)m(erything)0 2858 y(is)f(done)g(or)g(nothing)f(is)h(done.)
+39 b(If)23 b(an)h(error)f(o)s(ccurs)h(during)f(parsing)g(of)h(the)g
+(template,)j(\014ts)p 3125 2858 V 33 w(execute)p 3452
+2858 V 34 w(template\(\))0 2971 y(will)k(\(try)g(to\))h(delete)g(the)f
+(top)g(lev)m(el)h(BLOCK)e(\(with)h(all)g(its)h(c)m(hildren)e(if)h(an)m
+(y\))g(in)g(whic)m(h)f(the)h(error)f(o)s(ccurred,)0 3084
+y(then)g(it)h(will)g(stop)f(reading)h(the)f(template)i(\014le)e(and)g
+(it)h(will)g(return)e(with)h(an)g(error.)0 3417 y Fd(9.6)135
+b(Examples)0 3667 y Fi(1.)54 b(This)34 b(template)i(\014le)f(will)g
+(create)h(a)f(200)h(x)e(300)i(pixel)f(image,)j(with)c(4-b)m(yte)i(in)m
+(teger)g(pixel)f(v)-5 b(alues,)36 b(in)f(the)0 3780 y(primary)29
+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)i(v)-5 b(alues)36 b(of)f(BITPIX)g(are)
+h(8,)h(16,)h(32,)g(-32,)g(or)d(-64,)j(represen)m(ting,)f(resp)s(ectiv)m
+(ely)-8 b(,)39 b(8-bit)d(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)f(64)h
+(bit)g(\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,)26 b(the)c(template)i
+(\014rst)e(needs)g(to)i(include)e(XTENSION)g(=)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)h(is)g(an)f(ASCI)s(I)g(or)g(binary)g(table,)i(and)f(NAXIS2)g(to)g
+(de\014ne)f(the)h(n)m(um)m(b)s(er)f(of)h(ro)m(ws)f(in)h(the)0
+5348 y(table.)50 b(Tw)m(o)34 b(template)g(lines)g(are)g(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,)f(as)h(in)f(this)g(example:)
+95 5714 y Fe(xtension)46 b(=)h(bintable)p eop end
+%%Page: 111 117
+TeXDict begin 111 116 bop 0 299 a Fg(9.6.)72 b(EXAMPLES)3039
+b Fi(111)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)e(de\014nes)f(a)i(n)m(ull)f
+(primary)f(arra)m(y)h(follo)m(w)m(ed)i(b)m(y)e(a)g(40-ro)m(w)h(binary)e
+(table)i(extension)g(with)f(3)0 1718 y(columns)h(called)h('Name',)h
+('Np)s(oin)m(ts',)f(and)f('Rate',)i(with)e(data)h(formats)f(of)g('10A')
+i(\(ASCI)s(I)d(c)m(haracter)i(string\),)0 1831 y('1J')k(\(in)m(teger\))
+i(and)d('1E')i(\(\015oating)f(p)s(oin)m(t\),)h(resp)s(ectiv)m(ely)-8
+b(.)50 b(Note)34 b(that)f(the)g(other)g(required)f(FITS)g(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)j(de\014ned)d(in)i(the)f(template)i(b)s(ecause)f(their)
+g(v)-5 b(alues)38 b(can)g(b)s(e)f(inferred)f(from)i(the)f(other)h(k)m
+(eyw)m(ords)g(in)0 2170 y(the)d(template.)55 b(This)34
+b(example)i(also)g(illustrates)f(that)h(the)f(templates)h(are)f
+(generally)h(case-insensitiv)m(e)h(\(the)0 2283 y(k)m(eyw)m(ord)29
+b(names)g(and)g(TF)m(ORMn)f(v)-5 b(alues)30 b(are)f(con)m(v)m(erted)i
+(to)e(upp)s(er-case)g(in)f(the)h(FITS)g(\014le\))g(and)f(that)i(string)
+0 2396 y(k)m(eyw)m(ord)h(v)-5 b(alues)31 b(generally)g(do)f(not)h(need)
+f(to)h(b)s(e)f(enclosed)h(in)f(quotes.)p eop end
+%%Page: 112 118
+TeXDict begin 112 117 bop 0 299 a Fi(112)2295 b Fg(CHAPTER)30
+b(9.)71 b(TEMPLA)-8 b(TE)30 b(FILES)p eop end
+%%Page: 113 119
+TeXDict begin 113 118 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)f
+(page)h(29)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)h(Op)s(en)e(and)h(Close)h
+(Subroutines:)39 b(page)31 b(35)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(113)p
+eop end
+%%Page: 114 120
+TeXDict begin 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(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)33 b(Op)s(erations:)40 b(page)31 b(38)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)29 b(to)i(sp)s(ecify)f(or)g(mo)s(dify)g(the)g
+(structure)g(of)h(the)f(CHDU:)h(page)h(41)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)i(Subroutines:)39 b(page)31
+b(43)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)32 b(Standard)d(Header)i
+(Subroutines:)39 b(page)31 b(43)p eop end
+%%Page: 115 121
+TeXDict begin 115 120 bop 3764 299 a Fi(115)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)32
+b(Keyw)m(ord)e(Subroutines:)39 b(page)31 b(45)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[JKLS]\(unit,keyword)o
+(,ke)o(yval)o(,com)o(men)o(t,)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[JKLS]\(unit,keyroot)o(,st)o(artn)o
+(o,no)o(_ke)o(ys,k)o(eyva)o(ls,)o(comm)o(ents)o(,)42
+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:)39 b(page)31
+b(47)382 4408 y Fe(FTIREC\(unit,key_no,card,)41 b(>)47
+b(status\))382 4521 y(FTIKY[JKLS]\(unit,keyword)o(,ke)o(yval)o(,com)o
+(men)o(t,)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:)39 b(page)31 b(47)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 end
+%%Page: 116 122
+TeXDict begin 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)382 555 y Fe(FTGKEY\(unit,keyword,)42
+b(>)48 b(value,comment,status\))382 668 y(FTGKY[EDJKLS]\(unit,keywo)o
+(rd,)41 b(>)48 b(keyval,comment,status\))382 781 y
+(FTGKN[EDJKLS]\(unit,keyro)o(ot,)o(star)o(tno,)o(max)o(_key)o(s,)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)30 b(Keyw)m(ord)g(Subroutines:)39
+b(page)31 b(49)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[JKLS]\(unit,keyword)o(,ke)o(yval)o
+(,com)o(men)o(t,)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:)39
+b(page)32 b(50)382 2822 y Fe(FTUCRD\(unit,keyword,card)o(,)42
+b(>)47 b(status\))382 2935 y(FTUKY[JKLS]\(unit,keyword)o(,ke)o(yval)o
+(,com)o(men)o(t,)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)33 b(Keyw)m(ord)d(Subroutines:)39 b(page)31
+b(50)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)f(P)m(arameters)g(and)f(Unde\014ned)f
+(Pixel)i(Flags:)42 b(page)31 b(51)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)f(Arra)m(y)i(or)f(IMA)m(GE)i(Extension)e
+(I/O)h(Subroutines:)39 b(page)31 b(52)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
+end
+%%Page: 117 123
+TeXDict begin 117 122 bop 3764 299 a Fi(117)382 555 y
+Fe(FTGIPR\(unit,)44 b(maxdim,)i(>)i(bitpix,naxis,naxes,stat)o(us\))382
+668 y(FTPPR[BIJKED]\(unit,group)o(,fp)o(ixel)o(,nel)o(eme)o(nts,)o
+(valu)o(es,)41 b(>)48 b(status\))382 781 y(FTPPN[BIJKED]\(unit,group)o
+(,fp)o(ixel)o(,nel)o(eme)o(nts,)o(valu)o(es,)o(null)o(val)41
+b(>)48 b(status\))382 894 y(FTPPRU\(unit,group,fpixel)o(,ne)o(leme)o
+(nts,)41 b(>)47 b(status\))382 1007 y(FTGPV[BIJKED]\(unit,group)o(,fp)o
+(ixel)o(,nel)o(eme)o(nts,)o(null)o(val)o(,)42 b(>)47
+b(values,anyf,status\))382 1120 y(FTGPF[BIJKED]\(unit,group)o(,fp)o
+(ixel)o(,nel)o(eme)o(nts,)41 b(>)48 b(values,flagvals,anyf,st)o(atu)o
+(s\))382 1233 y(FTPGP[BIJKED]\(unit,group)o(,fp)o(arm,)o(npar)o(m,v)o
+(alue)o(s,)42 b(>)47 b(status\))382 1346 y(FTGGP[BIJKED]\(unit,group)o
+(,fp)o(arm,)o(npar)o(m,)41 b(>)48 b(values,status\))382
+1458 y(FTP2D[BIJKED]\(unit,group)o(,di)o(m1,n)o(axis)o(1,n)o(axis)o
+(2,im)o(age)o(,)42 b(>)47 b(status\))382 1571 y
+(FTP3D[BIJKED]\(unit,group)o(,di)o(m1,d)o(im2,)o(nax)o(is1,)o(naxi)o
+(s2,)o(naxi)o(s3,c)o(ube)o(,)42 b(>)47 b(status\))382
+1684 y(FTG2D[BIJKED]\(unit,group)o(,nu)o(llva)o(l,di)o(m1,)o(naxi)o
+(s1,n)o(axi)o(s2,)41 b(>)48 b(image,anyf,status\))382
+1797 y(FTG3D[BIJKED]\(unit,group)o(,nu)o(llva)o(l,di)o(m1,)o(dim2)o
+(,nax)o(is1)o(,nax)o(is2,)o(nax)o(is3,)41 b(>)1002 1910
+y(cube,anyf,status\))382 2023 y(FTPSS[BIJKED]\(unit,group)o(,na)o(xis,)
+o(naxe)o(s,f)o(pixe)o(ls,l)o(pix)o(els,)o(arra)o(y,)g(>)48
+b(status\))382 2136 y(FTGSV[BIJKED]\(unit,group)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 2249 y(array,anyf,status\))382 2362 y
+(FTGSF[BIJKED]\(unit,group)o(,na)o(xis,)o(naxe)o(s,f)o(pixe)o(ls,l)o
+(pix)o(els,)o(incs)o(,)g(>)1002 2475 y(array,flagvals,anyf,statu)o(s\))
+0 2739 y Fi(T)-8 b(able)31 b(Column)e(Information)i(Subroutines:)39
+b(page)31 b(55)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)32 b(T)-8
+b(able)31 b(Access)h(Subroutines:)39 b(page)31 b(58)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)30
+b(Ro)m(ws)h(or)f(Columns)g(page)h(58)p eop end
+%%Page: 118 124
+TeXDict begin 118 123 bop 0 299 a Fi(118)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)32 b(Column)e(Data)i(Routines)e
+(page)h(60)382 1974 y Fe(FTPCL[SLBIJKEDCM]\(unit,c)o(oln)o(um,f)o(row,)
+o(fel)o(em,n)o(elem)o(ent)o(s,va)o(lues)o(,)42 b(>)47
+b(status\))382 2087 y(FTPCN[BIJKED]\(unit,colnu)o(m,f)o(row,)o(fele)o
+(m,n)o(elem)o(ents)o(,va)o(lues)o(,nul)o(lva)o(l)42 b(>)47
+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[SBIJKEDCM]\(unit,co)o(lnu)o
+(m,fr)o(ow,f)o(ele)o(m,ne)o(leme)o(nts)o(,nul)o(lval)o(,)42
+b(>)1098 2651 y(values,anyf,status\))382 2764 y
+(FTGCF[SLBIJKEDCM]\(unit,c)o(oln)o(um,f)o(row,)o(fel)o(em,n)o(elem)o
+(ent)o(s,)g(>)1193 2877 y(values,flagvals,anyf,stat)o(us\))382
+2990 y(FTGSV[BIJKED]\(unit,colnu)o(m,n)o(axis)o(,nax)o(es,)o(fpix)o
+(els,)o(lpi)o(xels)o(,inc)o(s,n)o(ullv)o(al,)f(>)1002
+3103 y(array,anyf,status\))382 3216 y(FTGSF[BIJKED]\(unit,colnu)o(m,n)o
+(axis)o(,nax)o(es,)o(fpix)o(els,)o(lpi)o(xels)o(,inc)o(s,)g(>)1002
+3329 y(array,flagvals,anyf,statu)o(s\))382 3441 y
+(FTGCX\(unit,colnum,frow,f)o(bit)o(,nbi)o(t,)h(>)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)h(and)d(Calculator)
+j(Routines:)41 b(page)31 b(64)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)32 b(Co)s(ordinate)f(System)f
+(Subroutines:)39 b(page)31 b(65)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 end
+%%Page: 119 125
+TeXDict begin 119 124 bop 3764 299 a Fi(119)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)32 b(Chec)m(ksum)d(Subroutines:)40
+b(page)31 b(67)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)30 b(and)g(Date)i(Utilit)m(y)h
+(Subroutines:)39 b(page)31 b(68)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)31 b(Utilit)m(y)i(Subroutines:)39 b(page)31
+b(69)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 end
+%%Page: 120 126
+TeXDict begin 120 125 bop 0 299 a Fi(120)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 end
+%%Page: 121 127
+TeXDict begin 121 126 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(blank)g(-)i(\(integer*8\))d(value)h(used)h
+(for)f(undefined)g(pixels)g(in)h(integer)f(primary)g(array)0
+2744 y(blocksize)f(-)j(\(integer\))d(2880-byte)g(logical)h(record)g
+(blocking)g(factor)477 2857 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 2970 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 3083 y(blocksizes)e(greater)h(than)h(2880)f(are)h(no)g
+(longer)g(supported.)0 3196 y(bscale)f(-)i(\(double)d(precision\))g
+(scaling)h(factor)g(for)h(the)g(primary)f(array)0 3309
+y(bytlen)g(-)i(\(integer\))d(length)h(of)h(the)g(data)g(unit,)f(in)h
+(bytes)0 3422 y(bzero)f(-)i(\(double)e(precision\))f(zero)h(point)h
+(for)g(primary)e(array)i(scaling)0 3535 y(card)g(-)g(\(character*80\))d
+(header)i(record)g(to)h(be)h(read)e(or)h(written)0 3648
+y(casesen)f(-)h(\(logical\))f(will)g(string)g(matching)g(be)h(case)g
+(sensitive?)0 3760 y(checksum)f(-)h(\(character*16\))d(encoded)i
+(checksum)f(string)0 3873 y(colname)h(-)h(\(character\))e(ASCII)h(name)
+h(of)g(the)g(column)0 3986 y(colnum)f(-)i(\(integer\))d(number)h(of)h
+(the)g(column)f(\(first)g(column)g(=)i(1\))0 4099 y(coltemplate)d(-)i
+(\(character\))e(template)g(string)i(to)g(be)g(matched)f(to)h(column)f
+(names)0 4212 y(comment)g(-)h(\(character\))e(the)i(keyword)f(comment)g
+(field)0 4325 y(comments)g(-)h(\(character)e(array\))h(keyword)g
+(comment)g(fields)0 4438 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
+4551 y(complement)g(-)i(\(logical\))f(should)g(the)h(checksum)e(be)i
+(complemented?)0 4664 y(coordtype)e(-)j(\(character\))c(type)j(of)g
+(coordinate)e(projection)g(\(-SIN,)h(-TAN,)h(-ARC,)477
+4777 y(-NCP,)g(-GLS,)f(-MER,)g(or)i(-AIT\))0 4890 y(cube)f(-)g(3D)g
+(data)g(cube)g(of)g(the)g(appropriate)d(datatype)0 5002
+y(curaddr)i(-)h(\(integer\))f(starting)f(address)h(\(in)h(bytes\))f(of)
+h(the)g(CHDU)0 5115 y(current)f(-)h(\(integer\))f(if)h(not)g(equal)f
+(to)h(0,)g(copy)g(the)g(current)f(HDU)0 5228 y(datacode)g(-)h
+(\(integer\))e(symbolic)h(code)g(of)i(the)f(binary)f(table)g(column)g
+(datatype)0 5341 y(dataok)g(-)i(\(integer\))d(was)i(the)g(data)f(unit)h
+(verification)d(successful)h(\(=1\))i(or)430 5454 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 5567 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 5680
+y(datatype)f(-)h(\(character\))e(datatype)g(\(format\))h(of)h(the)g
+(binary)f(table)g(column)1882 5942 y Fi(121)p eop end
+%%Page: 122 128
+TeXDict begin 122 127 bop 0 299 a Fi(122)1779 b Fg(CHAPTER)30
+b(11.)112 b(P)-8 b(ARAMETER)30 b(DEFINITIONS)0 555 y
+Fe(datestr)94 b(-)47 b(\(string\))f(FITS)g(date/time)f(string:)h
+('YYYY-MM-DDThh:mm:ss.ddd')o(,)525 668 y('YYYY-MM-dd',)e(or)j
+('dd/mm/yy')0 781 y(day)g(-)g(\(integer\))f(current)f(day)i(of)h(the)e
+(month)0 894 y(dblval)g(-)i(\(double)d(precision\))g(fractional)g(part)
+i(of)g(the)g(keyword)f(value)0 1007 y(decimals)g(-)h(\(integer\))e
+(number)h(of)i(decimal)d(places)h(to)i(be)f(displayed)0
+1120 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 1233
+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 1346 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 1458 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
+1571 y(C)f(=)h(character)d(string)764 1684 y(L)i(=)h(logical)764
+1797 y(I)f(=)h(integer)764 1910 y(F)f(=)h(floating)d(point)h(number)0
+2023 y(errmsg)g(-)i(\(character*80\))43 b(oldest)k(error)f(message)g
+(on)h(the)g(internal)e(stack)0 2136 y(errtext)h(-)h(\(character*30\))d
+(descriptive)h(error)h(message)g(corresponding)e(to)j(error)g(number)0
+2249 y(casesen)f(-)h(\(logical\))f(true)g(if)h(column)f(name)h
+(matching)f(is)h(case)f(sensitive)0 2362 y(exact)g(-)i(\(logical\))d
+(do)i(the)g(strings)f(match)g(exactly,)g(or)h(were)g(wildcards)e(used?)
+0 2475 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 2588 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 2700 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 2813 y(extname)g(-)h(\(character\))e(value)h(of)i(the)e(EXTNAME)g
+(keyword)g(\(if)h(not)g(blank\))0 2926 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
+3039 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 3152 y(filename)f(-)h
+(\(character\))e(name)h(of)i(the)e(FITS)h(file)0 3265
+y(flagvals)f(-)h(\(logical)f(array\))g(True)g(if)h(corresponding)e
+(data)h(element)g(is)h(undefined)0 3378 y(following)e(-)j(\(integer\))d
+(if)i(not)g(equal)f(to)i(0,)f(copy)f(all)h(following)f(HDUs)g(in)h(the)
+g(input)g(file)0 3491 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
+3604 y(fpixel)f(-)i(\(integer\))d(the)i(first)f(pixel)g(position)0
+3717 y(fpixels)g(-)h(\(integer)f(array\))g(the)h(first)f(included)g
+(pixel)g(in)h(each)g(dimension)0 3830 y(frow)g(-)g(\(integer\))e
+(beginning)h(row)h(number)f(\(first)g(row)h(of)g(table)f(=)i(1\))0
+3942 y(frowll)e(-)i(\(integer*8\))c(beginning)i(row)g(number)h(\(first)
+f(row)h(of)g(table)f(=)i(1\))0 4055 y(gcount)e(-)i(\(integer\))d(value)
+h(of)h(the)g(GCOUNT)f(keyword)g(\(usually)g(=)h(1\))0
+4168 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 4281 y(hdtype)i(-)i
+(\(integer\))d(header)h(record)g(type:)g(-1=delete;)93
+b(0=append)46 b(or)h(replace;)907 4394 y(1=append;)e(2=this)h(is)h(the)
+g(END)g(keyword)0 4507 y(hduok)f(-)i(\(integer\))d(was)i(the)g(HDU)g
+(verification)d(successful)h(\(=1\))i(or)430 4620 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 4733 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
+4846 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 4959
+y(2)g(=)h(binary)e(table,)g(-1)h(=)h(any)e(HDU)h(type)g(or)g(unknown)f
+(type)0 5072 y(history)g(-)h(\(character\))e(the)i(HISTORY)f(keyword)g
+(comment)f(string)0 5185 y(hour)i(-)g(\(integer\))e(hour)i(from)g(0)g
+(-)h(23)0 5297 y(image)e(-)i(2D)f(image)f(of)i(the)e(appropriate)f
+(datatype)0 5410 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 5523 y(incs)g(-)g
+(\(integer)f(array\))g(sampling)f(interval)h(for)h(pixels)f(in)h(each)g
+(FITS)f(dimension)0 5636 y(intval)g(-)i(\(integer\))d(integer)h(part)g
+(of)h(the)g(keyword)f(value)p eop end
+%%Page: 123 129
+TeXDict begin 123 128 bop 3764 299 a Fi(123)0 555 y Fe(iounit)46
+b(-)i(\(integer\))d(value)h(of)h(an)h(unused)e(I/O)h(unit)f(number)0
+668 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 781 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 894 y(keylength)g(-)j(\(integer\))d(length)h(of)h
+(the)g(keyword)f(name)0 1007 y(keyroot)g(-)h(\(character\))e(root)i
+(string)f(for)h(the)g(keyword)e(name)0 1120 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 1233 y(keysexist)e(-)j(\(integer\))d(number)h(of)h(existing)f
+(keyword)g(records)f(in)j(the)f(CHU)0 1346 y(keyval)f(-)i(value)e(of)h
+(the)g(keyword)f(in)h(the)g(appropriate)e(datatype)0
+1458 y(keyvals)h(-)h(\(array\))f(value)g(of)i(the)f(keywords)e(in)i
+(the)g(appropriate)e(datatype)0 1571 y(keyword)h(-)h(\(character*8\))d
+(name)j(of)g(a)h(keyword)0 1684 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 1797 y(lpixels)f(-)h(\(integer)f(array\))g(the)h(last)f
+(included)g(pixel)g(in)i(each)e(dimension)0 1910 y(match)g(-)i
+(\(logical\))d(do)i(the)g(2)h(strings)d(match?)0 2023
+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 2136 y(max_keys)g(-)h
+(\(integer\))e(maximum)h(number)g(of)h(keywords)f(to)h(search)f(for)0
+2249 y(minute)g(-)i(\(integer\))d(minute)h(of)h(an)g(hour)g(\(0)g(-)h
+(59\))0 2362 y(month)e(-)i(\(integer\))d(current)h(month)g(of)h(the)g
+(year)g(\(1)g(-)h(12\))0 2475 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 2588 y(naxes)f(-)i(\(integer)d(array\))h(size)h(of)g(each)g
+(dimension)e(in)i(the)g(FITS)g(array)0 2700 y(naxesll)f(-)h
+(\(integer*8)e(array\))h(size)h(of)g(each)g(dimension)e(in)i(the)g
+(FITS)g(array)0 2813 y(naxis)f(-)i(\(integer\))d(number)h(of)h
+(dimensions)e(in)j(the)e(FITS)h(array)0 2926 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 3039 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 3152 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 3265 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 3378 y(nchars)f(-)i(\(integer\))d
+(number)h(of)h(characters)e(to)i(read)g(and)g(return)0
+3491 y(ncols)f(-)i(\(integer\))d(number)h(of)h(columns)0
+3604 y(nelements)e(-)j(\(integer\))d(number)h(of)h(data)g(elements)e
+(to)j(read)e(or)h(write)0 3717 y(nelementsll)e(-)i(\(integer*8\))e
+(number)h(of)h(data)g(elements)e(to)j(read)e(or)h(write)0
+3830 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 3942 y(nhdu)f(-)g(\(integer\))e
+(absolute)h(number)g(of)h(the)g(HDU)g(\(1st)g(HDU)g(=)g(1\))0
+4055 y(ninc)142 b(\(integer\))93 b(number)46 b(of)h(names)g(in)g(the)g
+(inclusion)e(list)0 4168 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 4281 y(nfound)g(-)i(\(integer\))d(number)h(of)h(keywords)f
+(found)g(\(highest)g(keyword)f(number\))0 4394 y(no_keys)h(-)h
+(\(integer\))f(number)g(of)h(keywords)e(to)j(write)e(in)h(the)g
+(sequence)0 4507 y(nparm)f(-)i(\(integer\))d(number)h(of)h(group)g
+(parameters)e(to)i(read)g(or)g(write)0 4620 y(nrows)f(-)i(\(integer\))d
+(number)h(of)h(rows)g(in)g(the)g(table)0 4733 y(nrowsll)f(-)h
+(\(integer*8\))e(number)h(of)h(rows)g(in)g(the)g(table)0
+4846 y(nullval)f(-)h(value)g(to)g(represent)e(undefined)g(pixels,)h(of)
+h(the)g(appropriate)e(datatype)0 4959 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 5072 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
+5185 y(offsetll)f(-)h(\(integer*8\))e(byte)h(offset)g(in)i(the)f(heap)f
+(to)h(the)g(first)g(element)e(of)j(the)f(array)0 5297
+y(oldkey)f(-)i(\(character\))c(old)j(name)g(of)g(keyword)f(to)h(be)g
+(modified)0 5410 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
+5523 y(pcount)f(-)i(\(integer\))d(value)h(of)h(the)g(PCOUNT)f(keyword)g
+(\(usually)g(=)h(0\))0 5636 y(previous)f(-)h(\(integer\))e(if)i(not)g
+(equal)g(to)g(0,)g(copy)g(all)g(previous)e(HDUs)i(in)g(the)g(input)f
+(file)p eop end
+%%Page: 124 130
+TeXDict begin 124 129 bop 0 299 a Fi(124)1779 b Fg(CHAPTER)30
+b(11.)112 b(P)-8 b(ARAMETER)30 b(DEFINITIONS)0 555 y
+Fe(repeat)46 b(-)i(\(integer\))d(length)h(of)h(element)f(vector)g
+(\(e.g.)g(12J\);)h(ignored)f(for)g(ASCII)h(table)0 668
+y(rot)g(-)g(\(double)f(precision\))f(celestial)g(coordinate)g(rotation)
+h(angle)g(\(degrees\))0 781 y(rowlen)g(-)i(\(integer\))d(length)h(of)h
+(a)h(table)e(row,)h(in)g(characters)e(or)i(bytes)0 894
+y(rowlenll)f(-)h(\(integer*8\))e(length)h(of)h(a)g(table)g(row,)f(in)i
+(characters)d(or)i(bytes)0 1007 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 1120 y(rownum)h(-)i(\(integer\))d(number)h(of)h(the)g(row)g
+(\(first)f(row)h(=)g(1\))0 1233 y(rowrange-)e(\(string\))h(list)g(of)i
+(rows)e(or)h(row)g(ranges)f(to)i(be)f(deleted)0 1346
+y(rwmode)f(-)i(\(integer\))d(file)h(access)h(mode:)f(0)h(=)h(readonly,)
+d(1)j(=)f(readwrite)0 1458 y(second)142 b(\(double\)-)45
+b(second)h(within)g(minute)g(\(0)h(-)h(60.9999999999\))c(\(leap)i
+(second!\))0 1571 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)0 1684
+y(simple)g(-)i(\(logical\))d(does)h(the)h(FITS)g(file)g(conform)e(to)j
+(all)f(the)f(FITS)h(standards)0 1797 y(snull)f(-)i(\(character\))d
+(value)h(used)h(to)g(represent)e(undefined)g(values)h(in)i(ASCII)e
+(table)0 1910 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 2023
+y(startchar)f(-)j(\(integer\))d(first)h(character)g(in)h(the)g(row)g
+(to)g(be)g(read)0 2136 y(startno)f(-)h(\(integer\))f(value)g(of)h(the)g
+(first)f(keyword)g(sequence)g(number)g(\(usually)f(1\))0
+2249 y(status)h(-)i(\(integer\))d(returned)g(error)i(status)f(code)g
+(\(0)i(=)f(OK\))0 2362 y(str_template)d(\(character\))h(template)h
+(string)g(to)h(be)g(matched)f(to)h(reference)e(string)0
+2475 y(stream)h(-)i(\(character\))c(output)i(stream)g(for)h(the)g
+(report:)f(either)g('STDOUT')g(or)h('STDERR')0 2588 y(string)f(-)i
+(\(character\))c(character)i(string)0 2700 y(sum)h(-)g(\(double)f
+(precision\))f(32)i(bit)g(unsigned)f(checksum)f(value)0
+2813 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 2926 y(tdisp)g(-)i
+(\(character\))d(Fortran)g(type)i(display)f(format)g(for)h(the)g(table)
+f(column)0 3039 y(template-\(character\))c(template)k(string)g(for)h(a)
+g(FITS)g(header)f(record)0 3152 y(tfields)g(-)h(\(integer\))f(number)g
+(of)h(fields)f(\(columns\))f(in)i(the)g(table)0 3265
+y(tform)f(-)i(\(character)d(array\))h(format)g(of)h(the)g(column\(s\);)
+e(allowed)h(values)g(are:)430 3378 y(For)g(ASCII)h(tables:)93
+b(Iw,)47 b(Aw,)g(Fww.dd,)f(Eww.dd,)g(or)h(Dww.dd)430
+3491 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 3604 y(where)f('w'=width)f(of)i(the)g
+(field,)f('d'=no.)g(of)h(decimals,)f('r'=repeat)f(count)430
+3717 y(Note)h(that)h(the)g('rAw')f(form)h(is)g(non-standard)d
+(extension)i(to)h(the)430 3830 y(TFORM)f(keyword)g(syntax)g(that)g(is)i
+(not)f(specifically)d(defined)i(in)h(the)430 3942 y(Binary)f(Tables)g
+(definition)f(document.)0 4055 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 4168 y(relative)e(to)i(the)g(beginning)e(of)j(the)f(binary)f(table)
+g(data)0 4281 y(tnull)g(-)i(\(integer\))d(value)h(used)h(to)g
+(represent)f(undefined)f(values)h(in)h(binary)f(table)0
+4394 y(tnullll)g(-)h(\(integer*8\))e(value)h(used)h(to)g(represent)e
+(undefined)h(values)g(in)h(binary)f(table)0 4507 y(ttype)g(-)i
+(\(character)d(array\))h(label)g(for)h(table)g(column\(s\))0
+4620 y(tscal)f(-)i(\(double)e(precision\))f(scaling)g(factor)i(for)f
+(table)h(column)0 4733 y(tunit)f(-)i(\(character)d(array\))h(physical)f
+(unit)i(for)g(table)f(column\(s\))0 4846 y(tzero)g(-)i(\(double)e
+(precision\))f(scaling)g(zero)i(point)f(for)h(table)g(column)0
+4959 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
+5072 y(units)g(-)i(\(character\))d(the)h(keyword)g(units)h(string)f
+(\(e.g.,)g('km/s'\))0 5185 y(value)g(-)i(\(character\))d(the)h(keyword)
+g(value)h(string)0 5297 y(values)f(-)i(array)e(of)h(data)g(values)f(of)
+h(the)g(appropriate)e(datatype)0 5410 y(varidat)h(-)h(\(integer\))f
+(size)g(in)h(bytes)g(of)g(the)g('variable)e(length)h(data)h(area')525
+5523 y(following)e(the)i(binary)f(table)h(data)f(\(usually)g(=)h(0\))0
+5636 y(version)f(-)h(\(real\))f(current)g(revision)g(number)g(of)h(the)
+g(library)p eop end
+%%Page: 125 131
+TeXDict begin 125 130 bop 3764 299 a Fi(125)0 555 y Fe(width)46
+b(-)i(\(integer\))d(width)h(of)i(the)f(character)e(string)h(field)0
+668 y(xcol)h(-)g(\(integer\))e(number)h(of)i(the)f(column)f(containing)
+f(the)i(X)g(coordinate)e(values)0 781 y(xinc)i(-)g(\(double)f
+(precision\))f(X)i(axis)g(coordinate)e(increment)g(at)i(reference)f
+(pixel)g(\(deg\))0 894 y(xpix)h(-)g(\(double)f(precision\))f(X)i(axis)g
+(pixel)f(location)0 1007 y(xpos)h(-)g(\(double)f(precision\))f(X)i
+(axis)g(celestial)e(coordinate)g(\(usually)h(RA\))h(\(deg\))0
+1120 y(xrpix)f(-)i(\(double)e(precision\))f(X)i(axis)g(reference)e
+(pixel)h(array)h(location)0 1233 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 1346 y(ycol)g(-)g(\(integer\))e(number)h(of)i(the)f(column)f
+(containing)f(the)i(X)g(coordinate)e(values)0 1458 y(year)i(-)g
+(\(integer\))e(last)i(2)g(digits)g(of)g(the)g(year)f(\(00)h(-)h(99\))0
+1571 y(yinc)f(-)g(\(double)f(precision\))f(Y)i(axis)g(coordinate)e
+(increment)g(at)i(reference)f(pixel)g(\(deg\))0 1684
+y(ypix)h(-)g(\(double)f(precision\))f(y)i(axis)g(pixel)f(location)0
+1797 y(ypos)h(-)g(\(double)f(precision\))f(y)i(axis)g(celestial)e
+(coordinate)g(\(usually)h(DEC\))g(\(deg\))0 1910 y(yrpix)g(-)i
+(\(double)e(precision\))f(Y)i(axis)g(reference)e(pixel)h(array)h
+(location)0 2023 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 end
+%%Page: 126 132
+TeXDict begin 126 131 bop 0 299 a Fi(126)1779 b Fg(CHAPTER)30
+b(11.)112 b(P)-8 b(ARAMETER)30 b(DEFINITIONS)p eop end
+%%Page: 127 133
+TeXDict begin 127 132 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(127)p eop end
+%%Page: 128 134
+TeXDict begin 128 133 bop 0 299 a Fi(128)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(206)95 b(illegal)45
+b(indexed)h(keyword)g(name)h(\(e.g.)f('TFORM1000'\))0
+1797 y(207)95 b(illegal)45 b(character)h(in)h(keyword)f(name)g(or)i
+(header)e(record)0 1910 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
+2023 y(209)95 b(keyword)45 b(does)i(not)g(have)g(expected)e(integer)h
+(value)0 2136 y(210)95 b(could)46 b(not)h(find)g(the)f(required)g(END)h
+(header)f(keyword)0 2249 y(211)95 b(illegal)45 b(BITPIX)i(keyword)e
+(value)0 2362 y(212)95 b(illegal)45 b(NAXIS)i(keyword)f(value)0
+2475 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 2588 y(214)95 b(illegal)45
+b(PCOUNT)i(keyword)e(value)0 2700 y(215)95 b(illegal)45
+b(GCOUNT)i(keyword)e(value)0 2813 y(216)95 b(illegal)45
+b(TFIELDS)h(keyword)g(value)0 2926 y(217)95 b(negative)45
+b(ASCII)i(or)g(binary)f(table)g(width)h(value)f(\(NAXIS1\))0
+3039 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 3152 y(219)95 b(column)46
+b(name)g(\(TTYPE)g(keyword\))g(not)h(found)0 3265 y(220)95
+b(illegal)45 b(SIMPLE)i(keyword)e(value)0 3378 y(221)95
+b(could)46 b(not)h(find)g(the)f(required)g(SIMPLE)g(header)g(keyword)0
+3491 y(222)95 b(could)46 b(not)h(find)g(the)f(required)g(BITPIX)g
+(header)g(keyword)0 3604 y(223)95 b(could)46 b(not)h(find)g(the)f
+(required)g(NAXIS)g(header)g(keyword)0 3717 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 3830 y(225)95 b(could)46 b(not)h(find)g(the)f
+(required)g(XTENSION)g(header)g(keyword)0 3942 y(226)95
+b(the)47 b(CHDU)f(is)h(not)g(an)g(ASCII)g(table)f(extension)0
+4055 y(227)95 b(the)47 b(CHDU)f(is)h(not)g(a)h(binary)e(table)g
+(extension)0 4168 y(228)95 b(could)46 b(not)h(find)g(the)f(required)g
+(PCOUNT)g(header)g(keyword)0 4281 y(229)95 b(could)46
+b(not)h(find)g(the)f(required)g(GCOUNT)g(header)g(keyword)0
+4394 y(230)95 b(could)46 b(not)h(find)g(the)f(required)g(TFIELDS)g
+(header)g(keyword)0 4507 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 4620
+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 4733 y(233)95 b(the)47
+b(CHDU)f(is)h(not)g(an)g(IMAGE)g(extension)0 4846 y(234)95
+b(illegal)45 b(TBCOL)i(keyword)f(value;)g(out)h(of)g(range)0
+4959 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 5072 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 5185 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
+5297 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 5410 y(251)95
+b(unrecognizable)44 b(type)i(of)h(FITS)g(extension)0
+5523 y(252)95 b(unrecognizable)44 b(FITS)i(record)0 5636
+y(253)95 b(END)47 b(keyword)e(contains)h(non-blank)f(characters)g(in)i
+(columns)f(9-80)p eop end
+%%Page: 129 135
+TeXDict begin 129 134 bop 3764 299 a Fi(129)0 555 y Fe(254)95
+b(Header)46 b(fill)g(area)h(contains)f(non-blank)f(characters)0
+668 y(255)95 b(Data)46 b(fill)h(area)g(contains)e(non-blank)g(on)j
+(non-zero)d(values)0 781 y(261)95 b(unable)46 b(to)h(parse)f(the)h
+(TFORM)g(keyword)e(value)i(string)0 894 y(262)95 b(unrecognizable)44
+b(TFORM)i(datatype)f(code)0 1007 y(263)95 b(illegal)45
+b(TDIMn)i(keyword)f(value)0 1233 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 1346 y(302)95 b(column)46 b(number)g(out)h(of)g(range)
+f(\(1)h(-)h(999\))0 1458 y(304)95 b(attempt)45 b(to)j(move)e(to)h
+(negative)f(file)h(record)f(number)0 1571 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 1684 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
+1797 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 1910 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 2023 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
+2136 y(311)95 b(illegal)45 b(ASCII)i(table)f(TFORM)h(format)f(code)g
+(for)h(attempted)e(operation)0 2249 y(312)95 b(illegal)45
+b(binary)i(table)f(TFORM)g(format)g(code)h(for)g(attempted)e(operation)
+0 2362 y(314)95 b(value)46 b(for)h(undefined)e(pixels)h(has)h(not)g
+(been)g(defined)0 2475 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
+2588 y(320)95 b(number)46 b(of)h(array)f(dimensions)f(out)i(of)g(range)
+0 2700 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 2813 y(322)95 b(attempt)45
+b(to)j(set)f(BSCALE)f(or)h(TSCALn)f(scaling)g(parameter)f(=)i(0)0
+2926 y(323)95 b(illegal)45 b(axis)i(length)f(less)h(than)f(1)0
+3152 y(340)h(NOT_GROUP_TABLE)d(340)142 b(Grouping)45
+b(function)h(error)0 3265 y(341)95 b(HDU_ALREADY_MEMBER)0
+3378 y(342)47 b(MEMBER_NOT_FOUND)0 3491 y(343)g(GROUP_NOT_FOUND)0
+3604 y(344)g(BAD_GROUP_ID)0 3717 y(345)g(TOO_MANY_HDUS_TRACKED)0
+3830 y(346)g(HDU_ALREADY_TRACKED)0 3942 y(347)g(BAD_OPTION)0
+4055 y(348)g(IDENTICAL_POINTERS)0 4168 y(349)g(BAD_GROUP_ATTACH)0
+4281 y(350)g(BAD_GROUP_DETACH)0 4507 y(360)g(NGP_NO_MEMORY)665
+b(malloc)46 b(failed)0 4620 y(361)h(NGP_READ_ERR)713
+b(read)46 b(error)h(from)f(file)0 4733 y(362)h(NGP_NUL_PTR)761
+b(null)46 b(pointer)g(passed)g(as)h(an)g(argument.)1575
+4846 y(Passing)f(null)g(pointer)g(as)h(a)h(name)f(of)1575
+4959 y(template)f(file)g(raises)g(this)h(error)0 5072
+y(363)g(NGP_EMPTY_CURLINE)473 b(line)46 b(read)h(seems)f(to)h(be)h
+(empty)e(\(used)1575 5185 y(internally\))0 5297 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 5410 y(line)g(twice\))0 5523
+y(365)g(NGP_INC_NESTING)569 b(too)46 b(deep)h(include)f(file)h(nesting)
+e(\(infinite)1575 5636 y(loop,)h(template)g(includes)f(itself)i(?\))p
+eop end
+%%Page: 130 136
+TeXDict begin 130 135 bop 0 299 a Fi(130)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(366)47 b(NGP_ERR_FOPEN)665 b(fopen\(\))45
+b(failed,)h(cannot)g(open)h(template)e(file)0 668 y(367)i(NGP_EOF)953
+b(end)46 b(of)i(file)e(encountered)f(and)i(not)g(expected)0
+781 y(368)g(NGP_BAD_ARG)761 b(bad)46 b(arguments)g(passed.)g(Usually)f
+(means)1575 894 y(internal)h(parser)g(error.)g(Should)g(not)h(happen)0
+1007 y(369)g(NGP_TOKEN_NOT_EXPECT)329 b(token)46 b(not)h(expected)e
+(here)0 1233 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
+1346 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 1458
+y(403)95 b(cannot)46 b(convert)g(a)h(quoted)f(string)g(keyword)g(to)h
+(an)g(integer)0 1571 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
+1684 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 1797 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
+1910 y(407)95 b(error)46 b(attempting)f(to)i(read)g(character)e(string)
+h(as)h(an)h(integer)0 2023 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
+2136 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 2249 y(410)95
+b(bad)47 b(keyword)e(datatype)h(code)0 2362 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 2475 y(412)95 b(numerical)45
+b(overflow)g(during)i(implicit)e(datatype)h(conversion)0
+2588 y(413)95 b(error)46 b(compressing)f(image)0 2700
+y(414)95 b(error)46 b(uncompressing)e(image)0 2813 y(420)95
+b(error)46 b(in)h(date)g(or)g(time)g(conversion)0 3039
+y(431)95 b(syntax)46 b(error)g(in)h(parser)f(expression)0
+3152 y(432)95 b(expression)45 b(did)i(not)f(evaluate)g(to)h(desired)f
+(type)0 3265 y(433)95 b(vector)46 b(result)g(too)h(large)f(to)h(return)
+f(in)i(array)0 3378 y(434)95 b(data)46 b(parser)g(failed)g(not)h(sent)g
+(an)g(out)g(column)0 3491 y(435)95 b(bad)47 b(data)f(encounter)f(while)
+i(parsing)f(column)0 3604 y(436)95 b(parse)46 b(error:)g(output)g(file)
+h(not)g(of)g(proper)f(type)0 3830 y(501)95 b(celestial)45
+b(angle)h(too)h(large)g(for)f(projection)0 3942 y(502)95
+b(bad)47 b(celestial)e(coordinate)g(or)i(pixel)f(value)0
+4055 y(503)95 b(error)46 b(in)h(celestial)e(coordinate)g(calculation)0
+4168 y(504)95 b(unsupported)44 b(type)j(of)g(celestial)e(projection)0
+4281 y(505)95 b(required)45 b(celestial)g(coordinate)g(keywords)h(not)h
+(found)0 4394 y(506)95 b(approximate)44 b(wcs)j(keyword)f(values)g
+(were)h(returned)p eop end
+%%Trailer
+
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/vendor/cfitsio/fitsio.tex b/vendor/cfitsio/fitsio.tex
new file mode 100644
index 00000000..b0255587
--- /dev/null
+++ b/vendor/cfitsio/fitsio.tex
@@ -0,0 +1,7688 @@
+\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 3.0\\}
+\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 May 2011\\}
+\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: William.D.Pence@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]
+ [--enable-sse2] [--enable-ssse3]
+ > 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 optional --enable-sse2 and --enable-ssse3 flags will cause configure to
+attempt to build CFITSIO using faster byte-swapping algorithms.
+See the "Optimizing Programs" section of this manual for
+more information about these options.
+
+By default, the Makefile will be configured to build 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 statically 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\_3xxx\_vcc.zip, where
+'3xxx' 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
+boundaries 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.
+
+On Windows platforms, linking Fortran programs with a C library
+often depends on the particular compilers involved. Some users have
+found the following commands work when using the Intel Fortran compiler:
+
+\begin{verbatim}
+ifort /libs.dll cfitsio.lib /MD testf77.f /Gm
+
+or possibly,
+
+ifort /libs:dll cfitsio.lib /MD /fpp /extfpp:cfortran.h,fitsio.h
+ /iface:cvf testf77.f
+\end{verbatim}
+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 performs 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
+necessary 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.
+
+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."
+
+
+\section{Acknowledgments}
+
+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.
+
+Martin Reinecke (Max Planck Institute, Garching)) provided the modifications to
+cfortran.h that are necessary to support 64-bit integer values when calling
+C routines from fortran programs. The cfortran.h macros were originally developed
+by Burkhard Burow (CERN).
+
+Julian Taylor (ESO, Garching) provided the fast byte-swapping algorithms
+that use the SSE2 and SSSE3 machine instructions available on x86\_64 CPUs.
+
+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. Six different primary
+datatypes are supported: Unsigned 8-bit bytes, 16, 32, and 64-bit signed
+integers, and 32 and 64-bit floating point reals. FITS also has a
+convention for storing 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, 64, -32, -64 for
+unsigned 8--bit byte, 16--bit signed integer, 32--bit signed integer,
+64--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 further information about the FITS format and related software
+packages.
+
+
+
+\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.
+
+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, 32-bit integer)
+ k - long long integer (I*8, 64-bit integer)
+ 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)' or `1Qt(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. This is also not
+supported when reading floating-point images that have been compressed
+with the FITS tiled image compression convention that is discussed in
+section 5.6; the pixels values in tile compressed images are
+represented by scaled integers, and a reserved integer value
+(not a NaN) is used to represent undefined pixels.
+
+
+
+\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}
+
+CFITSIO supports 2 ways to specify that a character column in a binary
+table contains an array of fixed-length strings. The first way, which
+is officially supported by the FITS Standard document, uses the TDIMn keyword.
+For example, if TFORMn = '60A' and TDIMn = '(12,5)' then that
+column will be interpreted as containing an array of 5 strings, each 12
+characters long.
+
+FITSIO also supports 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.
+
+
+\subsection{Optimization Strategies}
+
+1. Because the data in FITS files is always stored in "big-endian" byte order,
+where the first byte of numeric values contains the most significant bits and the
+last byte contains the least significant bits, CFITSIO must swap the order of the bytes
+when reading or writing FITS files when running on little-endian machines (e.g.,
+Linux and Microsoft Windows operating systems running on PCs with x86 CPUs).
+
+On fairly new CPUs that support "SSSE3" machine instructions
+(e.g., starting with Intel Core 2 CPUs in 2007, and in AMD CPUs
+beginning in 2011) significantly faster 4-byte and 8-byte swapping
+algorithms are available. These faster byte swapping functions are
+not used by default in CFITSIO (because of the potential code
+portablility issues), but users can enable them on supported
+platforms by adding the appropriate compiler flags (-mssse3 with gcc
+or icc on linux) when compiling the swapproc.c source file, which will
+allow the compiler to generate code using the SSSE3 instruction set.
+A convenient way to do this is to configure the CFITSIO library
+with the following command:
+
+\begin{verbatim}
+ > ./configure --enable-ssse3
+\end{verbatim}
+Note, however, that a binary executable file that is
+created using these faster functions will only run on
+machines that support the SSSE3 machine instructions. It will
+crash on machines that do not support them.
+
+For faster 2-byte swaps on virtually all x86-64 CPUs (even those that
+do not support SSSE3), a variant using only SSE2 instructions exists.
+SSE2 is enabled by default on x86\_64 CPUs with 64-bit operating systems
+(and is also automatically enabled by the --enable-ssse3 flag).
+When running on x86\_64 CPUs with 32-bit operating systems, these faster
+2-byte swapping algorithms are not used by default in CFITSIO, but can be
+enabled explicitly with:
+
+\begin{verbatim}
+./configure --enable-sse2
+\end{verbatim}
+Preliminary testing indicates that these SSSE3 and SSE2 based
+byte-swapping algorithms can boost the CFITSIO performance when
+reading or writing FITS images by 20\% - 30\% or more.
+It is important to note, however, that compiler optimization must be
+turned on (e.g., by using the -O1 or -O2 flags in gcc) when building
+programs that use these fast byte-swapping algorithms in order
+to reap the full benefit of the SSSE3 and SSE2 instructions; without
+optimization, the code may actually run slower than when using
+more traditional byte-swapping techniques.
+
+2. 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.
+
+3. 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
+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.
+
+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,
+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.
+
+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 ftpscl or
+fttscl) and then read or write the raw unscaled values in the FITS
+file.
+
+7. 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.
+
+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. In practice, this is probably not a significant efficiency issue.
+
+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 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.
+
+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
+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?).
+
+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.
+
+
+
+\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 FTDKOPEN 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 FTDKINIT 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 existing primary array will be
+ converted to an IMAGE extension. The new extension (or primary
+ array) will become the CHDU. The FTIIMGLL routine is identical
+ to the FTIIMG routine except that the 4th parameter (the length
+ of each axis) is an array of 64-bit integers rather than an array
+ of 32-bit integers.
+\end{description}
+
+\begin{verbatim}
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+ FTIIMGLL(unit,bitpix,naxis,naxesll, > 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. The FTITABLL
+ routine is identical
+ to the FTITAB routine except that the 2nd and 3rd parameters (that give
+ the size of the table) are 64-bit integers rather than
+ 32-bit integers. Under normal circumstances, the nrows and nrowsll
+ paramenters should have a value of 0; CFITSIO will automatically update
+ the number of rows as data is written to the table.
+\end{description}
+
+\begin{verbatim}
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+ FTITABLL(unit,rowlenll,nrowsll,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. The FTIBINLL
+ routine is identical
+ to the FTIBIN routine except that the 2nd parameter (that gives
+ the length of the table) is a 64-bit integer rather than
+ a 32-bit integer. Under normal circumstances, the nrows and nrowsll
+ paramenters should have a value of 0; CFITSIO will automatically update
+ the number of rows as data is written to the table.
+\end{description}
+
+\begin{verbatim}
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+ FTIBINLL(unit,nrowsll,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[JKLS](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[EDJKLS](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[BIJKED](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[BIJKED](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[SLBIJKEDCM](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[SBIJKEDCM](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. The
+FTDKOPEN routine simply opens the specified file without trying to
+interpret the filename using the extended filename syntax. FTDOPN opens
+the file and
+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)
+ FTDKOPEN(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.
+ The FTDKINIT 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 ] 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 (0), ASCII\_TBL (1), BINARY\_TBL (2), or ANY\_HDU (-1)
+ 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 ] 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 existing primary array will be
+ converted to an IMAGE extension. The new extension (or primary
+ array) will become the CHDU. The FTIIMGLL routine is identical
+ to the FTIIMG routine except that the 4th parameter (the length
+ of each axis) is an array of 64-bit integers rather than an array
+ of 32-bit integers.
+\end{description}
+
+\begin{verbatim}
+ FTIIMG(unit,bitpix,naxis,naxes, > status)
+ FTIIMGLL(unit,bitpix,naxis,naxesll, > 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. The FTITABLL
+ routine is identical
+ to the FTITAB routine except that the 2nd and 3rd parameters (that give
+ the size of the table) are 64-bit integers rather than
+ 32-bit integers.
+\end{description}
+
+\begin{verbatim}
+ FTITAB(unit,rowlen,nrows,tfields,ttype,tbcol,tform,tunit,extname, >
+ status)
+ FTITABLL(unit,rowlenll,nrowsll,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. The FTIBINLL
+ routine is identical
+ to the FTIBIN routine except that the 2nd parameter (that gives
+ the length of the table) is a 64-bit integer rather than
+ a 32-bit integer.
+\end{description}
+
+\begin{verbatim}
+ FTIBIN(unit,nrows,tfields,ttype,tform,tunit,extname,varidat > status)
+ FTIBINLL(unit,nrowsll,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. The FTRSIMLL routine is identical
+ to the FTRSIM routine except that the 4th parameter (the length
+ of each axis) is an array of 64-bit integers rather than an array
+ of 32-bit integers.
+\end{description}
+
+\begin{verbatim}
+ FTRSIM(unit,bitpix,naxis,naxes,status)
+ FTRSIMLL(unit,bitpix,naxis,naxesll,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' (an integer parameter) is
+ not equal to 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 not equal
+ to zero, 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[JKLS](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[JKLS](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}
+ FTCPKY(inunit, 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[JKLS](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[EDJKLS](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[EDJKLS](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[JKLS](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[JKLS](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,
+ 32. or 64 This does not create or change the value of the BLANK keyword in
+ the header. FTPNULLL is identical to FTPNUL except that the blank
+ value is a 64-bit integer instead of a 32-bit integer.
+\end{description}
+
+\begin{verbatim}
+ FTPNUL(unit,blank, > status)
+ FTPNULLL(unit,blankll, > 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', 'J', or 'K').
+ This does not create or change the value of the TNULLn keyword.
+ FTTNULLL is identical to FTTNUL except that the tnull
+ value is a 64-bit integer instead of a 32-bit integer.
+\end{description}
+
+\begin{verbatim}
+ FTTNUL(unit,colnum,tnull > status)
+ FTTNULLL(unit,colnum,tnullll > 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, 64, -32, or -64 corresponding to unsigned byte,
+ signed 2-byte integer, signed 4-byte integer, signed 8-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. The FTGISZLL
+ routine returns an array of 64-bit integers instead of 32-bit integers.
+\end{description}
+
+\begin{verbatim}
+ FTGISZ(unit, maxdim, > naxes,status)
+ FTGISZLL(unit, maxdim, > naxesll,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. The FTGIPRLL
+ routine returns an array of 64-bit integers instead of 32-bit integers.
+\end{description}
+
+
+\begin{verbatim}
+ FTGIPR(unit, maxdim, > bitpix, naxis, naxes, int *status)
+ FTGIPRLL(unit, maxdim, > bitpix, naxis, naxesll, int *status)
+\end{verbatim}
+
+\begin{description}
+\item[5 ]Put elements into the data array
+\end{description}
+
+\begin{verbatim}
+ FTPPR[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](unit,group,fpixel,nelements, > values,flagvals,anyf,status)
+\end{verbatim}
+
+\begin{description}
+\item[10] Put values into group parameters
+\end{description}
+
+\begin{verbatim}
+ FTPGP[BIJKED](unit,group,fparm,nparm,values, > status)
+\end{verbatim}
+
+\begin{description}
+\item[11] Get values from group parameters
+\end{description}
+
+\begin{verbatim}
+ FTGGP[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](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[BIJKED](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. The FTGNRWLL routine is identical to FTGNRW except
+ that the number of rows is returned as a 64-bit integer rather
+ than a 32-bit integer.
+\end{description}
+
+\begin{verbatim}
+ FTGNRW(unit, > nrows, status)
+ FTGNRWLL(unit, > nrowsll, 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.
+\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 TDIMn
+ keyword may also be used to specify the unit string length; The pair
+ of keywords TFORMn = '60A' and TDIMn = '(12,5)' would have the
+ same effect as TFORMn = '60A12').
+
+ 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 multidimensional 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 or FROWLL equals 0 then the blank rows are inserted at the beginning of the
+ table. These routines modify the NAXIS2 keyword to reflect the new
+ number of rows in the table. Note that it is *not* necessary to insert rows in a table before
+ writing data to those rows (indeed, it would be inefficient to do so).
+ Instead, one may simply write data to any row of the table, whether that
+ row of data already exists or not.
+\end{description}
+
+\begin{verbatim}
+ FTIROW(unit,frow,nrows, > status)
+ FTIROWLL(unit,frowll,nrowsll, > status)
+\end{verbatim}
+
+\begin{description}
+\item[2 ] Delete rows from an existing ASCII or binary table (in the CDU).
+ The NROWS (or NROWSLL) is the number of rows are deleted, starting
+ with row FROW (or FROWLL), and
+ any remaining rows in the table are shifted up to fill in the space.
+ These routines modify the NAXIS2 keyword to reflect the new number
+ of rows in the table.
+\end{description}
+
+\begin{verbatim}
+ FTDROW(unit,frow,nrows, > status)
+ FTDROWLL(unit,frowll,nrowsll, > 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.
+Note that it is *not* necessary to insert rows in a table before
+writing data to those rows (indeed, it would be inefficient to do so).
+Instead, one may simply write data to any row of the table, whether that
+row of data already exists or not.
+
+ 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).
+
+ The alternate version of these routines, whose names end in 'LL'
+ after the datatype character, support large tables with more then
+ 2*31 rows. When calling these routines, the frow and felem parameters
+ *must* be 64-bit integer*8 variables, instead of normal 4-byte integers.
+\end{description}
+
+\begin{verbatim}
+ FTPCL[SLBIJKEDCM](unit,colnum,frow,felem,nelements,values, > status)
+ FTPCL[LBIJKEDCM]LL(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. 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.
+
+ The alternate version of these routines, whose names end in 'LL'
+ after the datatype character, support large tables with more then
+ 2*31 rows. When calling these routines, the frow and felem parameters
+ *must* be 64-bit integer*8 variables, instead of normal 4-byte integers.
+\end{description}
+
+\begin{verbatim}
+ FTPCN[SBIJKED](unit,colnum,frow,felem,nelements,values,nullval > status)
+ FTPCN[SBIJKED]LL(unit,colnum,(I*8) frow,(I*8) 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).
+
+ The alternate version of these routines, whose names end in 'LL'
+ after the datatype character, support large tables with more then
+ 2*31 rows. When calling these routines, the frow and felem parameters
+ *must* be 64-bit integer*8 variables, instead of normal 4-byte integers.
+\end{description}
+
+\begin{verbatim}
+ FTGCL(unit,colnum,frow,felem,nelements, > values,status)
+ FTGCV[SBIJKEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+ FTGCV[BIJKEDCM]LL(unit,colnum,(I*8) frow, (I*8) 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).
+
+ The alternate version of these routines, whose names end in 'LL'
+ after the datatype character, support large tables with more then
+ 2*31 rows. When calling these routines, the frow and felem parameters
+ *must* be 64-bit integer*8 variables, instead of normal 4-byte integers.
+\end{description}
+
+\begin{verbatim}
+ FTGCF[SLBIJKEDCM](unit,colnum,frow,felem,nelements, >
+ values,flagvals,anyf,status)
+ FTGCF[BIJKED]LL(unit,colnum, (I*8) frow, (I*8) 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[BIJKED](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[BIJKED](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)
+ FTGDESLL(unit,colnum,rownum, > nelementsll,offsetll,status)
+
+ FFGDESS(unit,colnum,firstrow,nrows > nelements,offset, status)
+ FFGDESSLL(unit,colnum,firstrow,nrows > nelementsll,offsetll, status)
+\end{verbatim}
+
+\begin{description}
+\item[12] Write the descriptor for a variable length column in a binary table.
+ These subroutines 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)
+ FTPDESLL(unit,colnum,rownum,nelementsll,offsetll, > 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 output
+table is not empty, then this routine will append the new
+selected rows after the existing rows. 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 dimension and type information
+on the result. The returned dimensions correspond to a single row entry
+of the requested expression, and are equivalent to the result of fits\_read\_tdim().
+Note that strings are considered to be one element regardless of string length.
+If maxdim == 0, then naxes is optional.
+\end{description}
+
+\begin{verbatim}
+ FTTEXP(unit, expr, maxdim > 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 external 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. The '\#' character will match any consecutive string
+ of decimal digits (0 - 9). 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, staThe '\#' character will match any consecutive string
+ of decimal digits (0 - 9). tus)
+\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.
+ If the value token is a character string that contains 1 or more
+ embedded blank space characters or slash ('/') characters then the
+ entire character string must be enclosed in single quotes.
+\end{description}
+
+
+\begin{description}
+\item[- ] The COMMENT token is optional, but if present must be separated from
+ the VALUE token by a blank space or a '/' character.
+\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{ 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 repeatedly 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{ 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
+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 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
+ supports username:password just like the ftp driver.
+ Proxy HTTP servers are supported using the http_proxy
+ environment variable (see following note).
+ stream:// - special driver to read an input FITS file from the stdin
+ stream, and/or write an output FITS file to the stdout
+ stream. This driver is fragile and has limited
+ functionality (see the following note).
+ gsiftp:// - access files on a computational grid using the gridftp
+ protocol in the Globus toolkit (see following note).
+ 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 stream filetype driver}
+
+The stream driver can be used to efficiently read a FITS file from the stdin
+file stream or write a FITS to the stdout file stream. However, because these
+input and output streams must be accessed sequentially, the FITS file reading or
+writing application must also read and write the file sequentially, at least
+within the tolerances described below.
+
+CFITSIO supports 2 different methods for accessing FITS files on the stdin and
+stdout streams. The original method, which is invoked by specifying a dash
+character, "-", as the name of the file when opening or creating it, works by
+storing a complete copy of the entire FITS file in memory. In this case, when
+reading from stdin, CFITSIO will copy the entire stream into memory before doing
+any processing of the file. Similarly, when writing to stdout, CFITSIO will
+create a copy of the entire FITS file in memory, before finally flushing it out
+to the stdout stream when the FITS file is closed. Buffering the entire FITS
+file in this way allows the application to randomly access any part of the FITS
+file, in any order, but it also requires that the user have sufficient available
+memory (or virtual memory) to store the entire file, which may not be possible
+in the case of very large files.
+
+The newer stream filetype provides a more memory-efficient method of accessing
+FITS files on the stdin or stdout streams. Instead of storing a copy of the
+entire FITS file in memory, CFITSIO only uses a set of internal buffer which by
+default can store 40 FITS blocks, or about 100K bytes of the FITS file. The
+application program must process the FITS file sequentially from beginning to
+end, within this 100K buffer. Generally speaking the application program must
+conform to the following restrictions:
+
+\begin{itemize}
+\item
+The program must finish reading or writing the header keywords
+before reading or writing any data in the HDU.
+\item
+The HDU can contain at most about 1400 header keywords. This is the
+maximum that can fit in the nominal 40 FITS block buffer. In principle,
+this limit could be increased by recompiling CFITSIO with a larger
+buffer limit, which is set by the NIOBUF parameter in fitsio2.h.
+\item
+The program must read or write the data in a sequential manner from the
+beginning to the end of the HDU. Note that CFITSIO's internal
+100K buffer allows a little latitude in meeting this requirement.
+\item
+The program cannot move back to a previous HDU in the FITS file.
+\item
+Reading or writing of variable length array columns in binary tables is not
+supported on streams, because this requires moving back and forth between the
+fixed-length portion of the binary table and the following heap area where the
+arrays are actually stored.
+\item
+Reading or writing of tile-compressed images is not supported on streams,
+because the images are internally stored using variable length arrays.
+\end{itemize}
+
+
+\subsection{Notes about the gsiftp filetype}
+
+DEPENDENCIES: Globus toolkit (2.4.3 or higher) (GT) should be installed.
+There are two different ways to install GT:
+
+1) goto the globus toolkit web page www.globus.org and follow the
+ download and compilation instructions;
+
+2) goto the Virtual Data Toolkit web page http://vdt.cs.wisc.edu/
+ and follow the instructions (STRONGLY SUGGESTED);
+
+Once a globus client has been installed in your system with a specific flavour
+it is possible to compile and install the CFITSIO libraries.
+Specific configuration flags must be used:
+
+1) --with-gsiftp[[=PATH]] Enable Globus Toolkit gsiftp protocol support
+ PATH=GLOBUS\_LOCATION i.e. the location of your globus installation
+
+2) --with-gsiftp-flavour[[=PATH] defines the specific Globus flavour
+ ex. gcc32
+
+Both the flags must be used and it is mandatory to set both the PATH and the
+flavour.
+
+USAGE: To access files on a gridftp server it is necessary to use a gsiftp prefix:
+
+example: gsiftp://remote\_server\_fqhn/directory/filename
+
+The gridftp driver uses a local buffer on a temporary file the file is located
+in the /tmp directory. If you have special permissions on /tmp or you do not have a /tmp
+directory, it is possible to force another location setting the GSIFTP\_TMPFILE environment
+variable (ex. export GSIFTP\_TMPFILE=/your/location/yourtmpfile).
+
+Grid FTP supports multi channel transfer. By default a single channel transmission is
+available. However, it is possible to modify this behavior setting the GSIFTP\_STREAMS
+environment variable (ex. export GSIFTP\_STREAMS=8).
+
+
+\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 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 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{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{Image Transform Filters}
+
+CFITSIO can apply a user-specified mathematical function to the value
+of every pixel in a FITS image, thus creating a new virtual image
+in computer memory that is then opened and read by the application
+program. The original FITS image is not modified by this process.
+
+The image transformation specifier is appended to the input
+FITS file name and is enclosed in square brackets. It begins with the
+letters 'PIX' to distinguish it from other types of FITS file filters
+that are recognized by CFITSIO. The image transforming function may
+use any of the mathematical operators listed in the following
+'Row Filtering Specification' section of this document.
+Some examples of image transform filters are:
+
+\begin{verbatim}
+ [pix X * 2.0] - multiply each pixel by 2.0
+ [pix sqrt(X)] - take the square root of each pixel
+ [pix X + #ZEROPT - add the value of the ZEROPT keyword
+ [pix X>0 ? log10(X) : -99.] - if the pixel value is greater
+ than 0, compute the base 10 log,
+ else set the pixel = -99.
+\end{verbatim}
+Use the letter 'X' in the expression to represent the current pixel value
+in the image. The expression is evaluated
+independently for each pixel in the image and may be a function of 1) the
+original pixel value, 2) the value of other pixels in the image at
+a given relative offset from the position of the pixel that is being
+evaluated, and 3) the value of
+any header keywords. Header keyword values are represented
+by the name of the keyword preceded by the '\#' sign.
+
+
+To access the the value of adjacent pixels in the image,
+specify the (1-D) offset from the current pixel in curly brackets.
+For example
+
+\begin{verbatim}
+ [pix (x{-1} + x + x{+1}) / 3]
+\end{verbatim}
+will replace each pixel value with the running mean of the values of that
+pixel and it's 2 neighboring pixels. Note that in this notation the image
+is treated as a 1-D array, where each row of the image (or higher dimensional
+cube) is appended one after another in one long array of pixels.
+It is possible to refer to pixels
+in the rows above or below the current pixel by using the value of the
+NAXIS1 header keyword. For example
+
+\begin{verbatim}
+ [pix (x{-#NAXIS1} + x + x{#NAXIS1}) / 3]
+\end{verbatim}
+will compute the mean of each image pixel and the pixels immediately
+above and below it in the adjacent rows of the image.
+The following more complex example
+creates a smoothed virtual image where each pixel
+is a 3 x 3 boxcar average of the input image pixels:
+
+\begin{verbatim}
+ [pix (X + X{-1} + X{+1}
+ + X{-#NAXIS1} + X{-#NAXIS1 - 1} + X{-#NAXIS1 + 1}
+ + X{#NAXIS1} + X{#NAXIS1 - 1} + X{#NAXIS1 + 1}) / 9.]
+\end{verbatim}
+If the pixel offset
+extends beyond the first or last pixel in the image, the function will
+evaluate to undefined, or NULL.
+
+For complex or commonly used image filtering operations,
+one can write the expression into an external text file and
+then import it into the
+filter using the syntax '[pix @filename.txt]'. The mathematical
+expression can
+extend over multiple lines of text in 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.
+
+By default, the datatype of the resulting image will be the same as
+the original image, but one may force a different datatype by appended
+a code letter to the 'pix' keyword:
+
+\begin{verbatim}
+ pixb - 8-bit byte image with BITPIX = 8
+ pixi - 16-bit integer image with BITPIX = 16
+ pixj - 32-bit integer image with BITPIX = 32
+ pixr - 32-bit float image with BITPIX = -32
+ pixd - 64-bit float image with BITPIX = -64
+\end{verbatim}
+Also by default, any other HDUs in the input file will be copied without
+change to the
+output virtual FITS file, but one may discard the other HDUs by adding
+the number '1' to the 'pix' keyword (and following any optional datatype code
+letter). For example:
+
+\begin{verbatim}
+ myfile.fits[3][pixr1 sqrt(X)]
+\end{verbatim}
+will create a virtual FITS file containing only a primary array image
+with 32-bit floating point pixels that have a value equal to the square
+root of the pixels in the image that is in the 3rd extension
+of the 'myfile.fits' file.
+
+
+
+
+\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 commas or 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). If the keyword name ends with a
+pound sign '\#', then cfitsio will substitute the number of the
+most recently referenced column for the \# character .
+This is especially useful when writing
+a column-related keyword like TUNITn for a newly created column,
+as shown in the following examples.
+
+\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. If no columns to be deleted are specified, then only the
+columns that are explicitly listed will be included in the filtered
+output table. To include all the columns, add the '*' wildcard
+specifier at the end of the list, as shown in the examples.
+
+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; #TUNIT#(column units) = 'counts';*]
+ - creates new PI column from PHA values
+ and also writes the TUNITn keyword
+ for the new column. The final '*'
+ expression means preserve all the
+ columns in the input table in the
+ virtual output table; without the '*'
+ the output table would only contain
+ the single 'PI' column.
+
+ [col rate = rate/exposure; TUNIT#(&) = 'counts/s';*]
+ - recomputes the rate column by dividing
+ it by the EXPOSURE keyword value. This
+ also modifies the value of the TUNITn
+ keyword for this column. The use of the
+ '&' character for the keyword comment
+ string means preserve the existing
+ comment string for that keyword. The
+ final '*' preserves all the columns
+ in the input table in the virtual
+ output table.
+\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 enclose 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(y,x)
+ "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" x % y "random # [0.0,1.0)" random()
+ "random Gaussian" randomn() "random Poisson" randomp(x)
+ "minimum" min(x,y) "maximum" max(x,y)
+ "cumulative sum" accum(x) "sequential difference" seqdiff(x)
+ "if-then-else" b?x:y
+ "angular separation" angsep(ra1,dec1,ra2,de2) (all in degrees)
+ "substring" strmid(s,p,n) "string search" strstr(s,r)
+\end{verbatim}
+Three different random number functions are provided: random(), with no
+arguments, produces a uniform random deviate between 0 and 1; randomn(),
+also with no arguments, produces a normal (Gaussian) random deviate with
+zero mean and unit standard deviation; randomp(x) produces a Poisson random
+deviate whose expected number of counts is X. X may be any positive real
+number of expected counts, including fractional values, but the return value
+is an integer.
+
+When the random functions are used in a vector expression, by default
+the same random value will be used when evaluating each element of the vector.
+If different random numbers are desired, then the name of a vector
+column should be supplied as the single argument to the random
+function (e.g., "flux + 0.1 * random(flux)", where "flux' is the
+name of a vector column). This will create a vector of
+random numbers that will be used in sequence when evaluating each
+element of the vector expression.
+
+ 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.
+
+In the if-then-else expression, "b?x:y", b is an explicit boolean
+value or expression. There is no automatic type conversion from
+numeric to boolean values, so one needs to use "iVal!=0" instead of
+merely "iVal" as the boolean argument. x and y can be any scalar data
+type (including string).
+
+ The angsep function computes the angular separation in degrees
+ between 2 celestial positions, where the first 2 parameters
+ give the RA-like and Dec-like coordinates (in decimal degrees)
+ of the first position, and the 3rd and 4th parameters give the
+ coordinates of the second position.
+
+The substring function strmid(S,P,N) extracts a substring from S,
+starting at string position P, with a substring length N. The first
+character position in S is labeled as 1. If P is 0, or refers to a
+position beyond the end of S, then the extracted substring will be
+NULL. S, P, and N may be functions of other columns.
+
+The string search function strstr(S,R) searches for the first occurrence
+of the substring R in S. The result is an integer, indicating the
+character position of the first match (where 1 is the first character
+position of S). If no match is found, then strstr() returns a NULL
+value.
+
+ The following type casting operators are available, where the
+ enclosing 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)
+ "summation" 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 STDDEV() function computes the sample
+ standard deviation, i.e. it is proportional to 1/SQRT(N-1) instead
+ of 1/SQRT(N), where N is NVALID(V).
+
+ 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. There are 2 supported formats for the
+ region file: ASCII file or FITS binary table. The region file
+ 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. The FITS region file format is defined in a document
+ available from the FITS Support Office at
+ http://fits.gsfc.nasa.gov/ registry/ region.html
+
+ In its simplest 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 semi-major/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{ 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[JKLS](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[JKLS](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[JKLS](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[EDJKLS](unit,keyword, > keyval,comment,status)
+ FTGKN[EDJKLS](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[JKLS](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[JKLS](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[BIJKED](unit,group,fpixel,nelements,values, > status)
+ FTPPN[BIJKED](unit,group,fpixel,nelements,values,nullval > status)
+ FTPPRU(unit,group,fpixel,nelements, > status)
+ FTGPV[BIJKED](unit,group,fpixel,nelements,nullval, > values,anyf,status)
+ FTGPF[BIJKED](unit,group,fpixel,nelements, > values,flagvals,anyf,status)
+ FTPGP[BIJKED](unit,group,fparm,nparm,values, > status)
+ FTGGP[BIJKED](unit,group,fparm,nparm, > values,status)
+ FTP2D[BIJKED](unit,group,dim1,naxis1,naxis2,image, > status)
+ FTP3D[BIJKED](unit,group,dim1,dim2,naxis1,naxis2,naxis3,cube, > status)
+ FTG2D[BIJKED](unit,group,nullval,dim1,naxis1,naxis2, > image,anyf,status)
+ FTG3D[BIJKED](unit,group,nullval,dim1,dim2,naxis1,naxis2,naxis3, >
+ cube,anyf,status)
+ FTPSS[BIJKED](unit,group,naxis,naxes,fpixels,lpixels,array, > status)
+ FTGSV[BIJKED](unit,group,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+ FTGSF[BIJKED](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[SLBIJKEDCM](unit,colnum,frow,felem,nelements,values, > status)
+ FTPCN[BIJKED](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[SBIJKEDCM](unit,colnum,frow,felem,nelements,nullval, >
+ values,anyf,status)
+ FTGCF[SLBIJKEDCM](unit,colnum,frow,felem,nelements, >
+ values,flagvals,anyf,status)
+ FTGSV[BIJKED](unit,colnum,naxis,naxes,fpixels,lpixels,incs,nullval, >
+ array,anyf,status)
+ FTGSF[BIJKED](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
+blank - (integer*8) 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
+current - (integer) if not equal to 0, copy the current HDU
+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
+following - (integer) if not equal to 0, copy all following HDUs in the input file
+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)
+frowll - (integer*8) 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 = any HDU type or unknown type
+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
+naxesll - (integer*8 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
+nelementsll - (integer*8) 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
+nrowsll - (integer*8) 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
+offsetll - (integer*8) 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)
+previous - (integer) if not equal to 0, copy all previous HDUs in the input file
+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
+rowlenll - (integer*8) 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
+tnullll - (integer*8) 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
+206 illegal indexed keyword name (e.g. 'TFORM1000')
+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/vendor/cfitsio/fitsio.toc b/vendor/cfitsio/fitsio.toc
new file mode 100644
index 00000000..c9b4f7c4
--- /dev/null
+++ b/vendor/cfitsio/fitsio.toc
@@ -0,0 +1,95 @@
+\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}{8}
+\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}{10}
+\contentsline {section}{\numberline {2.7}Acknowledgments}{10}
+\contentsline {chapter}{\numberline {3} A FITS Primer }{13}
+\contentsline {chapter}{\numberline {4}FITSIO Conventions and Guidelines }{15}
+\contentsline {section}{\numberline {4.1}CFITSIO Size Limitations}{15}
+\contentsline {section}{\numberline {4.2}Multiple Access to the Same FITS File}{16}
+\contentsline {section}{\numberline {4.3}Current Header Data Unit (CHDU)}{16}
+\contentsline {section}{\numberline {4.4}Subroutine Names}{16}
+\contentsline {section}{\numberline {4.5}Subroutine Families and Datatypes}{17}
+\contentsline {section}{\numberline {4.6}Implicit Data Type Conversion}{17}
+\contentsline {section}{\numberline {4.7}Data Scaling}{18}
+\contentsline {section}{\numberline {4.8}Error Status Values and the Error Message Stack}{18}
+\contentsline {section}{\numberline {4.9}Variable-Length Array Facility in Binary Tables}{19}
+\contentsline {section}{\numberline {4.10}Support for IEEE Special Values}{20}
+\contentsline {section}{\numberline {4.11}When the Final Size of the FITS HDU is Unknown}{21}
+\contentsline {section}{\numberline {4.12}Local FITS Conventions supported by FITSIO}{21}
+\contentsline {subsection}{\numberline {4.12.1}Support for Long String Keyword Values.}{21}
+\contentsline {subsection}{\numberline {4.12.2}Arrays of Fixed-Length Strings in Binary Tables}{22}
+\contentsline {subsection}{\numberline {4.12.3}Keyword Units Strings}{23}
+\contentsline {subsection}{\numberline {4.12.4}HIERARCH Convention for Extended Keyword Names}{23}
+\contentsline {section}{\numberline {4.13}Optimizing Code for Maximum Processing Speed}{24}
+\contentsline {subsection}{\numberline {4.13.1}Background Information: How CFITSIO Manages Data I/O}{25}
+\contentsline {subsection}{\numberline {4.13.2}Optimization Strategies}{25}
+\contentsline {chapter}{\numberline {5} Basic Interface Routines }{29}
+\contentsline {section}{\numberline {5.1}FITSIO Error Status Routines }{29}
+\contentsline {section}{\numberline {5.2}File I/O Routines}{30}
+\contentsline {section}{\numberline {5.3}Keyword I/O Routines}{32}
+\contentsline {section}{\numberline {5.4}Data I/O Routines}{33}
+\contentsline {chapter}{\numberline {6} Advanced Interface Subroutines }{35}
+\contentsline {section}{\numberline {6.1}FITS File Open and Close Subroutines: }{35}
+\contentsline {section}{\numberline {6.2}HDU-Level Operations }{38}
+\contentsline {section}{\numberline {6.3}Define or Redefine the structure of the CHDU }{41}
+\contentsline {section}{\numberline {6.4}FITS Header I/O Subroutines}{43}
+\contentsline {subsection}{\numberline {6.4.1}Header Space and Position Routines }{43}
+\contentsline {subsection}{\numberline {6.4.2}Read or Write Standard Header Routines }{43}
+\contentsline {subsection}{\numberline {6.4.3}Write Keyword Subroutines }{45}
+\contentsline {subsection}{\numberline {6.4.4}Insert Keyword Subroutines }{47}
+\contentsline {subsection}{\numberline {6.4.5}Read Keyword Subroutines }{47}
+\contentsline {subsection}{\numberline {6.4.6}Modify Keyword Subroutines }{49}
+\contentsline {subsection}{\numberline {6.4.7}Update Keyword Subroutines }{50}
+\contentsline {subsection}{\numberline {6.4.8}Delete Keyword Subroutines }{50}
+\contentsline {section}{\numberline {6.5}Data Scaling and Undefined Pixel Parameters }{51}
+\contentsline {section}{\numberline {6.6}FITS Primary Array or IMAGE Extension I/O Subroutines }{52}
+\contentsline {section}{\numberline {6.7}FITS ASCII and Binary Table Data I/O Subroutines}{55}
+\contentsline {subsection}{\numberline {6.7.1}Column Information Subroutines }{55}
+\contentsline {subsection}{\numberline {6.7.2}Low-Level Table Access Subroutines }{58}
+\contentsline {subsection}{\numberline {6.7.3}Edit Rows or Columns }{58}
+\contentsline {subsection}{\numberline {6.7.4}Read and Write Column Data Routines }{60}
+\contentsline {section}{\numberline {6.8}Row Selection and Calculator Routines }{64}
+\contentsline {section}{\numberline {6.9}Celestial Coordinate System Subroutines }{65}
+\contentsline {section}{\numberline {6.10}File Checksum Subroutines }{67}
+\contentsline {section}{\numberline {6.11} Date and Time Utility Routines }{68}
+\contentsline {section}{\numberline {6.12}General Utility Subroutines }{69}
+\contentsline {chapter}{\numberline {7} The CFITSIO Iterator Function }{75}
+\contentsline {chapter}{\numberline {8} Extended File Name Syntax }{77}
+\contentsline {section}{\numberline {8.1}Overview}{77}
+\contentsline {section}{\numberline {8.2}Filetype}{80}
+\contentsline {subsection}{\numberline {8.2.1}Notes about HTTP proxy servers}{80}
+\contentsline {subsection}{\numberline {8.2.2}Notes about the stream filetype driver}{81}
+\contentsline {subsection}{\numberline {8.2.3}Notes about the gsiftp filetype}{82}
+\contentsline {subsection}{\numberline {8.2.4}Notes about the root filetype}{82}
+\contentsline {subsection}{\numberline {8.2.5}Notes about the shmem filetype:}{84}
+\contentsline {section}{\numberline {8.3}Base Filename}{84}
+\contentsline {section}{\numberline {8.4}Output File Name when Opening an Existing File}{86}
+\contentsline {section}{\numberline {8.5}Template File Name when Creating a New File}{88}
+\contentsline {section}{\numberline {8.6}Image Tile-Compression Specification}{88}
+\contentsline {section}{\numberline {8.7}HDU Location Specification}{88}
+\contentsline {section}{\numberline {8.8}Image Section}{89}
+\contentsline {section}{\numberline {8.9}Image Transform Filters}{90}
+\contentsline {section}{\numberline {8.10}Column and Keyword Filtering Specification}{92}
+\contentsline {section}{\numberline {8.11}Row Filtering Specification}{94}
+\contentsline {subsection}{\numberline {8.11.1}General Syntax}{94}
+\contentsline {subsection}{\numberline {8.11.2}Bit Masks}{97}
+\contentsline {subsection}{\numberline {8.11.3}Vector Columns}{98}
+\contentsline {subsection}{\numberline {8.11.4}Good Time Interval Filtering}{99}
+\contentsline {subsection}{\numberline {8.11.5}Spatial Region Filtering}{100}
+\contentsline {subsection}{\numberline {8.11.6}Example Row Filters}{103}
+\contentsline {section}{\numberline {8.12} Binning or Histogramming Specification}{104}
+\contentsline {chapter}{\numberline {9}Template Files }{107}
+\contentsline {section}{\numberline {9.1}Detailed Template Line Format}{107}
+\contentsline {section}{\numberline {9.2}Auto-indexing of Keywords}{108}
+\contentsline {section}{\numberline {9.3}Template Parser Directives}{109}
+\contentsline {section}{\numberline {9.4}Formal Template Syntax}{109}
+\contentsline {section}{\numberline {9.5}Errors}{110}
+\contentsline {section}{\numberline {9.6}Examples}{110}
+\contentsline {chapter}{\numberline {10} Summary of all FITSIO User-Interface Subroutines }{113}
+\contentsline {chapter}{\numberline {11} Parameter Definitions }{121}
+\contentsline {chapter}{\numberline {12} FITSIO Error Status Codes }{127}
diff --git a/vendor/cfitsio/fitsio2.h b/vendor/cfitsio/fitsio2.h
new file mode 100644
index 00000000..b6fd66c8
--- /dev/null
+++ b/vendor/cfitsio/fitsio2.h
@@ -0,0 +1,1205 @@
+#ifndef _FITSIO2_H
+#define _FITSIO2_H
+
+#include "fitsio.h"
+
+/*
+ Threading support using POSIX threads programming interface
+ (supplied by Bruce O'Neel)
+
+ All threaded programs MUST have the
+
+ -D_REENTRANT
+
+ on the compile line and must link with -lpthread. This means that
+ when one builds cfitsio for threads you must have -D_REENTRANT on the
+ gcc or cc command line.
+*/
+
+#ifdef _REENTRANT
+#include <pthread.h>
+#include <assert.h>
+extern pthread_mutex_t Fitsio_Lock;
+extern int Fitsio_Pthread_Status;
+
+#define FFLOCK1(lockname) (assert(!(Fitsio_Pthread_Status = pthread_mutex_lock(&lockname))))
+#define FFUNLOCK1(lockname) (assert(!(Fitsio_Pthread_Status = pthread_mutex_unlock(&lockname))))
+#define FFLOCK FFLOCK1(Fitsio_Lock)
+#define FFUNLOCK FFUNLOCK1(Fitsio_Lock)
+
+#else
+#define FFLOCK
+#define FFUNLOCK
+#endif
+
+/*
+ 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 NMAXFILES 300 /* maximum number of FITS files that can be opened */
+ /* CFITSIO will allocate (NMAXFILES * 80) bytes of memory */
+
+#define MINDIRECT 8640 /* minimum size for direct reads and writes */
+ /* MINDIRECT must have a value >= 8640 */
+
+/* it is useful to identify certain specific types of machines */
+#define NATIVE 0 /* machine that uses non-byteswapped IEEE formats */
+#define OTHERTYPE 1 /* any other type of machine */
+#define VAXVMS 3 /* uses an odd floating point format */
+#define ALPHAVMS 4 /* uses an odd floating point format */
+#define IBMPC 5 /* used in drvrfile.c to work around a bug on PCs */
+#define CRAY 6 /* requires a special NaN test algorithm */
+
+#define GFLOAT 1 /* used for VMS */
+#define IEEEFLOAT 2 /* used for VMS */
+
+/* ======================================================================= */
+/* The following logic is used to determine the type machine, */
+/* whether the bytes are swapped, and the number of bits in a long value */
+/* ======================================================================= */
+
+/* The following platforms have sizeof(long) == 8 */
+/* This block of code should match a similar block in fitsio.h */
+/* and the block of code at the beginning of f77_wrap.h */
+
+#if defined(__alpha) && ( defined(__unix__) || defined(__NetBSD__) )
+ /* old Dec Alpha platforms running OSF */
+#define BYTESWAPPED TRUE
+#define LONGSIZE 64
+
+#elif defined(__sparcv9) || (defined(__sparc__) && defined(__arch64__))
+ /* SUN Solaris7 in 64-bit mode */
+#define BYTESWAPPED FALSE
+#define MACHINE NATIVE
+#define LONGSIZE 64
+
+ /* IBM System z mainframe support */
+#elif defined(__s390x__)
+#define BYTESWAPPED FALSE
+#define LONGSIZE 64
+
+#elif defined(__s390__)
+#define BYTESWAPPED FALSE
+#define LONGSIZE 32
+
+#elif defined(__ia64__) || defined(__x86_64__)
+ /* Intel itanium 64-bit PC, or AMD opteron 64-bit PC */
+#define BYTESWAPPED TRUE
+#define LONGSIZE 64
+
+#elif defined(_SX) /* Nec SuperUx */
+
+#define BYTESWAPPED FALSE
+#define MACHINE NATIVE
+#define LONGSIZE 64
+
+#elif defined(__powerpc64__) || defined(__64BIT__) /* IBM 64-bit AIX powerpc*/
+ /* could also test for __ppc64__ or __PPC64 */
+#define BYTESWAPPED FALSE
+#define MACHINE NATIVE
+#define LONGSIZE 64
+
+#elif defined(_MIPS_SZLONG)
+
+# if defined(MIPSEL)
+# define BYTESWAPPED TRUE
+# else
+# define BYTESWAPPED FALSE
+# define MACHINE NATIVE
+# endif
+
+# 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
+
+/* ============================================================== */
+/* the following are all 32-bit byteswapped platforms */
+
+#elif 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 /* end of alpha VMS case */
+
+#elif defined(ultrix) && defined(unix)
+ /* old Dec ultrix machines */
+#define BYTESWAPPED TRUE
+
+#elif defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) \
+ || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__) \
+ || defined(_NI_mswin_) || defined(__EMX__)
+
+/* generic 32-bit IBM PC */
+#define MACHINE IBMPC
+#define BYTESWAPPED TRUE
+
+#elif defined(__arm__)
+
+/* This assumes all ARM are little endian. In the future, it might be */
+/* necessary to use "if defined(__ARMEL__)" to distinguish little from big. */
+/* (__ARMEL__ would be defined on little-endian, but not on big-endian). */
+
+#define BYTESWAPPED TRUE
+
+#elif defined(__tile__)
+
+/* 64-core 8x8-architecture Tile64 platform */
+
+#define BYTESWAPPED TRUE
+
+#elif defined(__sh__)
+
+/* SuperH CPU can be used in both little and big endian modes */
+
+#if defined(__LITTLE_ENDIAN__)
+#define BYTESWAPPED TRUE
+#else
+#define BYTESWAPPED FALSE
+#endif
+
+#else
+
+/* assume all other machine uses the same IEEE formats as used in FITS files */
+/* e.g., Macs fall into this category */
+
+#define MACHINE NATIVE
+#define BYTESWAPPED FALSE
+
+#endif
+
+#ifndef MACHINE
+#define MACHINE OTHERTYPE
+#endif
+
+/* assume longs are 4 bytes long, unless previously set otherwise */
+#ifndef LONGSIZE
+#define LONGSIZE 32
+#endif
+
+/* end of block that determine long size and byte swapping */
+/* ==================================================================== */
+
+#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.2233720368547755807E18 /* max double value longlong */
+#define DLONGLONG_MIN -9.2233720368547755808E18 /* 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
+
+
+#define COMPRESS_NULL_VALUE -2147483647
+#define N_RANDOM 10000 /* DO NOT CHANGE THIS; used when quantizing real numbers */
+
+int ffmkky(const char *keyname, char *keyval, const 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(LONGLONG 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 ffc2jj(char *cval, LONGLONG *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 ffc2j(char *cval, LONGLONG *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 ffgtknjj(fitsfile *fptr, int numkey, char *keyname, LONGLONG *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,
+ LONGLONG naxes[], long *pcount, long *gcount, int *extend, double *bscale,
+ double *bzero, LONGLONG *blank, int *nspace, int *status);
+int ffgttb(fitsfile *fptr, LONGLONG *rowlen, LONGLONG *nrows, LONGLONG *pcount,
+ long *tfield, int *status);
+
+int ffmkey(fitsfile *fptr, char *card, int *status);
+
+/* ffmbyt has been moved to fitsio.h */
+int ffgbyt(fitsfile *fptr, LONGLONG nbytes, void *buffer, int *status);
+int ffpbyt(fitsfile *fptr, LONGLONG 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(FITSfile *Fptr, int nbuff, int *status);
+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 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, LONGLONG *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, LONGLONG firstbyte, LONGLONG nbytes, LONGLONG nshift,
+ int *status);
+
+ int ffgcprll(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int writemode, double *scale, double *zero, char *tform,
+ long *twidth, int *tcode, int *maxelem, LONGLONG *startpos,
+ LONGLONG *elemnum, long *incre, LONGLONG *repeat, LONGLONG *rowlen,
+ int *hdutype, LONGLONG *tnull, char *snull, int *status);
+
+int ffflushx(FITSfile *fptr);
+int ffseek(FITSfile *fptr, LONGLONG 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, LONGLONG filesize, int *status);
+
+int ffpcluc(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int *status);
+
+int ffgcll(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int nultyp, char nulval, char *array, char *nularray,
+ int *anynul, int *status);
+int ffgcls(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int nultyp, char *nulval,
+ char **array, char *nularray, int *anynul, int *status);
+int ffgcls2(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, int nultyp, char *nulval,
+ char **array, char *nularray, int *anynul, int *status);
+int ffgclb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, unsigned char nulval,
+ unsigned char *array, char *nularray, int *anynul, int *status);
+int ffgclsb(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, signed char nulval,
+ signed char *array, char *nularray, int *anynul, int *status);
+int ffgclui(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, unsigned short nulval,
+ unsigned short *array, char *nularray, int *anynul, int *status);
+int ffgcli(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, short nulval,
+ short *array, char *nularray, int *anynul, int *status);
+int ffgcluj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, unsigned long nulval,
+ unsigned long *array, char *nularray, int *anynul, int *status);
+int ffgcljj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, LONGLONG nulval,
+ LONGLONG *array, char *nularray, int *anynul, int *status);
+int ffgclj(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, long nulval, long *array,
+ char *nularray, int *anynul, int *status);
+int ffgcluk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, unsigned int nulval,
+ unsigned int *array, char *nularray, int *anynul, int *status);
+int ffgclk(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, int nulval, int *array,
+ char *nularray, int *anynul, int *status);
+int ffgcle(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG nelem, long elemincre, int nultyp, float nulval, float *array,
+ char *nularray, int *anynul, int *status);
+int ffgcld(fitsfile *fptr, int colnum, LONGLONG firstrow, LONGLONG firstelem,
+ LONGLONG 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, LONGLONG pos, long nelem, long incre,
+ unsigned char *buffer, int *status);
+int ffgi2b(fitsfile *fptr, LONGLONG pos, long nelem, long incre, short *buffer,
+ int *status);
+int ffgi4b(fitsfile *fptr, LONGLONG pos, long nelem, long incre, INT32BIT *buffer,
+ int *status);
+int ffgi8b(fitsfile *fptr, LONGLONG pos, long nelem, long incre, long *buffer,
+ int *status);
+int ffgr4b(fitsfile *fptr, LONGLONG pos, long nelem, long incre, float *buffer,
+ int *status);
+int ffgr8b(fitsfile *fptr, LONGLONG pos, long nelem, long incre, double *buffer,
+ int *status);
+
+int ffcins(fitsfile *fptr, LONGLONG naxis1, LONGLONG naxis2, LONGLONG nbytes,
+ LONGLONG bytepos, int *status);
+int ffcdel(fitsfile *fptr, LONGLONG naxis1, LONGLONG naxis2, LONGLONG nbytes,
+ LONGLONG 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, LONGLONG 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, LONGLONG 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, LONGLONG 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, LONGLONG 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, LONGLONG 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, LONGLONG 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, LONGLONG 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, LONGLONG 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, LONGLONG 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, LONGLONG 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 );
+
+int fits_translate_pixkeyword(char *inrec, char *outrec,char *patterns[][2],
+ int npat, int naxis, int *colnum, int *pat_num, int *i,
+ int *j, int *n, int *m, int *l, int *status);
+
+/* 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, LONGLONG fpixel, LONGLONG 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 bitpix, int naxis,long *naxes, int writebitpix, int *status);
+int imcomp_calc_max_elem (int comptype, int nx, int zbitpix, int blocksize);
+int imcomp_copy_imheader(fitsfile *infptr, fitsfile *outfptr,
+ int *status);
+int imcomp_copy_img2comp(fitsfile *infptr, fitsfile *outfptr, int *status);
+int imcomp_copy_comp2img(fitsfile *infptr, fitsfile *outfptr,
+ int norec, int *status);
+int imcomp_copy_prime2img(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, long nx, long ny,
+ int nullcheck, void *nullval, int *status);
+int imcomp_nullscale(int *idata, long tilelen, int nullflagval, int nullval,
+ double scale, double zero, int * status);
+int imcomp_nullvalues(int *idata, long tilelen, int nullflagval, int nullval,
+ int * status);
+int imcomp_scalevalues(int *idata, long tilelen, double scale, double zero,
+ int * status);
+int imcomp_nullscalefloats(float *fdata, long tilelen, int *idata,
+ double scale, double zero, int nullcheck, float nullflagval, int nullval,
+ int *status);
+int imcomp_nullfloats(float *fdata, long tilelen, int *idata, int nullcheck,
+ float nullflagval, int nullval, int *status);
+int imcomp_nullscaledoubles(double *fdata, long tilelen, int *idata,
+ double scale, double zero, int nullcheck, double nullflagval, int nullval,
+ int *status);
+int imcomp_nulldoubles(double *fdata, long tilelen, int *idata, int nullcheck,
+ double nullflagval, int nullval, int *status);
+
+
+/* image decompression routines */
+int fits_read_compressed_img(fitsfile *fptr,
+ int datatype, LONGLONG *fpixel,LONGLONG *lpixel,long *inc,
+ int nullcheck, void *nulval, void *array, char *nullarray,
+ int *anynul, int *status);
+int fits_read_compressed_pixels(fitsfile *fptr,
+ int datatype, LONGLONG fpixel, LONGLONG 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, LONGLONG *firstcoord, LONGLONG *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 imcomp_decompress_img(fitsfile *infptr, fitsfile *outfptr, int datatype,
+ int *status);
+int fits_quantize_float (long row, float fdata[], long nx, long ny, int nullcheck,
+ float in_null_value,
+ float quantize_level, int idata[], double *bscale, double *bzero,
+ int *iminval, int *imaxval);
+int fits_quantize_double (long row, double fdata[], long nx, long ny, int nullcheck,
+ double in_null_value,
+ float quantize_level, 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_rcomp_short(short a[], int nx, unsigned char *c, int clen,int nblock);
+int fits_rcomp_byte(signed char 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 fits_rdecomp_short (unsigned char *c, int clen, unsigned short array[], int nx,
+ int nblock);
+int fits_rdecomp_byte (unsigned char *c, int clen, unsigned char 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);
+int fits_init_randoms(void);
+
+int fitsio_init_lock(void);
+
+/* general driver routines */
+
+int urltype2driver(char *urltype, int *driver);
+
+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, LONGLONG filesize),
+ int (*fitsclose)(int driverhandle),
+ int (*fremove)(char *filename),
+ int (*size)(int driverhandle, LONGLONG *size),
+ int (*flush)(int driverhandle),
+ int (*seek)(int driverhandle, LONGLONG 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, LONGLONG filesize);
+int file_size(int driverhandle, LONGLONG *filesize);
+int file_close(int driverhandle);
+int file_remove(char *filename);
+int file_flush(int driverhandle);
+int file_seek(int driverhandle, LONGLONG 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);
+
+/* stream driver I/O routines */
+
+int stream_open(char *filename, int rwmode, int *driverhandle);
+int stream_create(char *filename, int *driverhandle);
+int stream_size(int driverhandle, LONGLONG *filesize);
+int stream_close(int driverhandle);
+int stream_flush(int driverhandle);
+int stream_seek(int driverhandle, LONGLONG offset);
+int stream_read (int driverhandle, void *buffer, long nbytes);
+int stream_write(int driverhandle, void *buffer, long nbytes);
+
+/* 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, LONGLONG *filesize);
+int mem_truncate(int handle, LONGLONG filesize);
+int mem_close_free(int handle);
+int mem_close_keep(int handle);
+int mem_close_comp(int handle);
+int mem_seek(int handle, LONGLONG 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, LONGLONG offset);
+int root_read (int driverhandle, void *buffer, long nbytes);
+int root_write(int driverhandle, void *buffer, long nbytes);
+int root_size(int handle, LONGLONG *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);
+
+
+#ifdef HAVE_GSIFTP
+/* prototypes for gsiftp driver I/O routines */
+#include "drvrgsiftp.h"
+#endif
+
+#ifdef HAVE_SHMEM_SERVICES
+/* prototypes for shared memory driver I/O routines */
+#include "drvrsmem.h"
+#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
+
+/* end of the entire "ifndef _FITSIO2_H" block */
+#endif
diff --git a/vendor/cfitsio/fpack.c b/vendor/cfitsio/fpack.c
new file mode 100644
index 00000000..8e17bd1c
--- /dev/null
+++ b/vendor/cfitsio/fpack.c
@@ -0,0 +1,387 @@
+/* FPACK
+ * R. Seaman, NOAO, with a few enhancements by W. Pence, HEASARC
+ *
+ * Calls fits_img_compress in the CFITSIO library by W. Pence, HEASARC
+ */
+
+#include <ctype.h>
+/* #include <signal.h> */
+#include "fitsio.h"
+#include "fpack.h"
+
+/* ================================================================== */
+int main(int argc, char *argv[])
+{
+ fpstate fpvar;
+
+ if (argc <= 1) { fp_usage (); fp_hint (); exit (-1); }
+
+ fp_init (&fpvar);
+ fp_get_param (argc, argv, &fpvar);
+
+ if (fpvar.listonly) {
+ fp_list (argc, argv, fpvar);
+
+ } else {
+ fp_preflight (argc, argv, FPACK, &fpvar);
+ fp_loop (argc, argv, FPACK, fpvar);
+ }
+
+ exit (0);
+}
+/* ================================================================== */
+int fp_get_param (int argc, char *argv[], fpstate *fpptr)
+{
+ int gottype=0, gottile=0, wholetile=0, iarg, len, ndim, ii, doffset;
+ char tmp[SZ_STR], tile[SZ_STR];
+
+ if (fpptr->initialized != FP_INIT_MAGIC) {
+ fp_msg ("Error: internal initialization error\n"); exit (-1);
+ }
+
+ tile[0] = 0;
+
+ /* flags must come first and be separately specified
+ */
+ for (iarg = 1; iarg < argc; iarg++) {
+ if ((argv[iarg][0] == '-' && strlen (argv[iarg]) == 2) ||
+ !strncmp(argv[iarg], "-q", 2) || /* special case */
+ !strncmp(argv[iarg], "-g1", 3) || /* special case */
+ !strncmp(argv[iarg], "-g2", 3) || /* special case */
+ !strncmp(argv[iarg], "-i2f", 4) || /* special case */
+ !strncmp(argv[iarg], "-fast", 5) || /* special case */
+ !strncmp(argv[iarg], "-n3ratio", 8) || /* special case */
+ !strncmp(argv[iarg], "-n3min", 6) || /* special case */
+ !strncmp(argv[iarg], "-BETAtable", 10) ) /* special case */
+ {
+
+ /* Rice is the default, so -r is superfluous
+ */
+ if ( argv[iarg][1] == 'r') {
+ fpptr->comptype = RICE_1;
+ if (gottype) {
+ fp_msg ("Error: multiple compression flags\n");
+ fp_usage (); exit (-1);
+ } else
+ gottype++;
+
+ } else if (argv[iarg][1] == 'p') {
+ fpptr->comptype = PLIO_1;
+ if (gottype) {
+ fp_msg ("Error: multiple compression flags\n");
+ fp_usage (); exit (-1);
+ } else
+ gottype++;
+
+ } else if (argv[iarg][1] == 'g') {
+ /* test for modifiers following the 'g' */
+ if (argv[iarg][2] == '2')
+ fpptr->comptype = GZIP_2;
+ else
+ fpptr->comptype = GZIP_1;
+
+ if (gottype) {
+ fp_msg ("Error: multiple compression flags\n");
+ fp_usage (); exit (-1);
+ } else
+ gottype++;
+/*
+ } else if (argv[iarg][1] == 'b') {
+ fpptr->comptype = BZIP2_1;
+ if (gottype) {
+ fp_msg ("Error: multiple compression flags\n");
+ fp_usage (); exit (-1);
+ } else
+ gottype++;
+*/
+ } else if (argv[iarg][1] == 'h') {
+ fpptr->comptype = HCOMPRESS_1;
+ if (gottype) {
+ fp_msg ("Error: multiple compression flags\n");
+ fp_usage (); exit (-1);
+ } else
+ gottype++;
+
+ } else if (argv[iarg][1] == 'd') {
+ fpptr->comptype = NOCOMPRESS;
+ if (gottype) {
+ fp_msg ("Error: multiple compression flags\n");
+ fp_usage (); exit (-1);
+ } else
+ gottype++;
+
+ } else if (!strcmp(argv[iarg], "-i2f")) {
+ /* this means convert integer images to float, and then */
+ /* quantize and compress the float image. This lossy */
+ /* compression method may give higher compression than the */
+ /* lossless compression method that is usually applied to */
+ /* integer images. */
+
+ fpptr->int_to_float = 1;
+
+ } else if (!strcmp(argv[iarg], "-n3ratio")) {
+ /* this is the minimum ratio between the MAD noise sigma */
+ /* and the q parameter value in the case where the integer */
+ /* image is quantized and compressed like a float image. */
+ if (++iarg >= argc) {
+ fp_usage (); exit (-1);
+ } else {
+ fpptr->n3ratio = (float) atof (argv[iarg]);
+ }
+ } else if (!strcmp(argv[iarg], "-n3min")) {
+ /* this is the minimum MAD noise sigma in the case where the */
+ /* integer image is quantized and compressed like a float image. */
+ if (++iarg >= argc) {
+ fp_usage (); exit (-1);
+ } else {
+ fpptr->n3min = (float) atof (argv[iarg]);
+ }
+ } else if (argv[iarg][1] == 'q') {
+ /* test for modifiers following the 'q' */
+ if (argv[iarg][2] == 't') {
+ fpptr->dither_offset = -1; /* dither based on tile checksum */
+
+ } else if (isdigit(argv[iarg][2])) { /* is a number appended to q? */
+ doffset = atoi(argv[iarg]+2);
+
+ if (doffset == 0) {
+ fpptr->no_dither = 1; /* don't dither the quantized values */
+ } else if (doffset > 0 && doffset <= 10000) {
+ fpptr->dither_offset = doffset;
+ } else {
+ fp_msg ("Error: invalid q suffix\n");
+ fp_usage (); exit (-1);
+ }
+ }
+
+ if (++iarg >= argc) {
+ fp_usage (); exit (-1);
+ } else {
+ fpptr->quantize_level = (float) atof (argv[iarg]);
+ }
+ } else if (argv[iarg][1] == 'n') {
+ if (++iarg >= argc) {
+ fp_usage (); exit (-1);
+ } else {
+ fpptr->rescale_noise = (float) atof (argv[iarg]);
+ }
+ } else if (argv[iarg][1] == 's') {
+ if (++iarg >= argc) {
+ fp_usage (); exit (-1);
+ } else {
+ fpptr->scale = (float) atof (argv[iarg]);
+ }
+ } else if (argv[iarg][1] == 't') {
+ if (gottile) {
+ fp_msg ("Error: multiple tile specifications\n");
+ fp_usage (); exit (-1);
+ } else
+ gottile++;
+
+ if (++iarg >= argc) {
+ fp_usage (); exit (-1);
+ } else
+ strncpy (tile, argv[iarg], SZ_STR); /* checked below */
+
+ } else if (argv[iarg][1] == 'v') {
+ fpptr->verbose = 1;
+
+ } else if (argv[iarg][1] == 'w') {
+ wholetile++;
+ if (gottile) {
+ fp_msg ("Error: multiple tile specifications\n");
+ fp_usage (); exit (-1);
+ } else
+ gottile++;
+
+ } else if (argv[iarg][1] == 'F') {
+ fpptr->clobber++; /* overwrite existing file */
+
+ } else if (argv[iarg][1] == 'D') {
+ fpptr->delete_input++;
+
+ } else if (argv[iarg][1] == 'Y') {
+ fpptr->do_not_prompt++;
+
+ } else if (argv[iarg][1] == 'S') {
+ fpptr->to_stdout++;
+
+ } else if (argv[iarg][1] == 'L') {
+ fpptr->listonly++;
+
+ } else if (argv[iarg][1] == 'C') {
+ fpptr->do_checksums = 0;
+
+ } else if (argv[iarg][1] == 'T') {
+ fpptr->test_all = 1;
+
+ } else if (argv[iarg][1] == 'R') {
+ if (++iarg >= argc) {
+ fp_usage (); fp_hint (); exit (-1);
+ } else
+ strncpy (fpptr->outfile, argv[iarg], SZ_STR);
+
+ } else if (argv[iarg][1] == 'H') {
+ fp_help (); exit (0);
+
+ } else if (argv[iarg][1] == 'V') {
+ fp_version (); exit (0);
+
+ } else if (!strcmp(argv[iarg], "-BETAtable")) {
+ fpptr->do_tables = 1;
+ fp_msg ("Caution: -BETAtable is for feasibility studies, not general use.\n");
+
+ } else if (!strcmp(argv[iarg], "-fast")) {
+ fpptr->do_fast = 1;
+
+ } else {
+ fp_msg ("Error: unknown command line flag `");
+ fp_msg (argv[iarg]); fp_msg ("'\n");
+ fp_usage (); fp_hint (); exit (-1);
+ }
+
+ } else
+ break;
+ }
+
+ if (fpptr->scale != 0. &&
+ fpptr->comptype != HCOMPRESS_1 && fpptr->test_all != 1) {
+
+ fp_msg ("Error: `-s' requires `-h or -T'\n"); exit (-1);
+ }
+
+ if (fpptr->quantize_level == 0) {
+
+ if ((fpptr->comptype != GZIP_1) && (fpptr->comptype != GZIP_2)) {
+ fp_msg ("Error: `-q 0' only allowed with GZIP\n"); exit (-1);
+ }
+
+ if (fpptr->int_to_float == 1) {
+ fp_msg ("Error: `-q 0' not allowed with -i2f\n"); exit (-1);
+ }
+ }
+
+ if (wholetile) {
+ for (ndim=0; ndim < MAX_COMPRESS_DIM; ndim++)
+ fpptr->ntile[ndim] = (long) 0;
+
+ } else if (gottile) {
+ len = strlen (tile);
+ for (ii=0, ndim=0; ii < len; ) {
+ if (! (isdigit (tile[ii]) || tile[ii] == ',')) {
+ fp_msg ("Error: `-t' requires comma separated tile dims, ");
+ fp_msg ("e.g., `-t 100,100'\n"); exit (-1);
+ }
+
+ if (tile[ii] == ',') { ii++; continue; }
+
+ fpptr->ntile[ndim] = atol (&tile[ii]);
+ for ( ; isdigit(tile[ii]); ii++);
+
+ if (++ndim > MAX_COMPRESS_DIM) {
+ fp_msg ("Error: too many dimensions for `-t', max=");
+ sprintf (tmp, "%d\n", MAX_COMPRESS_DIM); fp_msg (tmp);
+ exit (-1);
+ }
+ }
+ }
+
+ if (iarg >= argc) {
+ fp_msg ("Error: no FITS files to compress\n");
+ fp_usage (); exit (-1);
+ } else
+ fpptr->firstfile = iarg;
+
+ return(0);
+}
+
+/* ================================================================== */
+int fp_usage (void)
+{
+fp_msg ("usage: fpack ");
+fp_msg (
+"[-r|-h|-g|-p] [-w|-t <axes>] [-q <level>] [-s <scale>] [-n <noise>] -v <FITS>\n");
+fp_msg ("more: [-T] [-R] [-F] [-D] [-Y] [-S] [-L] [-C] [-H] [-V] [-i2f]\n");
+return(0);
+}
+
+/* ================================================================== */
+int fp_hint (void)
+{ fp_msg (" `fpack -H' for help\n");
+return(0);
+}
+
+/* ================================================================== */
+int fp_help (void)
+{
+fp_msg ("fpack, a FITS image compression program. Version ");
+fp_version ();
+fp_usage ();
+fp_msg ("\n");
+
+fp_msg ("Flags must be separate and appear before filenames:\n");
+fp_msg (" -r Rice compression [default], or\n");
+fp_msg (" -h Hcompress compression, or\n");
+fp_msg (" -g or -g1 GZIP_1 (per-tile) compression, or\n");
+fp_msg (" -g2 GZIP_2 (per-tile) compression (with byte shuffling), or\n");
+/*
+fp_msg (" -b BZIP2 (per-tile) compression, or\n");
+*/
+fp_msg (" -p PLIO compression (only for positive 8 or 16-bit integer images).\n");
+fp_msg (" -d Tile the image without compression (debugging mode).\n");
+
+fp_msg (" -w Compress the whole image as a single large tile.\n");
+fp_msg (" -t <axes> Comma separated list of tile dimensions [default is row by row].\n");
+
+fp_msg (" -q <level> Quantized level spacing when converting floating point images to\n");
+fp_msg (" scaled integers. (+value relative to sigma of background noise;\n");
+fp_msg (" -value is absolute). Default q value of 4 gives a compression ratio\n");
+fp_msg (" of about 6 with very high fidelity (only 0.26% increase in noise).\n");
+fp_msg (" Using q values of 2, or 1 will give compression ratios of\n");
+fp_msg (" about 8, or 10, respectively (with 1.0% or 4.1% noise increase).\n");
+fp_msg (" The scaled quantized values are randomly dithered using a seed \n");
+fp_msg (" value determined from the system clock at run time.\n");
+fp_msg (" Use -q0 instead of -q to suppress random dithering.\n");
+fp_msg (" Use -qt to compute random dithering seed from first tile checksum.\n");
+fp_msg (" Use -qN, (N in range 1 to 10000) to use a specific dithering seed.\n");
+fp_msg (" Floating-point images can be losslessly compressed by selecting\n");
+fp_msg (" the GZIP algorithm and specifying -q 0, but this is slower and often\n");
+fp_msg (" produces much less compression than the default quantization method.\n");
+fp_msg (" -i2f Convert integer images to floating point, then quantize and compress\n");
+fp_msg (" using the specified q level. When used appropriately, this lossy\n");
+fp_msg (" compression method can give much better compression than the normal\n");
+fp_msg (" lossless compression methods without significant loss of information.\n");
+fp_msg (" The -n3ratio and -n3min flags control the minimum noise thresholds;\n");
+fp_msg (" Images below these thresholds will be losslessly compressed.\n");
+fp_msg (" -n3ratio Minimum ratio of background noise sigma divided by q. Default = 1.2.\n");
+fp_msg (" -n3min Minimum background noise sigma. Default = 6. The -i2f flag will be ignored\n");
+fp_msg (" if the noise level in the image does not exceed both thresholds.\n");
+fp_msg (" -s <scale> Scale factor for lossy Hcompress [default = 0 = lossless]\n");
+fp_msg (" (+values relative to RMS noise; -value is absolute)\n");
+fp_msg (" -n <noise> Rescale scaled-integer images to reduce noise and improve compression.\n");
+fp_msg (" -v Verbose mode; list each file as it is processed.\n");
+fp_msg (" -T Show compression algorithm comparison test statistics; files unchanged.\n");
+fp_msg (" -R <file> Write the comparison test report (above) to a text file.\n");
+fp_msg (" -BETAtable Compress FITS binary tables using prototype method.\n");
+fp_msg (" This option is ONLY for experimental use! Do NOT use\n");
+fp_msg (" on FITS data files that are to be publicly distributed.\n");
+fp_msg (" -fast Used with -BETAtable to favor speed over maximum compression.\n");
+
+fp_msg ("\nkeywords shared with funpack:\n");
+
+fp_msg (" -F Overwrite input file by output file with same name.\n");
+fp_msg (" -D Delete input file after writing output.\n");
+fp_msg (" -Y Suppress prompts to confirm -F or -D options.\n");
+
+fp_msg (" -S Output compressed FITS files to STDOUT.\n");
+fp_msg (" -L List contents; files unchanged.\n");
+
+fp_msg (" -C Don't update FITS checksum keywords.\n");
+
+fp_msg (" -H Show this message.\n");
+fp_msg (" -V Show version number.\n");
+
+fp_msg ("\n <FITS> FITS files to pack; enter '-' (a hyphen) to read input from stdin stream.\n");
+fp_msg (" Refer to the fpack User's Guide for more extensive help.\n");
+return(0);
+}
diff --git a/vendor/cfitsio/fpack.h b/vendor/cfitsio/fpack.h
new file mode 100644
index 00000000..398840f8
--- /dev/null
+++ b/vendor/cfitsio/fpack.h
@@ -0,0 +1,171 @@
+/* used by FPACK and FUNPACK
+ * R. Seaman, NOAO
+ * W. Pence, NASA/GSFC
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* not needed any more */
+/* #include <unistd.h> */
+/* #include <sys/stat.h> */
+/* #include <sys/types.h> */
+
+#define FPACK_VERSION "1.6.0 (Feb 2011)"
+/*
+VERSION History
+
+1.6.0 (June 2012)
+ - Fixed behavior of the "rename" function on Windows platforms so that
+ it will clobber/delete an existing file before renaming a file to
+ that name (the rename command behaves differently on POSIX and non-POSIX
+ environments).
+
+1.6.0 (February 2011)
+ - Added full support for compressing and uncompressing FITS binary tables
+ using a newly proposed format convention. This is intended only for
+ further feasibility studies, and is not recommended for use with publicly
+ distributed FITS files.
+ - Use the minimum of the MAD 2nd, 3rd, and 5th order values as a more
+ conservative extimate of the noise when quantizing floating point images.
+ - Enhanced the tile compression routines so that a tile that contains all
+ NaN pixel values will be compressed.
+ - When uncompressing an image that was originally in a FITS primary array,
+ funpack will also append any new keywords that were written into the
+ primary array of the compressed FITS file after the file was compressed.
+ - Added support for the GZIP_2 algorithm, which shuffles the bytes in the
+ pixel values prior to compressing them with gzip.
+1.5.1 (December 2010) Added prototype, mainly hidden, support for compressing
+ binary tables.
+1.5.0 (August 2010) Added the -i2f option to lossy compress integer images.
+1.4.0 (Jan 2010) Reduced the default value for the q floating point image
+ quantization parameter from 16 to 4. This results in about 50% better
+ compression (from about 4.6x to 6.4) with no lost of significant information
+ (with the new subtractive dithering enhancement). Replaced the code for
+ generating temporary filenames to make the code more portable (to Windows).
+ Replaced calls to the unix 'access' and 'stat' functions with more portable
+ code. When unpacking a file, write it first to a temporary file, then
+ rename it when finished, so that other tasks cannot try to read the file
+ before it is complete.
+1.3.0 (Oct 2009) added randomization to the dithering pattern so that
+ the same pattern is not used for every image; also added an option
+ for losslessly compressing floating point images with GZIP for test
+ purposes (not recommended for general use). Also added support for
+ reading the input FITS file from the stdin file streams.
+1.2.0 (Sept 2009) added subtractive dithering feature (in CFITSIO) when
+ quantizing floating point images; When packing an IRAF .imh + .pix image,
+ the file name is changed to FILE.fits.fz, and if the original file is
+ deleted, then both the .imh and .pix files are deleted.
+1.1.4 (May 2009) added -E option to funpack to unpack a list of HDUs
+1.1.3 (March 2009) minor modifications to the content and format of the -T report
+1.1.2 (September 2008)
+*/
+
+#define FP_INIT_MAGIC 42
+#define FPACK 0
+#define FUNPACK 1
+
+/* changed from 16 in Jan. 2010 */
+#define DEF_QLEVEL 4.
+
+#define DEF_HCOMP_SCALE 0.
+#define DEF_HCOMP_SMOOTH 0
+#define DEF_RESCALE_NOISE 0
+
+#define SZ_STR 513
+#define SZ_CARD 81
+
+
+typedef struct
+{
+ int comptype;
+ float quantize_level;
+ int no_dither;
+ int dither_offset;
+ float scale;
+ float rescale_noise;
+ int smooth;
+ int int_to_float;
+ float n3ratio;
+ float n3min;
+ long ntile[MAX_COMPRESS_DIM];
+
+ int to_stdout;
+ int listonly;
+ int clobber;
+ int delete_input;
+ int do_not_prompt;
+ int do_checksums;
+ int do_gzip_file;
+ int do_tables;
+ int do_fast;
+ int test_all;
+ int verbose;
+
+ char prefix[SZ_STR];
+ char extname[SZ_STR];
+ int delete_suffix;
+ char outfile[SZ_STR];
+ int firstfile;
+
+ int initialized;
+ int preflight_checked;
+} fpstate;
+
+typedef struct
+{
+ int n_nulls;
+ double minval;
+ double maxval;
+ double mean;
+ double sigma;
+ double noise1;
+ double noise2;
+ double noise3;
+ double noise5;
+} imgstats;
+
+int fp_get_param (int argc, char *argv[], fpstate *fpptr);
+void abort_fpack(int sig);
+void fp_abort_output (fitsfile *infptr, fitsfile *outfptr, int stat);
+int fp_usage (void);
+int fp_help (void);
+int fp_hint (void);
+int fp_init (fpstate *fpptr);
+int fp_list (int argc, char *argv[], fpstate fpvar);
+int fp_info (char *infits);
+int fp_info_hdu (fitsfile *infptr);
+int fp_preflight (int argc, char *argv[], int unpack, fpstate *fpptr);
+int fp_loop (int argc, char *argv[], int unpack, fpstate fpvar);
+int fp_pack (char *infits, char *outfits, fpstate fpvar, int *islossless);
+int fp_unpack (char *infits, char *outfits, fpstate fpvar);
+int fp_test (char *infits, char *outfits, char *outfits2, fpstate fpvar);
+int fp_pack_hdu (fitsfile *infptr, fitsfile *outfptr, fpstate fpvar,
+ int *islossless, int *status);
+int fp_unpack_hdu (fitsfile *infptr, fitsfile *outfptr, fpstate fpvar, int *status);
+int fits_read_image_speed (fitsfile *infptr, float *whole_elapse,
+ float *whole_cpu, float *row_elapse, float *row_cpu, int *status);
+int fp_test_hdu (fitsfile *infptr, fitsfile *outfptr, fitsfile *outfptr2,
+ fpstate fpvar, int *status);
+int marktime(int *status);
+int gettime(float *elapse, float *elapscpu, int *status);
+int fits_read_image_speed (fitsfile *infptr, float *whole_elapse,
+ float *whole_cpu, float *row_elapse, float *row_cpu, int *status);
+
+int fp_i2stat(fitsfile *infptr, int naxis, long *naxes, imgstats *imagestats, int *status);
+int fp_i4stat(fitsfile *infptr, int naxis, long *naxes, imgstats *imagestats, int *status);
+int fp_r4stat(fitsfile *infptr, int naxis, long *naxes, imgstats *imagestats, int *status);
+int fp_i2rescale(fitsfile *infptr, int naxis, long *naxes, double rescale,
+ fitsfile *outfptr, int *status);
+int fp_i4rescale(fitsfile *infptr, int naxis, long *naxes, double rescale,
+ fitsfile *outfptr, int *status);
+
+int fp_msg (char *msg);
+int fp_version (void);
+int fp_noop (void);
+
+int fu_get_param (int argc, char *argv[], fpstate *fpptr);
+int fu_usage (void);
+int fu_hint (void);
+int fu_help (void);
diff --git a/vendor/cfitsio/fpackguide.pdf b/vendor/cfitsio/fpackguide.pdf
new file mode 100644
index 00000000..0516b4ae
--- /dev/null
+++ b/vendor/cfitsio/fpackguide.pdf
Binary files differ
diff --git a/vendor/cfitsio/fpackutil.c b/vendor/cfitsio/fpackutil.c
new file mode 100644
index 00000000..4829613c
--- /dev/null
+++ b/vendor/cfitsio/fpackutil.c
@@ -0,0 +1,2391 @@
+/* FPACK utility routines
+ R. Seaman, NOAO & W. Pence, NASA/GSFC
+*/
+
+#include <time.h>
+#include <float.h>
+#include <signal.h>
+
+/* #include "bzlib.h" only for experimental purposes */
+
+#if defined(unix) || defined(__unix__) || defined(__unix)
+#include <sys/time.h>
+#endif
+
+#include <math.h>
+#include "fitsio.h"
+#include "fpack.h"
+
+/* these filename buffer are used to delete temporary files */
+/* in case the program is aborted */
+char tempfilename[SZ_STR];
+char tempfilename2[SZ_STR];
+char tempfilename3[SZ_STR];
+
+/* nearest integer function */
+# define NINT(x) ((x >= 0.) ? (int) (x + 0.5) : (int) (x - 0.5))
+# define NSHRT(x) ((x >= 0.) ? (short) (x + 0.5) : (short) (x - 0.5))
+
+/* define variables for measuring elapsed time */
+clock_t scpu, ecpu;
+long startsec; /* start of elapsed time interval */
+int startmilli; /* start of elapsed time interval */
+
+/* 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
+#endif
+
+FILE *outreport;
+
+/* dimension of central image area to be sampled for test statistics */
+int XSAMPLE = 4100;
+int YSAMPLE = 4100;
+
+int fp_msg (char *msg)
+{
+ printf ("%s", msg);
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fp_noop (void)
+{
+ fp_msg ("Input and output files are unchanged.\n");
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+void fp_abort_output (fitsfile *infptr, fitsfile *outfptr, int stat)
+{
+ int status = 0, hdunum;
+ char msg[SZ_STR];
+
+ fits_file_name(infptr, tempfilename, &status);
+ fits_get_hdu_num(infptr, &hdunum);
+
+ fits_close_file (infptr, &status);
+
+ sprintf(msg, "Error processing file: %s\n", tempfilename);
+ fp_msg (msg);
+ sprintf(msg, " in HDU number %d\n", hdunum);
+ fp_msg (msg);
+
+ fits_report_error (stderr, stat);
+
+ if (outfptr) {
+ fits_delete_file(outfptr, &status);
+ fp_msg ("Input file is unchanged.\n");
+ }
+
+ exit (stat);
+}
+/*--------------------------------------------------------------------------*/
+int fp_version (void)
+{
+ float version;
+ char cfitsioversion[40];
+
+ fp_msg (FPACK_VERSION);
+ fits_get_version(&version);
+ sprintf(cfitsioversion, " CFITSIO version %5.3f", version);
+ fp_msg(cfitsioversion);
+ fp_msg ("\n");
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fp_access (char *filename)
+{
+ /* test if a file exists */
+
+ FILE *diskfile;
+
+ diskfile = fopen(filename, "r");
+
+ if (diskfile) {
+ fclose(diskfile);
+ return(0);
+ } else {
+ return(-1);
+ }
+}
+/*--------------------------------------------------------------------------*/
+int fp_tmpnam(char *suffix, char *rootname, char *tmpnam)
+{
+ /* create temporary file name */
+
+ int maxtry = 30, len, i1 = 0, ii;
+
+ if (strlen(suffix) + strlen(rootname) > SZ_STR-5) {
+ fp_msg ("Error: filename is too long to create tempory file\n"); exit (-1);
+ }
+
+ strcpy (tmpnam, rootname); /* start with rootname */
+ strcat(tmpnam, suffix); /* append the suffix */
+
+ maxtry = SZ_STR - strlen(tmpnam) - 1;
+
+ for (ii = 0; ii < maxtry; ii++) {
+ if (fp_access(tmpnam)) break; /* good, the file does not exist */
+ strcat(tmpnam, "x"); /* append an x to the name, and try again */
+ }
+
+ if (ii == maxtry) {
+ fp_msg ("\nCould not create temporary file name:\n");
+ fp_msg (tmpnam);
+ fp_msg ("\n");
+ exit (-1);
+ }
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fp_init (fpstate *fpptr)
+{
+ int ii;
+
+ fpptr->comptype = RICE_1;
+ fpptr->quantize_level = DEF_QLEVEL;
+ fpptr->no_dither = 0;
+ fpptr->dither_offset = 0;
+ fpptr->int_to_float = 0;
+
+ /* thresholds when using the -i2f flag */
+ fpptr->n3ratio = 1.20; /* minimum ratio of image noise sigma / q */
+ fpptr->n3min = 6.; /* minimum noise sigma. */
+
+ fpptr->scale = DEF_HCOMP_SCALE;
+ fpptr->smooth = DEF_HCOMP_SMOOTH;
+ fpptr->rescale_noise = DEF_RESCALE_NOISE;
+ fpptr->ntile[0] = (long) 0; /* 0 means extent of axis */
+
+ for (ii=1; ii < MAX_COMPRESS_DIM; ii++)
+ fpptr->ntile[ii] = (long) 1;
+
+ fpptr->to_stdout = 0;
+ fpptr->listonly = 0;
+ fpptr->clobber = 0;
+ fpptr->delete_input = 0;
+ fpptr->do_not_prompt = 0;
+ fpptr->do_checksums = 1;
+ fpptr->do_gzip_file = 0;
+ fpptr->do_tables = 0; /* this is for beta testing purposes only */
+ fpptr->do_fast = 0; /* this is for beta testing purposes only */
+ fpptr->test_all = 0;
+ fpptr->verbose = 0;
+
+ fpptr->prefix[0] = 0;
+ fpptr->extname[0] = 0;
+ fpptr->delete_suffix = 0;
+ fpptr->outfile[0] = 0;
+
+ fpptr->firstfile = 1;
+
+ /* magic number for initialization check, boolean for preflight
+ */
+ fpptr->initialized = FP_INIT_MAGIC;
+ fpptr->preflight_checked = 0;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fp_list (int argc, char *argv[], fpstate fpvar)
+{
+ fitsfile *infptr;
+ char infits[SZ_STR], msg[SZ_STR];
+ int hdunum, iarg, stat=0;
+ LONGLONG sizell;
+
+ if (fpvar.initialized != FP_INIT_MAGIC) {
+ fp_msg ("Error: internal initialization error\n"); exit (-1);
+ }
+
+ for (iarg=fpvar.firstfile; iarg < argc; iarg++) {
+ strncpy (infits, argv[iarg], SZ_STR);
+
+ if (strchr (infits, '[') || strchr (infits, ']')) {
+ fp_msg ("Error: section/extension notation not supported: ");
+ fp_msg (infits); fp_msg ("\n"); exit (-1);
+ }
+
+ if (fp_access (infits) != 0) {
+ fp_msg ("Error: can't find or read input file "); fp_msg (infits);
+ fp_msg ("\n"); fp_noop (); exit (-1);
+ }
+
+ fits_open_file (&infptr, infits, READONLY, &stat);
+ if (stat) { fits_report_error (stderr, stat); exit (stat); }
+
+ /* move to the end of file, to get the total size in bytes */
+ fits_get_num_hdus (infptr, &hdunum, &stat);
+ fits_movabs_hdu (infptr, hdunum, NULL, &stat);
+ fits_get_hduaddrll(infptr, NULL, NULL, &sizell, &stat);
+
+
+ if (stat) {
+ fp_abort_output(infptr, NULL, stat);
+ }
+
+ sprintf (msg, "# %s (", infits); fp_msg (msg);
+
+#if defined(_MSC_VER)
+ /* Microsoft Visual C++ 6.0 uses '%I64d' syntax for 8-byte integers */
+ sprintf(msg, "%I64d bytes)\n", sizell); fp_msg (msg);
+#elif (USE_LL_SUFFIX == 1)
+ sprintf(msg, "%lld bytes)\n", sizell); fp_msg (msg);
+#else
+ sprintf(msg, "%ld bytes)\n", sizell); fp_msg (msg);
+#endif
+ fp_info_hdu (infptr);
+
+ fits_close_file (infptr, &stat);
+ if (stat) { fits_report_error (stderr, stat); exit (stat); }
+ }
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fp_info_hdu (fitsfile *infptr)
+{
+ long naxes[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
+ char msg[SZ_STR], val[SZ_CARD], com[SZ_CARD];
+ int comptype, naxis=0, hdutype, bitpix, hdupos, stat=0, ii;
+ unsigned long datasum, hdusum;
+
+ fits_movabs_hdu (infptr, 1, NULL, &stat);
+ if (stat) {
+ fp_abort_output(infptr, NULL, stat);
+ }
+
+ for (hdupos=1; ! stat; hdupos++) {
+ fits_get_hdu_type (infptr, &hdutype, &stat);
+ if (stat) {
+ fp_abort_output(infptr, NULL, stat);
+ }
+
+ /* fits_get_hdu_type calls unknown extensions "IMAGE_HDU"
+ * so consult XTENSION keyword itself
+ */
+ fits_read_keyword (infptr, "XTENSION", val, com, &stat);
+ if (stat == KEY_NO_EXIST) {
+ /* in primary HDU which by definition is an "image" */
+ stat=0; /* clear for later error handling */
+
+ } else if (stat) {
+ fp_abort_output(infptr, NULL, stat);
+
+ } else if (hdutype == IMAGE_HDU) {
+ /* that is, if XTENSION != "IMAGE" AND != "BINTABLE" */
+ if (strncmp (val+1, "IMAGE", 5) &&
+ strncmp (val+1, "BINTABLE", 5)) {
+
+ /* assign something other than any of these */
+ hdutype = IMAGE_HDU + ASCII_TBL + BINARY_TBL;
+ }
+ }
+
+ fits_get_chksum(infptr, &datasum, &hdusum, &stat);
+
+ if (hdutype == IMAGE_HDU) {
+ sprintf (msg, " %d IMAGE", hdupos); fp_msg (msg);
+ sprintf (msg, " SUMS=%lu/%lu", (unsigned long) (~((int) hdusum)), datasum); fp_msg (msg);
+
+ fits_get_img_param (infptr, 9, &bitpix, &naxis, naxes, &stat);
+
+ sprintf (msg, " BITPIX=%d", bitpix); fp_msg (msg);
+
+ if (naxis == 0) {
+ sprintf (msg, " [no_pixels]"); fp_msg (msg);
+ } else if (naxis == 1) {
+ sprintf (msg, " [%ld]", naxes[1]); fp_msg (msg);
+ } else {
+ sprintf (msg, " [%ld", naxes[0]); fp_msg (msg);
+ for (ii=1; ii < naxis; ii++) {
+ sprintf (msg, "x%ld", naxes[ii]); fp_msg (msg);
+ }
+ fp_msg ("]");
+ }
+
+ if (fits_is_compressed_image (infptr, &stat)) {
+ fits_read_keyword (infptr, "ZCMPTYPE", val, com, &stat);
+
+ /* allow for quote in keyword value */
+ if (! strncmp (val+1, "RICE_1", 6))
+ fp_msg (" tiled_rice\n");
+ else if (! strncmp (val+1, "GZIP_1", 6))
+ fp_msg (" tiled_gzip_1\n");
+ else if (! strncmp (val+1, "GZIP_2", 6))
+ fp_msg (" tiled_gzip_2\n");
+ else if (! strncmp (val+1, "PLIO_1", 6))
+ fp_msg (" tiled_plio\n");
+ else if (! strncmp (val+1, "HCOMPRESS_1", 11))
+ fp_msg (" tiled_hcompress\n");
+ else
+ fp_msg (" unknown\n");
+
+ } else
+ fp_msg (" not_tiled\n");
+
+ } else if (hdutype == ASCII_TBL) {
+ sprintf (msg, " %d ASCII_TBL", hdupos); fp_msg (msg);
+ sprintf (msg, " SUMS=%lu/%lu\n", (unsigned long) (~((int) hdusum)), datasum); fp_msg (msg);
+
+ } else if (hdutype == BINARY_TBL) {
+ sprintf (msg, " %d BINARY_TBL", hdupos); fp_msg (msg);
+ sprintf (msg, " SUMS=%lu/%lu\n", (unsigned long) (~((int) hdusum)), datasum); fp_msg (msg);
+
+ } else {
+ sprintf (msg, " %d OTHER", hdupos); fp_msg (msg);
+ sprintf (msg, " SUMS=%lu/%lu", (unsigned long) (~((int) hdusum), datasum)); fp_msg (msg);
+ sprintf (msg, " %s\n", val); fp_msg (msg);
+ }
+
+ fits_movrel_hdu (infptr, 1, NULL, &stat);
+ }
+ return(0);
+}
+
+/*--------------------------------------------------------------------------*/
+int fp_preflight (int argc, char *argv[], int unpack, fpstate *fpptr)
+{
+ char infits[SZ_STR], outfits[SZ_STR], temp[SZ_STR], *cptr;
+ int iarg, suflen, namelen, nfiles = 0;
+
+ if (fpptr->initialized != FP_INIT_MAGIC) {
+ fp_msg ("Error: internal initialization error\n"); exit (-1);
+ }
+
+ for (iarg=fpptr->firstfile; iarg < argc; iarg++) {
+
+ outfits[0] = '\0';
+
+ if (strlen(argv[iarg]) > SZ_STR - 4) { /* allow for .fz or .gz suffix */
+ fp_msg ("Error: input file name\n "); fp_msg (argv[iarg]);
+ fp_msg ("\n is too long\n"); fp_noop (); exit (-1);
+ }
+
+ strncpy (infits, argv[iarg], SZ_STR);
+
+ if (strchr (infits, '[') || strchr (infits, ']')) {
+ fp_msg ("Error: section/extension notation not supported: ");
+ fp_msg (infits); fp_msg ("\n"); fp_noop (); exit (-1);
+ }
+
+ if (unpack) {
+ /* ********** This section applies to funpack ************ */
+
+ /* check that input file exists */
+ if (infits[0] != '-') { /* if not reading from stdin stream */
+ if (fp_access (infits) != 0) { /* if not, then check if */
+ strcat(infits, ".fz"); /* a .fz version exsits */
+ if (fp_access (infits) != 0) {
+ namelen = strlen(infits);
+ infits[namelen - 3] = '\0'; /* remove the .fz suffix */
+ fp_msg ("Error: can't find or read input file "); fp_msg (infits);
+ fp_msg ("\n"); fp_noop (); exit (-1);
+ }
+ } else { /* make sure a .fz version of the same file doesn't exist */
+ namelen = strlen(infits);
+ strcat(infits, ".fz");
+ if (fp_access (infits) == 0) {
+ infits[namelen] = '\0'; /* remove the .fz suffix */
+ fp_msg ("Error: ambiguous input file name. Which file should be unpacked?:\n ");
+ fp_msg (infits); fp_msg ("\n ");
+ fp_msg (infits); fp_msg (".fz\n");
+ fp_noop (); exit (-1);
+ } else {
+ infits[namelen] = '\0'; /* remove the .fz suffix */
+ }
+ }
+ }
+
+ /* if writing to stdout, then we are all done */
+ if (fpptr->to_stdout) {
+ continue;
+ }
+
+ if (fpptr->outfile[0]) { /* user specified output file name */
+ nfiles++;
+ if (nfiles > 1) {
+ fp_msg ("Error: cannot use same output file name for multiple files:\n ");
+ fp_msg (fpptr->outfile);
+ fp_msg ("\n"); fp_noop (); exit (-1);
+ }
+
+ /* check that output file doesn't exist */
+ if (fp_access (fpptr->outfile) == 0) {
+ fp_msg ("Error: output file already exists:\n ");
+ fp_msg (fpptr->outfile);
+ fp_msg ("\n "); fp_noop (); exit (-1);
+ }
+ continue;
+ }
+
+ /* construct output file name to test */
+ if (fpptr->prefix[0]) {
+ if (strlen(fpptr->prefix) + strlen(infits) > SZ_STR - 1) {
+ fp_msg ("Error: output file name for\n "); fp_msg (infits);
+ fp_msg ("\n is too long with the prefix\n"); fp_noop (); exit (-1);
+ }
+ strcat(outfits,fpptr->prefix);
+ }
+
+ /* construct output file name */
+ if (infits[0] == '-') {
+ strcpy(outfits, "output.fits");
+ } else {
+ strcpy(outfits, infits);
+ }
+
+ /* remove .gz suffix, if present (output is not gzipped) */
+ namelen = strlen(outfits);
+ if ( !strcmp(".gz", outfits + namelen - 3) ) {
+ outfits[namelen - 3] = '\0';
+ }
+
+ /* check for .fz suffix that is sometimes required */
+ /* and remove it if present */
+ if (infits[0] != '-') { /* if not reading from stdin stream */
+ namelen = strlen(outfits);
+ if ( !strcmp(".fz", outfits + namelen - 3) ) { /* suffix is present */
+ outfits[namelen - 3] = '\0';
+ } else if (fpptr->delete_suffix) { /* required suffix is missing */
+ fp_msg ("Error: input compressed file "); fp_msg (infits);
+ fp_msg ("\n does not have the default .fz suffix.\n");
+ fp_noop (); exit (-1);
+ }
+ }
+
+ /* if infits != outfits, make sure outfits doesn't already exist */
+ if (strcmp(infits, outfits)) {
+ if (fp_access (outfits) == 0) {
+ fp_msg ("Error: output file already exists:\n "); fp_msg (outfits);
+ fp_msg ("\n "); fp_noop (); exit (-1);
+ }
+ }
+
+ /* if gzipping the output, make sure .gz file doesn't exist */
+ if (fpptr->do_gzip_file) {
+ strcat(outfits, ".gz");
+ if (fp_access (outfits) == 0) {
+ fp_msg ("Error: output file already exists:\n "); fp_msg (outfits);
+ fp_msg ("\n "); fp_noop (); exit (-1);
+ }
+ namelen = strlen(outfits);
+ outfits[namelen - 3] = '\0'; /* remove the .gz suffix again */
+ }
+ } else {
+ /* ********** This section applies to fpack ************ */
+
+ /* check that input file exists */
+ if (infits[0] != '-') { /* if not reading from stdin stream */
+ if (fp_access (infits) != 0) { /* if not, then check if */
+ strcat(infits, ".gz"); /* a gzipped version exsits */
+ if (fp_access (infits) != 0) {
+ namelen = strlen(infits);
+ infits[namelen - 3] = '\0'; /* remove the .gz suffix */
+ fp_msg ("Error: can't find or read input file "); fp_msg (infits);
+ fp_msg ("\n"); fp_noop (); exit (-1);
+ }
+ }
+ }
+
+ /* make sure the file to pack does not already have a .fz suffix */
+ namelen = strlen(infits);
+ if ( !strcmp(".fz", infits + namelen - 3) ) {
+ fp_msg ("Error: fpack input file already has '.fz' suffix\n" ); fp_msg (infits);
+ fp_msg ("\n"); fp_noop (); exit (-1);
+ }
+
+ /* if writing to stdout, or just testing the files, then we are all done */
+ if (fpptr->to_stdout || fpptr->test_all) {
+ continue;
+ }
+
+ /* construct output file name */
+ if (infits[0] == '-') {
+ strcpy(outfits, "input.fits");
+ } else {
+ strcpy(outfits, infits);
+ }
+
+ /* remove .gz suffix, if present (output is not gzipped) */
+ namelen = strlen(outfits);
+ if ( !strcmp(".gz", outfits + namelen - 3) ) {
+ outfits[namelen - 3] = '\0';
+ }
+
+ /* remove .imh suffix (IRAF format image), and replace with .fits */
+ namelen = strlen(outfits);
+ if ( !strcmp(".imh", outfits + namelen - 4) ) {
+ outfits[namelen - 4] = '\0';
+ strcat(outfits, ".fits");
+ }
+
+ /* If not clobbering the input file, add .fz suffix to output name */
+ if (! fpptr->clobber)
+ strcat(outfits, ".fz");
+
+ /* if infits != outfits, make sure outfits doesn't already exist */
+ if (strcmp(infits, outfits)) {
+ if (fp_access (outfits) == 0) {
+ fp_msg ("Error: output file already exists:\n "); fp_msg (outfits);
+ fp_msg ("\n "); fp_noop (); exit (-1);
+ }
+ }
+ } /* end of fpack section */
+ }
+
+ fpptr->preflight_checked++;
+ return(0);
+}
+
+/*--------------------------------------------------------------------------*/
+/* must run fp_preflight() before fp_loop()
+ */
+int fp_loop (int argc, char *argv[], int unpack, fpstate fpvar)
+{
+ char infits[SZ_STR], outfits[SZ_STR];
+ char temp[SZ_STR], answer[30], *cptr;
+ int ii, iarg, islossless, namelen, iraf_infile = 0, status = 0, ifail;
+ FILE *diskfile;
+
+ if (fpvar.initialized != FP_INIT_MAGIC) {
+ fp_msg ("Error: internal initialization error\n"); exit (-1);
+ } else if (! fpvar.preflight_checked) {
+ fp_msg ("Error: internal preflight error\n"); exit (-1);
+ }
+
+ if (fpvar.test_all && fpvar.outfile[0]) {
+ outreport = fopen(fpvar.outfile, "w");
+ fprintf(outreport," Filename Extension BITPIX NAXIS1 NAXIS2 Size N_nulls Minval Maxval Mean Sigm Noise1 Noise2 Noise3 Noise5 T_whole T_rowbyrow ");
+ fprintf(outreport,"[Comp_ratio, Pack_cpu, Unpack_cpu, Lossless readtimes] (repeated for Rice, Hcompress, and GZIP)\n");
+ }
+
+
+ tempfilename[0] = '\0';
+ tempfilename2[0] = '\0';
+ tempfilename3[0] = '\0';
+
+/* set up signal handler to delete temporary file on abort */
+#ifdef SIGINT
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGINT, abort_fpack);
+ }
+#endif
+
+#ifdef SIGTERM
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGTERM, abort_fpack);
+ }
+#endif
+
+#ifdef SIGHUP
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGHUP, abort_fpack);
+ }
+#endif
+
+ for (iarg=fpvar.firstfile; iarg < argc; iarg++) {
+
+ temp[0] = '\0';
+ outfits[0] = '\0';
+ islossless = 1;
+
+ strncpy (infits, argv[iarg], SZ_STR - 1);
+
+ if (unpack) {
+ /* ********** This section applies to funpack ************ */
+
+ /* find input file */
+ if (infits[0] != '-') { /* if not reading from stdin stream */
+ if (fp_access (infits) != 0) { /* if not, then */
+ strcat(infits, ".fz"); /* a .fz version must exsit */
+ }
+ }
+
+ if (fpvar.to_stdout) {
+ strcpy(outfits, "-");
+
+ } else if (fpvar.outfile[0]) { /* user specified output file name */
+ strcpy(outfits, fpvar.outfile);
+
+ } else {
+ /* construct output file name */
+ if (fpvar.prefix[0]) {
+ strcat(outfits,fpvar.prefix);
+ }
+
+ /* construct output file name */
+ if (infits[0] == '-') {
+ strcpy(outfits, "output.fits");
+ } else {
+ strcpy(outfits, infits);
+ }
+
+ /* remove .gz suffix, if present (output is not gzipped) */
+ namelen = strlen(outfits);
+ if ( !strcmp(".gz", outfits + namelen - 3) ) {
+ outfits[namelen - 3] = '\0';
+ }
+
+ /* check for .fz suffix that is sometimes required */
+ /* and remove it if present */
+ namelen = strlen(outfits);
+ if ( !strcmp(".fz", outfits + namelen - 3) ) { /* suffix is present */
+ outfits[namelen - 3] = '\0';
+ }
+ }
+
+ } else {
+ /* ********** This section applies to fpack ************ */
+
+ if (fpvar.to_stdout) {
+ strcpy(outfits, "-");
+ } else if (! fpvar.test_all) {
+
+ /* construct output file name */
+ if (infits[0] == '-') {
+ strcpy(outfits, "input.fits");
+ } else {
+ strcpy(outfits, infits);
+ }
+
+ /* remove .gz suffix, if present (output is not gzipped) */
+ namelen = strlen(outfits);
+ if ( !strcmp(".gz", outfits + namelen - 3) ) {
+ outfits[namelen - 3] = '\0';
+ }
+
+ /* remove .imh suffix (IRAF format image), and replace with .fits */
+ namelen = strlen(outfits);
+ if ( !strcmp(".imh", outfits + namelen - 4) ) {
+ outfits[namelen - 4] = '\0';
+ strcat(outfits, ".fits");
+ iraf_infile = 1; /* this is an IRAF format input file */
+ /* change the output name to "NAME.fits.fz" */
+ }
+
+ /* If not clobbering the input file, add .fz suffix to output name */
+ if (! fpvar.clobber)
+ strcat(outfits, ".fz");
+ }
+ }
+
+ strncpy(temp, outfits, SZ_STR-1);
+
+ if (infits[0] != '-') { /* if not reading from stdin stream */
+ if (!strcmp(infits, outfits) ) { /* are input and output names the same? */
+
+ /* clobber the input file with the output file with the same name */
+ if (! fpvar.clobber) {
+ fp_msg ("\nError: must use -F flag to clobber input file.\n");
+ exit (-1);
+ }
+
+ /* create temporary file name in the output directory (same as input directory)*/
+ fp_tmpnam("Tmp1", infits, outfits);
+
+ strcpy(tempfilename, outfits); /* store temp file name, in case of abort */
+ }
+ }
+
+
+ /* *************** now do the real work ********************* */
+
+ if (fpvar.verbose && ! fpvar.to_stdout)
+ printf("%s ", infits);
+
+ if (fpvar.test_all) { /* compare all the algorithms */
+
+ /* create 2 temporary file names, in the CWD */
+ fp_tmpnam("Tmpfile1", "", tempfilename);
+ fp_tmpnam("Tmpfile2", "", tempfilename2);
+
+ fp_test (infits, tempfilename, tempfilename2, fpvar);
+
+ remove(tempfilename);
+ tempfilename[0] = '\0'; /* clear the temp file name */
+ remove(tempfilename2);
+ tempfilename2[0] = '\0';
+ continue;
+
+ } else if (unpack) {
+ if (fpvar.to_stdout) {
+ /* unpack the input file to the stdout stream */
+ fp_unpack (infits, outfits, fpvar);
+ } else {
+ /* unpack to temporary file, so other tasks can't open it until it is renamed */
+
+ /* create temporary file name, in the output directory */
+ fp_tmpnam("Tmp2", outfits, tempfilename2);
+
+ /* unpack the input file to the temporary file */
+ fp_unpack (infits, tempfilename2, fpvar);
+
+ /* rename the temporary file to it's real name */
+ ifail = rename(tempfilename2, outfits);
+ if (ifail) {
+ fp_msg("Failed to rename temporary file name:\n ");
+ fp_msg(tempfilename2);
+ fp_msg(" -> ");
+ fp_msg(outfits);
+ fp_msg("\n");
+ exit (-1);
+ } else {
+ tempfilename2[0] = '\0'; /* clear temporary file name */
+ }
+ }
+ } else {
+ fp_pack (infits, outfits, fpvar, &islossless);
+ }
+
+ if (fpvar.to_stdout) {
+ continue;
+ }
+
+ /* ********** clobber and/or delete files, if needed ************** */
+
+ if (!strcmp(infits, temp) && fpvar.clobber ) {
+
+ if (!islossless && ! fpvar.do_not_prompt) {
+ fp_msg ("\nFile ");
+ fp_msg (infits);
+ fp_msg ("\nwas compressed with a LOSSY method. Overwrite the\n");
+ fp_msg ("original file with the compressed version? (Y/N) ");
+ fgets(answer, 29, stdin);
+ if (answer[0] != 'Y' && answer[0] != 'y') {
+ fp_msg ("\noriginal file NOT overwritten!\n");
+ remove(outfits);
+ continue;
+ }
+ }
+
+ if (iraf_infile) { /* special case of deleting an IRAF format header and pixel file */
+ if (fits_delete_iraf_file(infits, &status)) {
+ fp_msg("\nError deleting IRAF .imh and .pix files.\n");
+ fp_msg(infits); fp_msg ("\n"); exit (-1);
+ }
+ }
+
+#if defined(unix) || defined(__unix__) || defined(__unix)
+ /* rename clobbers input on Unix platforms */
+ if (rename (outfits, temp) != 0) {
+ fp_msg ("\nError renaming tmp file to ");
+ fp_msg (temp); fp_msg ("\n"); exit (-1);
+ }
+#else
+ /* rename DOES NOT clobber existing files on Windows platforms */
+ /* so explicitly remove any existing file before renaming the file */
+ remove(temp);
+ if (rename (outfits, temp) != 0) {
+ fp_msg ("\nError renaming tmp file to ");
+ fp_msg (temp); fp_msg ("\n"); exit (-1);
+ }
+#endif
+
+ tempfilename[0] = '\0'; /* clear temporary file name */
+ strcpy(outfits, temp);
+
+ } else if (fpvar.clobber || fpvar.delete_input) { /* delete the input file */
+ if (!islossless && !fpvar.do_not_prompt) { /* user did not turn off delete prompt */
+ fp_msg ("\nFile ");
+ fp_msg (infits);
+ fp_msg ("\nwas compressed with a LOSSY method. \n");
+ fp_msg ("Delete the original file? (Y/N) ");
+ fgets(answer, 29, stdin);
+ if (answer[0] != 'Y' && answer[0] != 'y') { /* user abort */
+ fp_msg ("\noriginal file NOT deleted!\n");
+ } else {
+ if (iraf_infile) { /* special case of deleting an IRAF format header and pixel file */
+ if (fits_delete_iraf_file(infits, &status)) {
+ fp_msg("\nError deleting IRAF .imh and .pix files.\n");
+ fp_msg(infits); fp_msg ("\n"); exit (-1);
+ }
+ } else if (remove(infits) != 0) { /* normal case of deleting input FITS file */
+ fp_msg ("\nError deleting input file ");
+ fp_msg (infits); fp_msg ("\n"); exit (-1);
+ }
+ }
+ } else { /* user said don't prompt, so just delete the input file */
+ if (iraf_infile) { /* special case of deleting an IRAF format header and pixel file */
+ if (fits_delete_iraf_file(infits, &status)) {
+ fp_msg("\nError deleting IRAF .imh and .pix files.\n");
+ fp_msg(infits); fp_msg ("\n"); exit (-1);
+ }
+ } else if (remove(infits) != 0) { /* normal case of deleting input FITS file */
+ fp_msg ("\nError deleting input file ");
+ fp_msg (infits); fp_msg ("\n"); exit (-1);
+ }
+ }
+ }
+ iraf_infile = 0;
+
+ if (fpvar.do_gzip_file) { /* gzip the output file */
+ strcpy(temp, "gzip -1 ");
+ strcat(temp,outfits);
+ system(temp);
+ strcat(outfits, ".gz"); /* only possibible with funpack */
+ }
+
+ if (fpvar.verbose && ! fpvar.to_stdout)
+ printf("-> %s\n", outfits);
+
+ }
+
+ if (fpvar.test_all && fpvar.outfile[0])
+ fclose(outreport);
+ return(0);
+}
+
+/*--------------------------------------------------------------------------*/
+/* fp_pack assumes the output file does not exist (checked by preflight)
+ */
+int fp_pack (char *infits, char *outfits, fpstate fpvar, int *islossless)
+{
+ fitsfile *infptr, *outfptr;
+ int stat=0;
+
+ fits_open_file (&infptr, infits, READONLY, &stat);
+ if (stat) { fits_report_error (stderr, stat); exit (stat); }
+
+ fits_create_file (&outfptr, outfits, &stat);
+ if (stat) {
+ fp_abort_output(infptr, NULL, stat);
+ }
+
+ fits_set_compression_type (outfptr, fpvar.comptype, &stat);
+ fits_set_lossy_int (outfptr, fpvar.int_to_float, &stat);
+
+ if (fpvar.no_dither)
+ fits_set_quantize_dither(outfptr, -1, &stat);
+
+ fits_set_quantize_level (outfptr, fpvar.quantize_level, &stat);
+ fits_set_hcomp_scale (outfptr, fpvar.scale, &stat);
+ fits_set_hcomp_smooth (outfptr, fpvar.smooth, &stat);
+ fits_set_tile_dim (outfptr, 6, fpvar.ntile, &stat);
+ fits_set_dither_offset(outfptr, fpvar.dither_offset, &stat);
+
+ if (stat) {
+ fp_abort_output(infptr, outfptr, stat);
+ }
+
+
+ while (! stat) {
+
+ /* the lossy_int value may have changed, so reset it for each HDU */
+ fits_set_lossy_int (outfptr, fpvar.int_to_float, &stat);
+
+ fp_pack_hdu (infptr, outfptr, fpvar, islossless, &stat);
+
+ if (fpvar.do_checksums) {
+ fits_write_chksum (outfptr, &stat);
+ }
+
+ fits_movrel_hdu (infptr, 1, NULL, &stat);
+ }
+
+ if (stat == END_OF_FILE) stat = 0;
+
+ /* set checksum for case of newly created primary HDU
+ */
+ if (fpvar.do_checksums) {
+ fits_movabs_hdu (outfptr, 1, NULL, &stat);
+ fits_write_chksum (outfptr, &stat);
+ }
+
+ if (stat) {
+ fp_abort_output(infptr, outfptr, stat);
+ }
+
+ fits_close_file (outfptr, &stat);
+ fits_close_file (infptr, &stat);
+
+ return(0);
+}
+
+/*--------------------------------------------------------------------------*/
+/* fp_unpack assumes the output file does not exist
+ */
+int fp_unpack (char *infits, char *outfits, fpstate fpvar)
+{
+ fitsfile *infptr, *outfptr;
+ int stat=0, hdutype, extnum, single = 0;
+ char *loc, *hduloc, hduname[SZ_STR];
+
+ fits_open_file (&infptr, infits, READONLY, &stat);
+ fits_create_file (&outfptr, outfits, &stat);
+
+ if (fpvar.extname[0]) { /* unpack a list of HDUs? */
+
+ /* move to the first HDU in the list */
+ hduloc = fpvar.extname;
+ loc = strchr(hduloc, ','); /* look for 'comma' delimiter between names */
+
+ if (loc)
+ *loc = '\0'; /* terminate the first name in the string */
+
+ strcpy(hduname, hduloc); /* copy the first name into temporary string */
+
+ if (loc)
+ hduloc = loc + 1; /* advance to the beginning of the next name, if any */
+ else {
+ hduloc += strlen(hduname); /* end of the list */
+ single = 1; /* only 1 HDU is being unpacked */
+ }
+
+ if (isdigit( (int) hduname[0]) ) {
+ extnum = strtol(hduname, &loc, 10); /* read the string as an integer */
+
+ /* check for junk following the integer */
+ if (*loc == '\0' ) /* no junk, so move to this HDU number (+1) */
+ {
+ fits_movabs_hdu(infptr, extnum + 1, &hdutype, &stat); /* move to HDU number */
+ if (hdutype != IMAGE_HDU)
+ stat = NOT_IMAGE;
+
+ } else { /* the string is not an integer, so must be the column name */
+ hdutype = IMAGE_HDU;
+ fits_movnam_hdu(infptr, hdutype, hduname, 0, &stat);
+ }
+ }
+ else
+ {
+ /* move to the named image extension */
+ hdutype = IMAGE_HDU;
+ fits_movnam_hdu(infptr, hdutype, hduname, 0, &stat);
+ }
+ }
+
+ if (stat) {
+ fp_msg ("Unable to find and move to extension '");
+ fp_msg(hduname);
+ fp_msg("'\n");
+ fp_abort_output(infptr, outfptr, stat);
+ }
+
+ while (! stat) {
+
+ if (single)
+ stat = -1; /* special status flag to force output primary array */
+
+ fp_unpack_hdu (infptr, outfptr, fpvar, &stat);
+
+ if (fpvar.do_checksums) {
+ fits_write_chksum (outfptr, &stat);
+ }
+
+ /* move to the next HDU */
+ if (fpvar.extname[0]) { /* unpack a list of HDUs? */
+
+ if (!(*hduloc)) {
+ stat = END_OF_FILE; /* we reached the end of the list */
+ } else {
+ /* parse the next HDU name and move to it */
+ loc = strchr(hduloc, ',');
+
+ if (loc) /* look for 'comma' delimiter between names */
+ *loc = '\0'; /* terminate the first name in the string */
+
+ strcpy(hduname, hduloc); /* copy the next name into temporary string */
+
+ if (loc)
+ hduloc = loc + 1; /* advance to the beginning of the next name, if any */
+ else
+ *hduloc = '\0'; /* end of the list */
+
+ if (isdigit( (int) hduname[0]) ) {
+ extnum = strtol(hduname, &loc, 10); /* read the string as an integer */
+
+ /* check for junk following the integer */
+ if (*loc == '\0' ) /* no junk, so move to this HDU number (+1) */
+ {
+ fits_movabs_hdu(infptr, extnum + 1, &hdutype, &stat); /* move to HDU number */
+ if (hdutype != IMAGE_HDU)
+ stat = NOT_IMAGE;
+
+ } else { /* the string is not an integer, so must be the column name */
+ hdutype = IMAGE_HDU;
+ fits_movnam_hdu(infptr, hdutype, hduname, 0, &stat);
+ }
+
+ } else {
+ /* move to the named image extension */
+ hdutype = IMAGE_HDU;
+ fits_movnam_hdu(infptr, hdutype, hduname, 0, &stat);
+ }
+
+ if (stat) {
+ fp_msg ("Unable to find and move to extension '");
+ fp_msg(hduname);
+ fp_msg("'\n");
+ }
+ }
+ } else {
+ /* increment to the next HDU */
+ fits_movrel_hdu (infptr, 1, NULL, &stat);
+ }
+ }
+
+ if (stat == END_OF_FILE) stat = 0;
+
+ /* set checksum for case of newly created primary HDU
+ */
+ if (fpvar.do_checksums) {
+ fits_movabs_hdu (outfptr, 1, NULL, &stat);
+ fits_write_chksum (outfptr, &stat);
+ }
+
+
+ if (stat) {
+ fp_abort_output(infptr, outfptr, stat);
+ }
+
+ fits_close_file (outfptr, &stat);
+ fits_close_file (infptr, &stat);
+
+ return(0);
+}
+
+/*--------------------------------------------------------------------------*/
+/* fp_test assumes the output files do not exist
+ */
+int fp_test (char *infits, char *outfits, char *outfits2, fpstate fpvar)
+{
+ fitsfile *inputfptr, *infptr, *outfptr, *outfptr2, *tempfile;
+
+ long naxes[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
+ long tilesize[9] = {0,1,1,1,1,1,1,1,1};
+ int stat=0, totpix=0, naxis=0, ii, hdutype, bitpix, extnum = 0, len;
+ int tstatus = 0, hdunum, rescale_flag, bpix;
+ char dtype[8], dimen[100];
+ double bscale, rescale, noisemin;
+ long headstart, datastart, dataend;
+ float origdata = 0., whole_cpu, whole_elapse, row_elapse, row_cpu, xbits;
+ FILE *diskfile;
+ /* structure to hold image statistics (defined in fpack.h) */
+ imgstats imagestats;
+
+ fits_open_file (&inputfptr, infits, READONLY, &stat);
+ fits_create_file (&outfptr, outfits, &stat);
+ fits_create_file (&outfptr2, outfits2, &stat);
+
+ if (stat) { fits_report_error (stderr, stat); exit (stat); }
+
+ if (fpvar.no_dither)
+ fits_set_quantize_dither(outfptr, -1, &stat);
+
+ fits_set_quantize_level (outfptr, fpvar.quantize_level, &stat);
+ fits_set_hcomp_scale (outfptr, fpvar.scale, &stat);
+ fits_set_hcomp_smooth (outfptr, fpvar.smooth, &stat);
+ fits_set_tile_dim (outfptr, 6, fpvar.ntile, &stat);
+ fits_set_dither_offset(outfptr, fpvar.dither_offset, &stat);
+
+ while (! stat) {
+
+ rescale_flag = 0;
+
+ /* LOOP OVER EACH HDU */
+ fits_get_hdu_type (inputfptr, &hdutype, &stat);
+
+ if (hdutype == IMAGE_HDU) {
+ fits_get_img_param (inputfptr, 9, &bitpix, &naxis, naxes, &stat);
+ for (totpix=1, ii=0; ii < 9; ii++) totpix *= naxes[ii];
+ }
+
+ if ( !fits_is_compressed_image (inputfptr, &stat) &&
+ hdutype == IMAGE_HDU && naxis != 0 && totpix != 0) {
+
+ /* rescale a scaled integer image to reduce noise? */
+ if (fpvar.rescale_noise != 0. && bitpix > 0 && bitpix < LONGLONG_IMG) {
+
+ tstatus = 0;
+ fits_read_key(inputfptr, TDOUBLE, "BSCALE", &bscale, 0, &tstatus);
+
+ if (tstatus == 0 && bscale != 1.0) { /* image must be scaled */
+
+ if (bitpix == LONG_IMG)
+ fp_i4stat(inputfptr, naxis, naxes, &imagestats, &stat);
+ else
+ fp_i2stat(inputfptr, naxis, naxes, &imagestats, &stat);
+
+ /* use the minimum of the MAD 2nd, 3rd, and 5th order noise estimates */
+ noisemin = imagestats.noise3;
+ if (imagestats.noise2 != 0. && imagestats.noise2 < noisemin) noisemin = imagestats.noise2;
+ if (imagestats.noise5 != 0. && imagestats.noise5 < noisemin) noisemin = imagestats.noise5;
+
+ rescale = noisemin / fpvar.rescale_noise;
+ if (rescale > 1.0) {
+
+ /* all the criteria are met, so create a temporary file that */
+ /* contains a rescaled version of the image, in CWD */
+
+ /* create temporary file name */
+ fp_tmpnam("Tmpfile3", "", tempfilename3);
+
+ fits_create_file(&tempfile, tempfilename3, &stat);
+
+ fits_get_hdu_num(inputfptr, &hdunum);
+ if (hdunum != 1) {
+
+ /* the input hdu is an image extension, so create dummy primary */
+ fits_create_img(tempfile, 8, 0, naxes, &stat);
+ }
+
+ fits_copy_header(inputfptr, tempfile, &stat); /* copy the header */
+
+ /* rescale the data, so that it will compress more efficiently */
+ if (bitpix == LONG_IMG)
+ fp_i4rescale(inputfptr, naxis, naxes, rescale, tempfile, &stat);
+ else
+ fp_i2rescale(inputfptr, naxis, naxes, rescale, tempfile, &stat);
+
+ /* scale the BSCALE keyword by the inverse factor */
+
+ bscale = bscale * rescale;
+ fits_update_key(tempfile, TDOUBLE, "BSCALE", &bscale, 0, &stat);
+
+ /* rescan the header, to reset the actual scaling parameters */
+ fits_set_hdustruc(tempfile, &stat);
+
+ infptr = tempfile;
+ rescale_flag = 1;
+ }
+ }
+ }
+
+ if (!rescale_flag) /* just compress the input file, without rescaling */
+ infptr = inputfptr;
+
+ /* compute basic statistics about the input image */
+ if (bitpix == BYTE_IMG) {
+ bpix = 8;
+ strcpy(dtype, "8 ");
+ fp_i2stat(infptr, naxis, naxes, &imagestats, &stat);
+ } else if (bitpix == SHORT_IMG) {
+ bpix = 16;
+ strcpy(dtype, "16 ");
+ fp_i2stat(infptr, naxis, naxes, &imagestats, &stat);
+ } else if (bitpix == LONG_IMG) {
+ bpix = 32;
+ strcpy(dtype, "32 ");
+ fp_i4stat(infptr, naxis, naxes, &imagestats, &stat);
+ } else if (bitpix == LONGLONG_IMG) {
+ bpix = 64;
+ strcpy(dtype, "64 ");
+ } else if (bitpix == FLOAT_IMG) {
+ bpix = 32;
+ strcpy(dtype, "-32");
+ fp_r4stat(infptr, naxis, naxes, &imagestats, &stat);
+ } else if (bitpix == DOUBLE_IMG) {
+ bpix = 64;
+ strcpy(dtype, "-64");
+ fp_r4stat(infptr, naxis, naxes, &imagestats, &stat);
+ }
+
+ /* use the minimum of the MAD 2nd, 3rd, and 5th order noise estimates */
+ noisemin = imagestats.noise3;
+ if (imagestats.noise2 != 0. && imagestats.noise2 < noisemin) noisemin = imagestats.noise2;
+ if (imagestats.noise5 != 0. && imagestats.noise5 < noisemin) noisemin = imagestats.noise5;
+
+ xbits = log10(noisemin)/.301 + 1.792;
+
+ printf("\n File: %s\n", infits);
+ printf(" Ext BITPIX Dimens. Nulls Min Max Mean Sigma Noise2 Noise3 Noise5 Nbits MaxR\n");
+
+ printf(" %3d %s", extnum, dtype);
+ sprintf(dimen," (%ld", naxes[0]);
+ len =strlen(dimen);
+ for (ii = 1; ii < naxis; ii++) {
+ sprintf(dimen+len,",%ld", naxes[ii]);
+ len =strlen(dimen);
+ }
+ strcat(dimen, ")");
+ printf("%-12s",dimen);
+
+ fits_get_hduaddr(inputfptr, &headstart, &datastart, &dataend, &stat);
+ origdata = (dataend - datastart)/1000000.;
+
+ /* get elapsed and cpu times need to read the uncompressed image */
+ fits_read_image_speed (infptr, &whole_elapse, &whole_cpu,
+ &row_elapse, &row_cpu, &stat);
+
+ printf(" %5d %6.0f %6.0f %8.1f %#8.2g %#7.3g %#7.3g %#7.3g %#5.1f %#6.2f\n",
+ imagestats.n_nulls, imagestats.minval, imagestats.maxval,
+ imagestats.mean, imagestats.sigma,
+ imagestats.noise2, imagestats.noise3, imagestats.noise5, xbits, bpix/xbits);
+
+ printf("\n Type Ratio Size (MB) Pk (Sec) UnPk Exact ElpN CPUN Elp1 CPU1\n");
+
+ printf(" Native %5.3f %5.3f %5.3f %5.3f\n",
+ whole_elapse, whole_cpu, row_elapse, row_cpu);
+
+ if (fpvar.outfile[0]) {
+ fprintf(outreport,
+ " %s %d %d %ld %ld %#10.4g %d %#10.4g %#10.4g %#10.4g %#10.4g %#10.4g %#10.4g %#10.4g %#10.4g %#10.4g %#10.4g %#10.4g %#10.4g",
+ infits, extnum, bitpix, naxes[0], naxes[1], origdata, imagestats.n_nulls, imagestats.minval,
+ imagestats.maxval, imagestats.mean, imagestats.sigma,
+ imagestats.noise1, imagestats.noise2, imagestats.noise3, imagestats.noise5, whole_elapse, whole_cpu, row_elapse, row_cpu);
+ }
+
+ fits_set_lossy_int (outfptr, fpvar.int_to_float, &stat);
+ if ( (bitpix > 0) && (fpvar.int_to_float != 0) ) {
+
+ if ( (noisemin < (fpvar.n3ratio * fpvar.quantize_level) ) ||
+ (noisemin < fpvar.n3min)) {
+
+ /* image contains too little noise to quantize effectively */
+ fits_set_lossy_int (outfptr, 0, &stat);
+ fits_get_hdu_num(infptr, &hdunum);
+
+printf(" HDU %d does not meet noise criteria to be quantized, so losslessly compressed.\n", hdunum);
+ }
+ }
+
+ /* test compression ratio and speed for each algorithm */
+
+ if (fpvar.quantize_level != 0) {
+ fits_set_compression_type (outfptr, RICE_1, &stat);
+ fits_set_tile_dim (outfptr, 6, fpvar.ntile, &stat);
+ fp_test_hdu(infptr, outfptr, outfptr2, fpvar, &stat);
+ }
+
+ if (fpvar.quantize_level != 0) {
+ fits_set_compression_type (outfptr, HCOMPRESS_1, &stat);
+ fits_set_tile_dim (outfptr, 6, fpvar.ntile, &stat);
+ fp_test_hdu(infptr, outfptr, outfptr2, fpvar, &stat);
+ }
+
+ if (fpvar.comptype == GZIP_2) {
+ fits_set_compression_type (outfptr, GZIP_2, &stat);
+ } else {
+ fits_set_compression_type (outfptr, GZIP_1, &stat);
+ }
+ fits_set_tile_dim (outfptr, 6, fpvar.ntile, &stat);
+ fp_test_hdu(infptr, outfptr, outfptr2, fpvar, &stat);
+
+/*
+ fits_set_compression_type (outfptr, BZIP2_1, &stat);
+ fits_set_tile_dim (outfptr, 6, fpvar.ntile, &stat);
+ fp_test_hdu(infptr, outfptr, outfptr2, fpvar, &stat);
+*/
+/*
+ fits_set_compression_type (outfptr, PLIO_1, &stat);
+ fits_set_tile_dim (outfptr, 6, fpvar.ntile, &stat);
+ fp_test_hdu(infptr, outfptr, outfptr2, fpvar, &stat);
+*/
+/*
+ if (bitpix == SHORT_IMG || bitpix == LONG_IMG) {
+ fits_set_compression_type (outfptr, NOCOMPRESS, &stat);
+ fits_set_tile_dim (outfptr, 6, fpvar.ntile, &stat);
+ fp_test_hdu(infptr, outfptr, outfptr2, fpvar, &stat);
+ }
+*/
+ if (fpvar.outfile[0])
+ fprintf(outreport,"\n");
+
+ /* delete the temporary file */
+ if (rescale_flag) {
+ fits_delete_file (infptr, &stat);
+ tempfilename3[0] = '\0'; /* clear the temp filename */
+ }
+ } else if ( (hdutype == BINARY_TBL) && fpvar.do_tables) {
+
+ printf("\n File: %s\n", infits);
+ fp_test_table(inputfptr, outfptr, outfptr2, fpvar, &stat);
+
+ } else {
+ fits_copy_hdu (inputfptr, outfptr, 0, &stat);
+ fits_copy_hdu (inputfptr, outfptr2, 0, &stat);
+ }
+
+ fits_movrel_hdu (inputfptr, 1, NULL, &stat);
+ extnum++;
+ }
+
+
+ if (stat == END_OF_FILE) stat = 0;
+
+ fits_close_file (outfptr2, &stat);
+ fits_close_file (outfptr, &stat);
+ fits_close_file (inputfptr, &stat);
+
+ if (stat) {
+ fits_report_error (stderr, stat);
+ }
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fp_pack_hdu (fitsfile *infptr, fitsfile *outfptr, fpstate fpvar,
+ int *islossless, int *status)
+{
+ fitsfile *tempfile;
+ long naxes[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
+ int stat=0, totpix=0, naxis=0, ii, hdutype, bitpix;
+ int tstatus, hdunum, rescale_flag = 0;
+ double bscale, rescale;
+ FILE *diskfile;
+ char outfits[SZ_STR];
+ long headstart, datastart, dataend, datasize;
+ double noisemin;
+ /* structure to hold image statistics (defined in fpack.h) */
+ imgstats imagestats;
+
+ if (*status) return(0);
+
+ fits_get_hdu_type (infptr, &hdutype, &stat);
+
+ if (hdutype == IMAGE_HDU) {
+ fits_get_img_param (infptr, 9, &bitpix, &naxis, naxes, &stat);
+ for (totpix=1, ii=0; ii < 9; ii++) totpix *= naxes[ii];
+ }
+
+ /* =============================================================== */
+ /* This block is only for beta testing of binary table compression */
+ if (hdutype == BINARY_TBL && fpvar.do_tables) {
+
+ fits_get_hduaddr(infptr, &headstart, &datastart, &dataend, status);
+ datasize = dataend - datastart;
+
+ if (datasize <= 2880) {
+ /* data is less than 1 FITS block in size, so don't compress */
+ fits_copy_hdu (infptr, outfptr, 0, &stat);
+ } else {
+
+ /* transpose the table and compress each column */
+ if (fpvar.do_fast) {
+ fits_compress_table_fast (infptr, outfptr, &stat);
+ } else {
+ fits_compress_table_best (infptr, outfptr, &stat);
+ }
+ }
+
+ return(0);
+ }
+ /* =============================================================== */
+
+ /* If this is not a non-null image HDU, just copy it verbatim */
+ if (fits_is_compressed_image (infptr, &stat) ||
+ hdutype != IMAGE_HDU || naxis == 0 || totpix == 0) {
+ fits_copy_hdu (infptr, outfptr, 0, &stat);
+
+ } else { /* remaining code deals only with IMAGE HDUs */
+
+ /* special case: rescale a scaled integer image to reduce noise? */
+ if (fpvar.rescale_noise != 0. && bitpix > 0 && bitpix < LONGLONG_IMG) {
+
+ tstatus = 0;
+ fits_read_key(infptr, TDOUBLE, "BSCALE", &bscale, 0, &tstatus);
+ if (tstatus == 0 && bscale != 1.0) { /* image must be scaled */
+
+ if (bitpix == LONG_IMG)
+ fp_i4stat(infptr, naxis, naxes, &imagestats, &stat);
+ else
+ fp_i2stat(infptr, naxis, naxes, &imagestats, &stat);
+
+ /* use the minimum of the MAD 2nd, 3rd, and 5th order noise estimates */
+ noisemin = imagestats.noise3;
+ if (imagestats.noise2 != 0. && imagestats.noise2 < noisemin) noisemin = imagestats.noise2;
+ if (imagestats.noise5 != 0. && imagestats.noise5 < noisemin) noisemin = imagestats.noise5;
+
+ rescale = noisemin / fpvar.rescale_noise;
+ if (rescale > 1.0) {
+
+ /* all the criteria are met, so create a temporary file that */
+ /* contains a rescaled version of the image, in output directory */
+
+ /* create temporary file name */
+ fits_file_name(outfptr, outfits, &stat); /* get the output file name */
+ fp_tmpnam("Tmp3", outfits, tempfilename3);
+
+ fits_create_file(&tempfile, tempfilename3, &stat);
+
+ fits_get_hdu_num(infptr, &hdunum);
+ if (hdunum != 1) {
+
+ /* the input hdu is an image extension, so create dummy primary */
+ fits_create_img(tempfile, 8, 0, naxes, &stat);
+ }
+
+ fits_copy_header(infptr, tempfile, &stat); /* copy the header */
+
+ /* rescale the data, so that it will compress more efficiently */
+ if (bitpix == LONG_IMG)
+ fp_i4rescale(infptr, naxis, naxes, rescale, tempfile, &stat);
+ else
+ fp_i2rescale(infptr, naxis, naxes, rescale, tempfile, &stat);
+
+
+ /* scale the BSCALE keyword by the inverse factor */
+
+ bscale = bscale * rescale;
+ fits_update_key(tempfile, TDOUBLE, "BSCALE", &bscale, 0, &stat);
+
+ /* rescan the header, to reset the actual scaling parameters */
+ fits_set_hdustruc(tempfile, &stat);
+
+ fits_img_compress (tempfile, outfptr, &stat);
+ fits_delete_file (tempfile, &stat);
+ tempfilename3[0] = '\0'; /* clear the temp filename */
+ *islossless = 0; /* used a lossy compression method */
+
+ *status = stat;
+ return(0);
+ }
+ }
+ }
+
+ /* if requested to do lossy compression of integer images (by */
+ /* converting to float), then check if this HDU qualifies */
+ if ( (bitpix > 0) && (fpvar.int_to_float != 0) ) {
+
+ if (bitpix >= LONG_IMG)
+ fp_i4stat(infptr, naxis, naxes, &imagestats, &stat);
+ else
+ fp_i2stat(infptr, naxis, naxes, &imagestats, &stat);
+
+ /* use the minimum of the MAD 2nd, 3rd, and 5th order noise estimates */
+ noisemin = imagestats.noise3;
+ if (imagestats.noise2 != 0. && imagestats.noise2 < noisemin) noisemin = imagestats.noise2;
+ if (imagestats.noise5 != 0. && imagestats.noise5 < noisemin) noisemin = imagestats.noise5;
+
+ if ( (noisemin < (fpvar.n3ratio * fpvar.quantize_level) ) ||
+ (imagestats.noise3 < fpvar.n3min)) {
+
+ /* image contains too little noise to quantize effectively */
+ fits_set_lossy_int (outfptr, 0, &stat);
+
+ fits_get_hdu_num(infptr, &hdunum);
+
+printf(" HDU %d does not meet noise criteria to be quantized, so losslessly compressed.\n", hdunum);
+
+ } else {
+ /* compressed image is not identical to original */
+ *islossless = 0;
+ }
+ }
+
+ /* finally, do the actual image compression */
+ fits_img_compress (infptr, outfptr, &stat);
+
+ if (bitpix < 0 ||
+ (fpvar.comptype == HCOMPRESS_1 && fpvar.scale != 0.)) {
+
+ /* compressed image is not identical to original */
+ *islossless = 0;
+ }
+ }
+
+ *status = stat;
+ return(0);
+}
+
+/*--------------------------------------------------------------------------*/
+int fp_unpack_hdu (fitsfile *infptr, fitsfile *outfptr, fpstate fpvar, int *status)
+{
+ int hdutype, lval;
+
+ if (*status > 0) return(0);
+
+ fits_get_hdu_type (infptr, &hdutype, status);
+
+ /* =============================================================== */
+ /* This block is only for beta testing of binary table compression */
+ if (hdutype == BINARY_TBL) {
+
+ fits_read_key(infptr, TLOGICAL, "ZTABLE", &lval, NULL, status);
+
+ if (*status == 0 && lval != 0) {
+ /* uncompress the table */
+ fits_uncompress_table (infptr, outfptr, status);
+
+ } else {
+ if (*status == KEY_NO_EXIST) /* table is not compressed */
+ *status = 0;
+ fits_copy_hdu (infptr, outfptr, 0, status);
+ }
+
+ return(0);
+ /* =============================================================== */
+
+ } else if (fits_is_compressed_image (infptr, status)) {
+ /* uncompress the compressed image HDU */
+ fits_img_decompress (infptr, outfptr, status);
+ } else {
+ /* not a compressed image HDU, so just copy it to the output */
+ fits_copy_hdu (infptr, outfptr, 0, status);
+ }
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fits_read_image_speed (fitsfile *infptr, float *whole_elapse,
+ float *whole_cpu, float *row_elapse, float *row_cpu, int *status)
+{
+ unsigned char *carray, cnull = 0;
+ short *sarray, snull=0;
+ int bitpix, naxis, anynull, *iarray, inull = 0;
+ long ii, naxes[9], fpixel[9]={1,1,1,1,1,1,1,1,1}, lpixel[9]={1,1,1,1,1,1,1,1,1};
+ long inc[9]={1,1,1,1,1,1,1,1,1} ;
+ float *earray, enull = 0, filesize;
+ double *darray, dnull = 0;
+ LONGLONG fpixelll[9];
+
+ if (*status) return(*status);
+
+ fits_get_img_param (infptr, 9, &bitpix, &naxis, naxes, status);
+
+ if (naxis != 2)return(*status);
+
+ lpixel[0] = naxes[0];
+ lpixel[1] = naxes[1];
+
+ /* filesize in MB */
+ filesize = naxes[0] * abs(bitpix) / 8000000. * naxes[1];
+
+ /* measure time required to read the raw image */
+ fits_set_bscale(infptr, 1.0, 0.0, status);
+ *whole_elapse = 0.;
+ *whole_cpu = 0;
+
+ if (bitpix == BYTE_IMG) {
+ carray = calloc(naxes[1]*naxes[0], sizeof(char));
+
+ /* remove any cached uncompressed tile
+ (dangerous to directly modify the structure!) */
+ (infptr->Fptr)->tilerow = 0;
+
+ marktime(status);
+ fits_read_subset(infptr, TBYTE, fpixel, lpixel, inc, &cnull,
+ carray, &anynull, status);
+
+ /* get elapsped times */
+ gettime(whole_elapse, whole_cpu, status);
+
+ /* now read the image again, row by row */
+ if (row_elapse) {
+
+ /* remove any cached uncompressed tile
+ (dangerous to directly modify the structure!) */
+ (infptr->Fptr)->tilerow = 0;
+
+ marktime(status);
+ for (ii = 0; ii < naxes[1]; ii++) {
+ fpixel[1] = ii+1;
+ fits_read_pix(infptr, TBYTE, fpixel, naxes[0], &cnull,
+ carray, &anynull, status);
+ }
+ /* get elapsped times */
+ gettime(row_elapse, row_cpu, status);
+ }
+ free(carray);
+
+ } else if (bitpix == SHORT_IMG) {
+ sarray = calloc(naxes[0]*naxes[1], sizeof(short));
+
+ marktime(status);
+
+ fits_read_subset(infptr, TSHORT, fpixel, lpixel, inc, &snull,
+ sarray, &anynull, status);
+
+ gettime(whole_elapse, whole_cpu, status); /* get elapsped times */
+
+ /* now read the image again, row by row */
+ if (row_elapse) {
+ marktime(status);
+ for (ii = 0; ii < naxes[1]; ii++) {
+ fpixel[1] = ii+1;
+ fits_read_pix(infptr, TSHORT, fpixel, naxes[0], &snull,
+ sarray, &anynull, status);
+ }
+ /* get elapsped times */
+ gettime(row_elapse, row_cpu, status);
+ }
+
+ free(sarray);
+
+ } else if (bitpix == LONG_IMG) {
+ iarray = calloc(naxes[0]*naxes[1], sizeof(int));
+
+ marktime(status);
+
+ fits_read_subset(infptr, TINT, fpixel, lpixel, inc, &inull,
+ iarray, &anynull, status);
+
+ /* get elapsped times */
+ gettime(whole_elapse, whole_cpu, status);
+
+
+ /* now read the image again, row by row */
+ if (row_elapse) {
+ marktime(status);
+ for (ii = 0; ii < naxes[1]; ii++) {
+ fpixel[1] = ii+1;
+ fits_read_pix(infptr, TINT, fpixel, naxes[0], &inull,
+ iarray, &anynull, status);
+ }
+ /* get elapsped times */
+ gettime(row_elapse, row_cpu, status);
+ }
+
+
+ free(iarray);
+
+ } else if (bitpix == FLOAT_IMG) {
+ earray = calloc(naxes[1]*naxes[0], sizeof(float));
+
+ marktime(status);
+
+ fits_read_subset(infptr, TFLOAT, fpixel, lpixel, inc, &enull,
+ earray, &anynull, status);
+
+ /* get elapsped times */
+ gettime(whole_elapse, whole_cpu, status);
+
+ /* now read the image again, row by row */
+ if (row_elapse) {
+ marktime(status);
+ for (ii = 0; ii < naxes[1]; ii++) {
+ fpixel[1] = ii+1;
+ fits_read_pix(infptr, TFLOAT, fpixel, naxes[0], &enull,
+ earray, &anynull, status);
+ }
+ /* get elapsped times */
+ gettime(row_elapse, row_cpu, status);
+ }
+
+ free(earray);
+
+ } else if (bitpix == DOUBLE_IMG) {
+ darray = calloc(naxes[1]*naxes[0], sizeof(double));
+
+ marktime(status);
+
+ fits_read_subset(infptr, TDOUBLE, fpixel, lpixel, inc, &dnull,
+ darray, &anynull, status);
+
+ /* get elapsped times */
+ gettime(whole_elapse, whole_cpu, status);
+
+ /* now read the image again, row by row */
+ if (row_elapse) {
+ marktime(status);
+ for (ii = 0; ii < naxes[1]; ii++) {
+ fpixel[1] = ii+1;
+ fits_read_pix(infptr, TDOUBLE, fpixel, naxes[0], &dnull,
+ darray, &anynull, status);
+ }
+ /* get elapsped times */
+ gettime(row_elapse, row_cpu, status);
+ }
+
+ free(darray);
+ }
+
+ if (whole_elapse) *whole_elapse = *whole_elapse / filesize;
+ if (row_elapse) *row_elapse = *row_elapse / filesize;
+ if (whole_cpu) *whole_cpu = *whole_cpu / filesize;
+ if (row_cpu) *row_cpu = *row_cpu / filesize;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fp_test_hdu (fitsfile *infptr, fitsfile *outfptr, fitsfile *outfptr2,
+ fpstate fpvar, int *status)
+{
+ /* This routine is only used for performance testing of image HDUs. */
+ /* Use fp_test_table for testing binary table HDUs. */
+
+ int stat = 0, hdutype, comptype, noloss = 0;
+ char ctype[20], lossless[4];
+ long headstart, datastart, dataend;
+ float origdata = 0., compressdata = 0.;
+ float compratio = 0., packcpu = 0., unpackcpu = 0., readcpu;
+ float elapse, whole_elapse, row_elapse, whole_cpu, row_cpu;
+ unsigned long datasum1, datasum2, hdusum;
+
+ if (*status) return(0);
+
+ origdata = 0;
+ compressdata = 0;
+ compratio = 0.;
+ lossless[0] = '\0';
+
+ fits_get_compression_type(outfptr, &comptype, &stat);
+ if (comptype == RICE_1)
+ strcpy(ctype, "RICE");
+ else if (comptype == GZIP_1)
+ strcpy(ctype, "GZIP1");
+ else if (comptype == GZIP_2)
+ strcpy(ctype, "GZIP2");/*
+ else if (comptype == BZIP2_1)
+ strcpy(ctype, "BZIP2");
+*/
+ else if (comptype == PLIO_1)
+ strcpy(ctype, "PLIO");
+ else if (comptype == HCOMPRESS_1)
+ strcpy(ctype, "HCOMP");
+ else if (comptype == NOCOMPRESS)
+ strcpy(ctype, "NONE");
+ else {
+ fp_msg ("Error: unsupported image compression type ");
+ *status = DATA_COMPRESSION_ERR;
+ return(0);
+ }
+
+ /* -------------- COMPRESS the image ------------------ */
+
+ marktime(&stat);
+
+ fits_img_compress (infptr, outfptr, &stat);
+
+ /* get elapsped times */
+ gettime(&elapse, &packcpu, &stat);
+
+ /* get elapsed and cpu times need to read the compressed image */
+
+ /* if whole image is compressed as single tile, don't read row by row
+ because it usually takes a very long time
+ */
+ if (fpvar.ntile[1] == 0) {
+ fits_read_image_speed (outfptr, &whole_elapse, &whole_cpu,
+ 0, 0, &stat);
+ row_elapse = 0; row_cpu = 0;
+ } else {
+
+ fits_read_image_speed (outfptr, &whole_elapse, &whole_cpu,
+ &row_elapse, &row_cpu, &stat);
+ }
+
+ if (!stat) {
+
+ /* -------------- UNCOMPRESS the image ------------------ */
+
+ /* remove any cached uncompressed tile
+ (dangerous to directly modify the structure!) */
+ (outfptr->Fptr)->tilerow = 0;
+ marktime(&stat);
+
+ fits_img_decompress (outfptr, outfptr2, &stat);
+
+ /* get elapsped times */
+ gettime(&elapse, &unpackcpu, &stat);
+
+ /* ----------------------------------------------------- */
+
+ /* get sizes of original and compressed images */
+
+ fits_get_hduaddr(infptr, &headstart, &datastart, &dataend, &stat);
+ origdata = (dataend - datastart)/1000000.;
+
+ fits_get_hduaddr(outfptr, &headstart, &datastart, &dataend, &stat);
+ compressdata = (dataend - datastart)/1000000.;
+
+ if (compressdata != 0)
+ compratio = (float) origdata / (float) compressdata;
+
+ /* is this uncompressed image identical to the original? */
+
+ fits_get_chksum(infptr, &datasum1, &hdusum, &stat);
+ fits_get_chksum(outfptr2, &datasum2, &hdusum, &stat);
+
+ if ( datasum1 == datasum2) {
+ strcpy(lossless, "Yes");
+ noloss = 1;
+ } else {
+ strcpy(lossless, "No");
+ }
+
+ printf(" %-5s %6.2f %7.2f ->%7.2f %7.2f %7.2f %s %5.3f %5.3f %5.3f %5.3f\n",
+ ctype, compratio, origdata, compressdata,
+ packcpu, unpackcpu, lossless, whole_elapse, whole_cpu,
+ row_elapse, row_cpu);
+
+
+ if (fpvar.outfile[0]) {
+ fprintf(outreport," %6.3f %5.2f %5.2f %s %7.3f %7.3f %7.3f %7.3f",
+ compratio, packcpu, unpackcpu, lossless, whole_elapse, whole_cpu,
+ row_elapse, row_cpu);
+ }
+
+ /* delete the output HDUs to concerve disk space */
+
+ fits_delete_hdu(outfptr, &hdutype, &stat);
+ fits_delete_hdu(outfptr2, &hdutype, &stat);
+
+ } else {
+ printf(" %-5s (unable to compress image)\n", ctype);
+ }
+
+ /* try to recover from any compression errors */
+ if (stat == DATA_COMPRESSION_ERR) stat = 0;
+
+ *status = stat;
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int fp_test_table (fitsfile *infptr, fitsfile *outfptr, fitsfile *outfptr2,
+ fpstate fpvar, int *status)
+{
+/* this routine is for performance testing of the beta table compression methods */
+
+ int stat = 0, hdutype, comptype, noloss = 0, ii;
+ unsigned int idatasize;
+ char ctype[20], lossless[4];
+ LONGLONG headstart, datastart, dataend, datasize;
+ float origdata = 0., compressdata = 0.;
+ float compratio = 0., packcpu = 0., unpackcpu = 0., readcpu;
+ float elapse, whole_elapse, row_elapse, whole_cpu, row_cpu;
+ float gratio, tratio, sratio, pratio, bratio;
+ float grate, trate, srate, prate, brate, filesize;
+ float rratio, rrate;
+ size_t headsize, hlen, dlen;
+ LONGLONG indatasize, outdatasize;
+ char *ptr, *cptr, *iptr, *cbuff;
+
+ if (*status) return(0);
+
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ datasize = dataend - datastart;
+
+ /* can't compress small tables with less than 2880 bytes of data */
+ if (datasize <= 2880) {
+ return(0);
+ }
+
+ /* 1 gzip raw table ********************************** */
+ marktime(&stat);
+
+ /* get compressed size of the data blocks */
+ fits_gzip_datablocks(infptr, &dlen, &stat);
+
+ /* get elapsped times */
+ gettime(&elapse, &packcpu, &stat);
+
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ indatasize = dataend - datastart;
+
+ outdatasize = dlen;
+
+ gratio = (float) indatasize / (float) outdatasize;
+ grate = packcpu;
+
+ fits_delete_hdu(outfptr, &hdutype, &stat);
+
+ /* 2 transposed table and compress each column with gzip *********** */
+
+ marktime(&stat);
+ fits_transpose_table (infptr, outfptr, &stat);
+
+ /* get elapsped times */
+ gettime(&elapse, &packcpu, &stat);
+
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ indatasize = dataend - datastart;
+ filesize = (float) dataend / 1000000.;
+
+ fits_get_hduaddrll(outfptr, &headstart, &datastart, &dataend, status);
+ outdatasize = dataend - datastart;
+
+ sratio = (float) indatasize / (float) outdatasize;
+ srate = packcpu;
+
+ fits_delete_hdu(outfptr, &hdutype, &stat);
+
+ /* 3 transpose table, shuffle numeric columns, and compress each column with gzip */
+
+ marktime(&stat);
+ fits_compress_table_fast (infptr, outfptr, &stat);
+
+ /* get elapsped times */
+ gettime(&elapse, &packcpu, &stat);
+
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ indatasize = dataend - datastart;
+ filesize = (float) dataend / 1000000.;
+
+ fits_get_hduaddrll(outfptr, &headstart, &datastart, &dataend, status);
+ outdatasize = dataend - datastart;
+
+ pratio = (float) indatasize / (float) outdatasize;
+ prate = packcpu;
+
+ fits_delete_hdu(outfptr, &hdutype, &stat);
+
+ /* 4 transposed, use Rice for integer columns, shuffled gzip for others */
+
+ marktime(&stat);
+ fits_compress_table_rice (infptr, outfptr, &stat);
+
+ /* get elapsped times */
+ gettime(&elapse, &packcpu, &stat);
+
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ indatasize = dataend - datastart;
+ filesize = (float) dataend / 1000000.;
+
+ fits_get_hduaddrll(outfptr, &headstart, &datastart, &dataend, status);
+ outdatasize = dataend - datastart;
+
+ rratio = (float) indatasize / (float) outdatasize;
+ rrate = packcpu;
+
+ fits_delete_hdu(outfptr, &hdutype, &stat);
+
+
+ /* 5 best */
+
+ marktime(&stat);
+ fits_compress_table_best (infptr, outfptr, &stat);
+
+ /* get elapsped times */
+ gettime(&elapse, &packcpu, &stat);
+
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ indatasize = dataend - datastart;
+ filesize = (float) dataend / 1000000.;
+
+ fits_get_hduaddrll(outfptr, &headstart, &datastart, &dataend, status);
+ outdatasize = dataend - datastart;
+
+ bratio = (float) indatasize / (float) outdatasize;
+ brate = packcpu;
+
+ fits_delete_hdu(outfptr, &hdutype, &stat);
+
+ printf("\n Size Raw Transposed Shuffled Rice Best\n");
+ printf(" %5.2fMB %5.2f (%4.2fs) %5.2f (%4.2fs) %5.2f (%4.2fs) %5.2f (%4.2fs) %5.2f (%4.2fs)\n",
+ filesize, gratio, grate, sratio, srate, pratio, prate, rratio, rrate, bratio, brate);
+ printf(" Disk savings ratio: %5.2f %5.2f %5.2f\n",
+ (1. - 1./sratio) / (1. - 1./gratio), (1. - 1./pratio) / (1. - 1./gratio), (1. - 1./bratio) / (1. - 1./gratio));
+
+
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+int marktime(int *status)
+{
+#if defined(unix) || defined(__unix__) || defined(__unix)
+ struct timeval tv;
+/* struct timezone tz; */
+
+/* gettimeofday (&tv, &tz); */
+ gettimeofday (&tv, NULL);
+
+ startsec = tv.tv_sec;
+ startmilli = tv.tv_usec/1000;
+
+ scpu = clock();
+#else
+/* don't support high timing precision on Windows machines */
+ startsec = 0.;
+ startmilli = 0.;
+
+ scpu = clock();
+#endif
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int gettime(float *elapse, float *elapscpu, int *status)
+{
+#if defined(unix) || defined(__unix__) || defined(__unix)
+ struct timeval tv;
+/* struct timezone tz; */
+ int stopmilli;
+ long stopsec;
+
+/* gettimeofday (&tv, &tz); */
+ gettimeofday (&tv, NULL);
+ ecpu = clock();
+
+ stopmilli = tv.tv_usec/1000;
+ stopsec = tv.tv_sec;
+
+ *elapse = (stopsec - startsec) + (stopmilli - startmilli)/1000.;
+ *elapscpu = (ecpu - scpu) * 1.0 / CLOCKTICKS;
+/*
+printf(" (start: %ld + %d), stop: (%ld + %d) elapse: %f\n ",
+startsec,startmilli,stopsec, stopmilli, *elapse);
+*/
+#else
+/* set the elapsed time the same as the CPU time on Windows machines */
+ *elapscpu = (ecpu - scpu) * 1.0 / CLOCKTICKS;
+ *elapse = *elapscpu;
+#endif
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int fp_i2stat(fitsfile *infptr, int naxis, long *naxes, imgstats *imagestats, int *status)
+{
+/*
+ read the central XSAMPLE by YSAMPLE region of pixels in the int*2 image,
+ and then compute basic statistics: min, max, mean, sigma, mean diff, etc.
+*/
+
+ long fpixel[9] = {1,1,1,1,1,1,1,1,1};
+ long lpixel[9] = {1,1,1,1,1,1,1,1,1};
+ long inc[9] = {1,1,1,1,1,1,1,1,1};
+ long i1, i2, npix, ii, ngood, nx, ny;
+ short *intarray, minvalue, maxvalue, nullvalue;
+ int anynul, tstatus, checknull = 1;
+ double mean, sigma, noise1, noise2, noise3, noise5;
+
+ /* select the middle XSAMPLE by YSAMPLE area of the image */
+ i1 = naxes[0]/2 - (XSAMPLE/2 - 1);
+ i2 = naxes[0]/2 + (XSAMPLE/2);
+ if (i1 < 1) i1 = 1;
+ if (i2 > naxes[0]) i2 = naxes[0];
+ fpixel[0] = i1;
+ lpixel[0] = i2;
+ nx = i2 - i1 +1;
+
+ if (naxis > 1) {
+ i1 = naxes[1]/2 - (YSAMPLE/2 - 1);
+ i2 = naxes[1]/2 + (YSAMPLE/2);
+ if (i1 < 1) i1 = 1;
+ if (i2 > naxes[1]) i2 = naxes[1];
+ fpixel[1] = i1;
+ lpixel[1] = i2;
+ }
+ ny = i2 - i1 +1;
+
+ npix = nx * ny;
+
+ /* if there are higher dimensions, read the middle plane of the cube */
+ if (naxis > 2) {
+ fpixel[2] = naxes[2]/2 + 1;
+ lpixel[2] = naxes[2]/2 + 1;
+ }
+
+ intarray = calloc(npix, sizeof(short));
+ if (!intarray) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* turn off any scaling of the integer pixel values */
+ fits_set_bscale(infptr, 1.0, 0.0, status);
+
+ fits_read_subset_sht(infptr, 0, naxis, naxes, fpixel, lpixel, inc,
+ 0, intarray, &anynul, status);
+
+ /* read the null value keyword (BLANK) if present */
+ tstatus = 0;
+ fits_read_key(infptr, TSHORT, "BLANK", &nullvalue, 0, &tstatus);
+ if (tstatus) {
+ nullvalue = 0;
+ checknull = 0;
+ }
+
+ /* compute statistics of the image */
+
+ fits_img_stats_short(intarray, nx, ny, checknull, nullvalue,
+ &ngood, &minvalue, &maxvalue, &mean, &sigma, &noise1, &noise2, &noise3, &noise5, status);
+
+ imagestats->n_nulls = npix - ngood;
+ imagestats->minval = minvalue;
+ imagestats->maxval = maxvalue;
+ imagestats->mean = mean;
+ imagestats->sigma = sigma;
+ imagestats->noise1 = noise1;
+ imagestats->noise2 = noise2;
+ imagestats->noise3 = noise3;
+ imagestats->noise5 = noise5;
+
+ free(intarray);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fp_i4stat(fitsfile *infptr, int naxis, long *naxes, imgstats *imagestats, int *status)
+{
+/*
+ read the central XSAMPLE by YSAMPLE region of pixels in the int*2 image,
+ and then compute basic statistics: min, max, mean, sigma, mean diff, etc.
+*/
+
+ long fpixel[9] = {1,1,1,1,1,1,1,1,1};
+ long lpixel[9] = {1,1,1,1,1,1,1,1,1};
+ long inc[9] = {1,1,1,1,1,1,1,1,1};
+ long i1, i2, npix, ii, ngood, nx, ny;
+ int *intarray, minvalue, maxvalue, nullvalue;
+ int anynul, tstatus, checknull = 1;
+ double mean, sigma, noise1, noise2, noise3, noise5;
+
+ /* select the middle XSAMPLE by YSAMPLE area of the image */
+ i1 = naxes[0]/2 - (XSAMPLE/2 - 1);
+ i2 = naxes[0]/2 + (XSAMPLE/2);
+ if (i1 < 1) i1 = 1;
+ if (i2 > naxes[0]) i2 = naxes[0];
+ fpixel[0] = i1;
+ lpixel[0] = i2;
+ nx = i2 - i1 +1;
+
+ if (naxis > 1) {
+ i1 = naxes[1]/2 - (YSAMPLE/2 - 1);
+ i2 = naxes[1]/2 + (YSAMPLE/2);
+ if (i1 < 1) i1 = 1;
+ if (i2 > naxes[1]) i2 = naxes[1];
+ fpixel[1] = i1;
+ lpixel[1] = i2;
+ }
+ ny = i2 - i1 +1;
+
+ npix = nx * ny;
+
+ /* if there are higher dimensions, read the middle plane of the cube */
+ if (naxis > 2) {
+ fpixel[2] = naxes[2]/2 + 1;
+ lpixel[2] = naxes[2]/2 + 1;
+ }
+
+ intarray = calloc(npix, sizeof(int));
+ if (!intarray) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* turn off any scaling of the integer pixel values */
+ fits_set_bscale(infptr, 1.0, 0.0, status);
+
+ fits_read_subset_int(infptr, 0, naxis, naxes, fpixel, lpixel, inc,
+ 0, intarray, &anynul, status);
+
+ /* read the null value keyword (BLANK) if present */
+ tstatus = 0;
+ fits_read_key(infptr, TINT, "BLANK", &nullvalue, 0, &tstatus);
+ if (tstatus) {
+ nullvalue = 0;
+ checknull = 0;
+ }
+
+ /* compute statistics of the image */
+
+ fits_img_stats_int(intarray, nx, ny, checknull, nullvalue,
+ &ngood, &minvalue, &maxvalue, &mean, &sigma, &noise1, &noise2, &noise3, &noise5, status);
+
+ imagestats->n_nulls = npix - ngood;
+ imagestats->minval = minvalue;
+ imagestats->maxval = maxvalue;
+ imagestats->mean = mean;
+ imagestats->sigma = sigma;
+ imagestats->noise1 = noise1;
+ imagestats->noise2 = noise2;
+ imagestats->noise3 = noise3;
+ imagestats->noise5 = noise5;
+
+ free(intarray);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fp_r4stat(fitsfile *infptr, int naxis, long *naxes, imgstats *imagestats, int *status)
+{
+/*
+ read the central XSAMPLE by YSAMPLE region of pixels in the int*2 image,
+ and then compute basic statistics: min, max, mean, sigma, mean diff, etc.
+*/
+
+ long fpixel[9] = {1,1,1,1,1,1,1,1,1};
+ long lpixel[9] = {1,1,1,1,1,1,1,1,1};
+ long inc[9] = {1,1,1,1,1,1,1,1,1};
+ long i1, i2, npix, ii, ngood, nx, ny;
+ float *array, minvalue, maxvalue, nullvalue = FLOATNULLVALUE;
+ int anynul,checknull = 1;
+ double mean, sigma, noise1, noise2, noise3, noise5;
+
+ /* select the middle XSAMPLE by YSAMPLE area of the image */
+ i1 = naxes[0]/2 - (XSAMPLE/2 - 1);
+ i2 = naxes[0]/2 + (XSAMPLE/2);
+ if (i1 < 1) i1 = 1;
+ if (i2 > naxes[0]) i2 = naxes[0];
+ fpixel[0] = i1;
+ lpixel[0] = i2;
+ nx = i2 - i1 +1;
+
+ if (naxis > 1) {
+ i1 = naxes[1]/2 - (YSAMPLE/2 - 1);
+ i2 = naxes[1]/2 + (YSAMPLE/2);
+ if (i1 < 1) i1 = 1;
+ if (i2 > naxes[1]) i2 = naxes[1];
+ fpixel[1] = i1;
+ lpixel[1] = i2;
+ }
+ ny = i2 - i1 +1;
+
+ npix = nx * ny;
+
+ /* if there are higher dimensions, read the middle plane of the cube */
+ if (naxis > 2) {
+ fpixel[2] = naxes[2]/2 + 1;
+ lpixel[2] = naxes[2]/2 + 1;
+ }
+
+ array = calloc(npix, sizeof(float));
+ if (!array) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ fits_read_subset_flt(infptr, 0, naxis, naxes, fpixel, lpixel, inc,
+ nullvalue, array, &anynul, status);
+
+ /* are there any null values in the array? */
+ if (!anynul) {
+ nullvalue = 0.;
+ checknull = 0;
+ }
+
+ /* compute statistics of the image */
+
+ fits_img_stats_float(array, nx, ny, checknull, nullvalue,
+ &ngood, &minvalue, &maxvalue, &mean, &sigma, &noise1, &noise2, &noise3, &noise5, status);
+
+ imagestats->n_nulls = npix - ngood;
+ imagestats->minval = minvalue;
+ imagestats->maxval = maxvalue;
+ imagestats->mean = mean;
+ imagestats->sigma = sigma;
+ imagestats->noise1 = noise1;
+ imagestats->noise2 = noise2;
+ imagestats->noise3 = noise3;
+ imagestats->noise5 = noise5;
+
+ free(array);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fp_i2rescale(fitsfile *infptr, int naxis, long *naxes, double rescale,
+ fitsfile *outfptr, int *status)
+{
+/*
+ divide the integer pixel values in the input file by rescale,
+ and write back out to the output file..
+*/
+
+ long ii, jj, nelem = 1, nx, ny;
+ short *intarray, nullvalue;
+ int anynul, tstatus, checknull = 1;
+
+ nx = naxes[0];
+ ny = 1;
+
+ for (ii = 1; ii < naxis; ii++) {
+ ny = ny * naxes[ii];
+ }
+
+ intarray = calloc(nx, sizeof(short));
+ if (!intarray) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* read the null value keyword (BLANK) if present */
+ tstatus = 0;
+ fits_read_key(infptr, TSHORT, "BLANK", &nullvalue, 0, &tstatus);
+ if (tstatus) {
+ checknull = 0;
+ }
+
+ /* turn off any scaling of the integer pixel values */
+ fits_set_bscale(infptr, 1.0, 0.0, status);
+ fits_set_bscale(outfptr, 1.0, 0.0, status);
+
+ for (ii = 0; ii < ny; ii++) {
+
+ fits_read_img_sht(infptr, 1, nelem, nx,
+ 0, intarray, &anynul, status);
+
+ if (checknull) {
+ for (jj = 0; jj < nx; jj++) {
+ if (intarray[jj] != nullvalue)
+ intarray[jj] = NSHRT( (intarray[jj] / rescale) );
+ }
+ } else {
+ for (jj = 0; jj < nx; jj++)
+ intarray[jj] = NSHRT( (intarray[jj] / rescale) );
+ }
+
+ fits_write_img_sht(outfptr, 1, nelem, nx, intarray, status);
+
+ nelem += nx;
+ }
+
+ free(intarray);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fp_i4rescale(fitsfile *infptr, int naxis, long *naxes, double rescale,
+ fitsfile *outfptr, int *status)
+{
+/*
+ divide the integer pixel values in the input file by rescale,
+ and write back out to the output file..
+*/
+
+ long ii, jj, nelem = 1, nx, ny;
+ int *intarray, nullvalue;
+ int anynul, tstatus, checknull = 1;
+
+ nx = naxes[0];
+ ny = 1;
+
+ for (ii = 1; ii < naxis; ii++) {
+ ny = ny * naxes[ii];
+ }
+
+ intarray = calloc(nx, sizeof(int));
+ if (!intarray) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* read the null value keyword (BLANK) if present */
+ tstatus = 0;
+ fits_read_key(infptr, TINT, "BLANK", &nullvalue, 0, &tstatus);
+ if (tstatus) {
+ checknull = 0;
+ }
+
+ /* turn off any scaling of the integer pixel values */
+ fits_set_bscale(infptr, 1.0, 0.0, status);
+ fits_set_bscale(outfptr, 1.0, 0.0, status);
+
+ for (ii = 0; ii < ny; ii++) {
+
+ fits_read_img_int(infptr, 1, nelem, nx,
+ 0, intarray, &anynul, status);
+
+ if (checknull) {
+ for (jj = 0; jj < nx; jj++) {
+ if (intarray[jj] != nullvalue)
+ intarray[jj] = NINT( (intarray[jj] / rescale) );
+ }
+ } else {
+ for (jj = 0; jj < nx; jj++)
+ intarray[jj] = NINT( (intarray[jj] / rescale) );
+ }
+
+ fits_write_img_int(outfptr, 1, nelem, nx, intarray, status);
+
+ nelem += nx;
+ }
+
+ free(intarray);
+ return(*status);
+}
+/* ========================================================================
+ * Signal and error handler.
+ */
+void abort_fpack(int sig)
+{
+ /* clean up by deleting temporary files */
+
+ if (tempfilename[0]) {
+ remove(tempfilename);
+ }
+ if (tempfilename2[0]) {
+ remove(tempfilename2);
+ }
+ if (tempfilename3[0]) {
+ remove(tempfilename3);
+ }
+ exit(-1);
+}
diff --git a/vendor/cfitsio/funpack.c b/vendor/cfitsio/funpack.c
new file mode 100644
index 00000000..49b679c5
--- /dev/null
+++ b/vendor/cfitsio/funpack.c
@@ -0,0 +1,168 @@
+/* FUNPACK
+ * R. Seaman, NOAO
+ * uses fits_img_compress by W. Pence, HEASARC
+ */
+
+#include "fitsio.h"
+#include "fpack.h"
+
+int main (int argc, char *argv[])
+{
+ fpstate fpvar;
+
+ if (argc <= 1) { fu_usage (); fu_hint (); exit (-1); }
+
+ fp_init (&fpvar);
+ fu_get_param (argc, argv, &fpvar);
+
+ if (fpvar.listonly) {
+ fp_list (argc, argv, fpvar);
+
+ } else {
+ fp_preflight (argc, argv, FUNPACK, &fpvar);
+ fp_loop (argc, argv, FUNPACK, fpvar);
+ }
+
+ exit (0);
+}
+
+int fu_get_param (int argc, char *argv[], fpstate *fpptr)
+{
+ int gottype=0, gottile=0, wholetile=0, iarg, len, ndim, ii;
+ char tmp[SZ_STR], tile[SZ_STR];
+
+ if (fpptr->initialized != FP_INIT_MAGIC) {
+ fp_msg ("Error: internal initialization error\n"); exit (-1);
+ }
+
+ tile[0] = 0;
+
+ /* by default, .fz suffix characters to be deleted from compressed file */
+ fpptr->delete_suffix = 1;
+
+ /* flags must come first and be separately specified
+ */
+ for (iarg = 1; iarg < argc; iarg++) {
+ if (argv[iarg][0] == '-' && strlen (argv[iarg]) == 2) {
+
+ if (argv[iarg][1] == 'F') {
+ fpptr->clobber++;
+ fpptr->delete_suffix = 0; /* no suffix in this case */
+
+ } else if (argv[iarg][1] == 'D') {
+ fpptr->delete_input++;
+
+ } else if (argv[iarg][1] == 'P') {
+ if (++iarg >= argc) {
+ fu_usage (); fu_hint (); exit (-1);
+ } else
+ strncpy (fpptr->prefix, argv[iarg], SZ_STR);
+
+ } else if (argv[iarg][1] == 'E') {
+ if (++iarg >= argc) {
+ fu_usage (); fu_hint (); exit (-1);
+ } else
+ strncpy (fpptr->extname, argv[iarg], SZ_STR);
+
+ } else if (argv[iarg][1] == 'S') {
+ fpptr->to_stdout++;
+
+ } else if (argv[iarg][1] == 'L') {
+ fpptr->listonly++;
+
+ } else if (argv[iarg][1] == 'C') {
+ fpptr->do_checksums = 0;
+
+ } else if (argv[iarg][1] == 'H') {
+ fu_help (); exit (0);
+
+ } else if (argv[iarg][1] == 'V') {
+ fp_version (); exit (0);
+
+ } else if (argv[iarg][1] == 'Z') {
+ fpptr->do_gzip_file++;
+
+ } else if (argv[iarg][1] == 'v') {
+ fpptr->verbose = 1;
+
+ } else if (argv[iarg][1] == 'O') {
+ if (++iarg >= argc) {
+ fu_usage (); fu_hint (); exit (-1);
+ } else
+ strncpy (fpptr->outfile, argv[iarg], SZ_STR);
+
+ } else {
+ fp_msg ("Error: unknown command line flag `");
+ fp_msg (argv[iarg]); fp_msg ("'\n");
+ fu_usage (); fu_hint (); exit (-1);
+ }
+
+ } else
+ break;
+ }
+
+ if (fpptr->extname[0] && (fpptr->clobber || fpptr->delete_input)) {
+ fp_msg ("Error: -E option may not be used with -F or -D\n");
+ fu_usage (); exit (-1);
+ }
+
+ if (fpptr->to_stdout && (fpptr->outfile[0] || fpptr->prefix[0]) ) {
+
+ fp_msg ("Error: -S option may not be used with -P or -O\n");
+ fu_usage (); exit (-1);
+ }
+
+ if (fpptr->outfile[0] && fpptr->prefix[0] ) {
+ fp_msg ("Error: -P and -O options may not be used together\n");
+ fu_usage (); exit (-1);
+ }
+
+ if (iarg >= argc) {
+ fp_msg ("Error: no FITS files to uncompress\n");
+ fu_usage (); exit (-1);
+ } else
+ fpptr->firstfile = iarg;
+
+ return(0);
+}
+
+int fu_usage (void)
+{
+ fp_msg ("usage: funpack [-E <HDUlist>] [-P <pre>] [-O <name>] [-Z] -v <FITS>\n");
+ fp_msg ("more: [-F] [-D] [-S] [-L] [-C] [-H] [-V] \n");
+ return(0);
+}
+
+int fu_hint (void)
+{
+ fp_msg (" `funpack -H' for help\n");
+ return(0);
+}
+
+int fu_help (void)
+{
+fp_msg ("funpack, decompress fpacked files. Version ");
+fp_version ();
+fu_usage ();
+fp_msg ("\n");
+
+fp_msg ("Flags must be separate and appear before filenames:\n");
+fp_msg (" -E <HDUlist> Unpack only the list of HDU names or numbers in the file.\n");
+fp_msg (" -P <pre> Prepend <pre> to create new output filenames.\n");
+fp_msg (" -O <name> Specify full output file name.\n");
+fp_msg (" -Z Recompress the output file with host GZIP program.\n");
+fp_msg (" -F Overwrite input file by output file with same name.\n");
+fp_msg (" -D Delete input file after writing output.\n");
+fp_msg (" -S Output uncompressed file to STDOUT file stream.\n");
+fp_msg (" -L List contents, files unchanged.\n");
+
+fp_msg (" -C Don't update FITS checksum keywords.\n");
+
+fp_msg (" -v Verbose mode; list each file as it is processed.\n");
+fp_msg (" -H Show this message.\n");
+fp_msg (" -V Show version number.\n");
+
+fp_msg (" \n<FITS> FITS files to unpack; enter '-' (a hyphen) to read from stdin.\n");
+fp_msg (" Refer to the fpack User's Guide for more extensive help.\n");
+ return(0);
+}
diff --git a/vendor/cfitsio/getcol.c b/vendor/cfitsio/getcol.c
new file mode 100644
index 00000000..f40b91d4
--- /dev/null
+++ b/vendor/cfitsio/getcol.c
@@ -0,0 +1,1055 @@
+
+/* 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) */
+ LONGLONG 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.
+*/
+{
+ LONGLONG tfirstpix[99];
+ int naxis, ii;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+
+ for (ii=0; ii < naxis; ii++)
+ tfirstpix[ii] = firstpix[ii];
+
+ ffgpxvll(fptr, datatype, tfirstpix, nelem, nulval, array, anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpxvll( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ LONGLONG *firstpix, /* I - coord of first pixel to read (1s based) */
+ LONGLONG 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;
+ char cdummy;
+ int nullcheck = 1;
+ LONGLONG naxes[9], trc[9]= {1,1,1,1,1,1,1,1,1};
+ long inc[9]= {1,1,1,1,1,1,1,1,1};
+ LONGLONG 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);
+
+ ffgiszll(fptr, 9, naxes, status);
+
+ if (naxis == 0 || naxes[0] == 0) {
+ *status = BAD_DIMEN;
+ return(*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];
+ trc[ii] = firstpix[ii];
+ }
+ firstelem++;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ /* test for special case of reading an integral number of */
+ /* rows in a 2D or 3D image (which includes reading the whole image */
+
+ if (naxis > 1 && naxis < 4 && firstpix[0] == 1 &&
+ (nelem / naxes[0]) * naxes[0] == nelem) {
+
+ /* calculate coordinate of last pixel */
+ trc[0] = naxes[0]; /* reading whole rows */
+ trc[1] = firstpix[1] + (nelem / naxes[0] - 1);
+ while (trc[1] > naxes[1]) {
+ trc[1] = trc[1] - naxes[1];
+ trc[2] = trc[2] + 1; /* increment to next plane of cube */
+ }
+
+ fits_read_compressed_img(fptr, datatype, firstpix, trc, inc,
+ 1, nulval, array, NULL, anynul, status);
+
+ } else {
+
+ fits_read_compressed_pixels(fptr, datatype, firstelem,
+ nelem, nullcheck, nulval, 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.
+ */
+
+ if (datatype == TBYTE)
+ {
+ if (nulval == 0)
+ ffgclb(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (unsigned char *) array, &cdummy, anynul, status);
+ else
+ ffgclb(fptr, 2, 1, firstelem, nelem, 1, 1, *(unsigned char *) nulval,
+ (unsigned char *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ if (nulval == 0)
+ ffgclsb(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (signed char *) array, &cdummy, anynul, status);
+ else
+ ffgclsb(fptr, 2, 1, firstelem, nelem, 1, 1, *(signed char *) nulval,
+ (signed char *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ if (nulval == 0)
+ ffgclui(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (unsigned short *) array, &cdummy, anynul, status);
+ else
+ ffgclui(fptr, 2, 1, firstelem, nelem, 1, 1, *(unsigned short *) nulval,
+ (unsigned short *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ if (nulval == 0)
+ ffgcli(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (short *) array, &cdummy, anynul, status);
+ else
+ ffgcli(fptr, 2, 1, firstelem, nelem, 1, 1, *(short *) nulval,
+ (short *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ if (nulval == 0)
+ ffgcluk(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (unsigned int *) array, &cdummy, anynul, status);
+ else
+ ffgcluk(fptr, 2, 1, firstelem, nelem, 1, 1, *(unsigned int *) nulval,
+ (unsigned int *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TINT)
+ {
+ if (nulval == 0)
+ ffgclk(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (int *) array, &cdummy, anynul, status);
+ else
+ ffgclk(fptr, 2, 1, firstelem, nelem, 1, 1, *(int *) nulval,
+ (int *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ if (nulval == 0)
+ ffgcluj(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (unsigned long *) array, &cdummy, anynul, status);
+ else
+ ffgcluj(fptr, 2, 1, firstelem, nelem, 1, 1, *(unsigned long *) nulval,
+ (unsigned long *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ if (nulval == 0)
+ ffgclj(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (long *) array, &cdummy, anynul, status);
+ else
+ ffgclj(fptr, 2, 1, firstelem, nelem, 1, 1, *(long *) nulval,
+ (long *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ if (nulval == 0)
+ ffgcljj(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (LONGLONG *) array, &cdummy, anynul, status);
+ else
+ ffgcljj(fptr, 2, 1, firstelem, nelem, 1, 1, *(LONGLONG *) nulval,
+ (LONGLONG *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ if (nulval == 0)
+ ffgcle(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (float *) array, &cdummy, anynul, status);
+ else
+ ffgcle(fptr, 2, 1, firstelem, nelem, 1, 1, *(float *) nulval,
+ (float *) array, &cdummy, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ if (nulval == 0)
+ ffgcld(fptr, 2, 1, firstelem, nelem, 1, 1, 0,
+ (double *) array, &cdummy, anynul, status);
+ else
+ ffgcld(fptr, 2, 1, firstelem, nelem, 1, 1, *(double *) nulval,
+ (double *) array, &cdummy, 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) */
+ LONGLONG 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.
+*/
+{
+ LONGLONG tfirstpix[99];
+ int naxis, ii;
+
+ if (*status > 0 || nelem == 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+
+ for (ii=0; ii < naxis; ii++)
+ tfirstpix[ii] = firstpix[ii];
+
+ ffgpxfll(fptr, datatype, tfirstpix, nelem, array, nullarray, anynul, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgpxfll( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ LONGLONG *firstpix, /* I - coord of first pixel to read (1s based) */
+ LONGLONG 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;
+ int nullcheck = 2;
+ LONGLONG naxes[9];
+ LONGLONG 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);
+ ffgiszll(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++;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ fits_read_compressed_pixels(fptr, datatype, firstelem, nelem,
+ nullcheck, NULL, array, nullarray, 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.
+ */
+
+ if (datatype == TBYTE)
+ {
+ ffgclb(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (unsigned char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffgclsb(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (signed char *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffgclui(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (unsigned short *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffgcli(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (short *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TUINT)
+ {
+ ffgcluk(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (unsigned int *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffgclk(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (int *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TULONG)
+ {
+ ffgcluj(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (unsigned long *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TLONG)
+ {
+ ffgclj(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (long *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffgcljj(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (LONGLONG *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ ffgcle(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (float *) array, nullarray, anynul, status);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ ffgcld(fptr, 2, 1, firstelem, nelem, 1, 2, 0,
+ (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, ii;
+ long naxes[9];
+ LONGLONG nelem = 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);
+
+ /* test for the important special case where we are reading the whole image */
+ /* this is only useful for images that are not tile-compressed */
+ if (!fits_is_compressed_image(fptr, status)) {
+ for (ii = 0; ii < naxis; ii++) {
+ if (inc[ii] != 1 || blc[ii] !=1 || trc[ii] != naxes[ii])
+ break;
+
+ nelem = nelem * naxes[ii];
+ }
+
+ if (ii == naxis) {
+ /* read the whole image more efficiently */
+ ffgpxv(fptr, datatype, blc, nelem, nulval, array, anynul, status);
+ return(*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 */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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/vendor/cfitsio/getcolb.c b/vendor/cfitsio/getcolb.c
new file mode 100644
index 00000000..9c2746f6
--- /dev/null
+++ b/vendor/cfitsio/getcolb.c
@@ -0,0 +1,2002 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ LONGLONG narray, nfits;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1};
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TBYTE, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TBYTE, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre, ntodo;
+ long ii, xwidth;
+ int convert, nulcheck, readcheck = 0;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ ffgcprll( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status);
+ maxelem = maxelem2;
+
+ /* 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 = (long) minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = (long) minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgclb).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgclb).",
+ dtemp+1., dtemp+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 ffgextn( fitsfile *fptr, /* I - FITS file pointer */
+ LONGLONG offset, /* I - byte offset from start of extension data */
+ LONGLONG nelem, /* I - number of elements to read */
+ void *buffer, /* I - stream of bytes to read */
+ int *status) /* IO - error status */
+/*
+ Read a stream of bytes from the current FITS HDU. This primative routine is mainly
+ for reading non-standard "conforming" extensions and should not be used
+ for standard IMAGE, TABLE or BINTABLE extensions.
+*/
+{
+ 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);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ /* move to write position */
+ ffmbyt(fptr, (fptr->Fptr)->datastart+ offset, IGNORE_EOF, status);
+
+ /* read the buffer */
+ ffgbyt(fptr, nelem, buffer, status);
+
+ 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 */
+ LONGLONG 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 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 == '.' || *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/vendor/cfitsio/getcold.c b/vendor/cfitsio/getcold.c
new file mode 100644
index 00000000..cbee5b01
--- /dev/null
+++ b/vendor/cfitsio/getcold.c
@@ -0,0 +1,1677 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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.
+*/
+{
+ LONGLONG nfits, narray;
+ long tablerow, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1};
+ LONGLONG lpixel[3];
+ double nullvalue;
+
+ if (fits_is_compressed_image(fptr, status))
+ {
+ /* this is a compressed image in a binary table */
+
+ lpixel[0] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TDOUBLE, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TDOUBLE, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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( (size_t) (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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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, dtemp;
+ int tcode, hdutype, xcode, decimals, maxelem2;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int convert, nulcheck, readcheck = 0;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) 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 ( ffgcprll( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = (long) minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgcld).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgcld).",
+ dtemp+1., dtemp+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 = (long) (elemnum / repeat);
+ rownum += rowincre;
+ elemnum = elemnum - (rowincre * repeat);
+ }
+ else if (elemnum < 0) /* completed a row; start on a previous row */
+ {
+ rowincre = (long) ((-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 */
+ LONGLONG 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 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 == '.' || *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/vendor/cfitsio/getcole.c b/vendor/cfitsio/getcole.c
new file mode 100644
index 00000000..268c16db
--- /dev/null
+++ b/vendor/cfitsio/getcole.c
@@ -0,0 +1,1680 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ LONGLONG narray, nfits;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1};
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TFLOAT, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TFLOAT, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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( (size_t) (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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int convert, nulcheck, readcheck = 0;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) 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 ( ffgcprll( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = (long) minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgcle).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgcle).",
+ dtemp+1., dtemp+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] = (float) (( (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] = (float) (( (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] = (float) (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] = (float) (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] = (float) (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] = (float) (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 */
+ LONGLONG 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] = (float) (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] = (float) (input[ii] * scale + zero);
+ }
+ }
+ }
+ }
+ 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] = (float) (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] = (float) zero;
+ }
+ else
+ output[ii] = (float) (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] = (float) input[ii]; /* copy input to output */
+ }
+ else /* must scale the data */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = (float) (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] = (float) 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] = (float) zero;
+ }
+ else
+ output[ii] = (float) (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 == '.' || *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/vendor/cfitsio/getcoli.c b/vendor/cfitsio/getcoli.c
new file mode 100644
index 00000000..6ad29560
--- /dev/null
+++ b/vendor/cfitsio/getcoli.c
@@ -0,0 +1,1902 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ LONGLONG nfits, narray;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1};
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TSHORT, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TSHORT, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int convert, nulcheck, readcheck = 0;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) 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 ( ffgcprll( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = (long) minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgcli).",
+ dtemp+1, dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgcli).",
+ dtemp+1, dtemp+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 */
+ LONGLONG 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 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 == '.' || *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/vendor/cfitsio/getcolj.c b/vendor/cfitsio/getcolj.c
new file mode 100644
index 00000000..67a6cde7
--- /dev/null
+++ b/vendor/cfitsio/getcolj.c
@@ -0,0 +1,3728 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1}, nfits, narray;
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TLONG, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TLONG, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int convert, nulcheck, readcheck = 0;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) 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 (ffgcprll(fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = (long) minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((LONGLONG)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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgclj).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgclj).",
+ dtemp+1., dtemp+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 */
+ LONGLONG 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++)
+ {
+ 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;
+ }
+ }
+ }
+ }
+ 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 == '.' || *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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1}, nfits, narray;
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TLONGLONG, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TLONGLONG, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int convert, nulcheck, readcheck = 0;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) 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 (ffgcprll(fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = (long) minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgclj).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgclj).",
+ dtemp+1., dtemp+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 == '.' || *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/vendor/cfitsio/getcolk.c b/vendor/cfitsio/getcolk.c
new file mode 100644
index 00000000..3958a598
--- /dev/null
+++ b/vendor/cfitsio/getcolk.c
@@ -0,0 +1,1895 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1}, nfits, narray;
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TINT, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TINT, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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, dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int convert, nulcheck, readcheck = 0;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) 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 ( ffgcprll( fptr, colnum, firstrow, firstelem, nelem, readcheck, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = (long) minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgclk).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgclk).",
+ dtemp+1., dtemp+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 */
+ LONGLONG 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++)
+ {
+ 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;
+ }
+ }
+ }
+ }
+ 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 == '.' || *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/vendor/cfitsio/getcoll.c b/vendor/cfitsio/getcoll.c
new file mode 100644
index 00000000..427247d4
--- /dev/null
+++ b/vendor/cfitsio/getcoll.c
@@ -0,0 +1,614 @@
+/* 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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.
+*/
+{
+ double dtemp;
+ int tcode, maxelem, hdutype, ii, nulcheck;
+ long twidth, incre;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull, rowlen, rownum, remain, next;
+ 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, (size_t) nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( 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 = (long) 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 = (long) minvalue(ntodo, maxelem);
+ ntodo = (long) 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 */
+ {
+ dtemp = (double) next;
+ sprintf(message,
+ "Error reading elements %.0f thruough %.0f of logical array (ffgcl).",
+ dtemp+1., dtemp + 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 = (long) 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) */
+ LONGLONG frow, /* I - first row to write (1 = 1st row) */
+ LONGLONG fbit, /* I - first bit to write (1 = 1st) */
+ LONGLONG 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'.
+*/
+{
+ LONGLONG bstart;
+ long offset, ndone, ii, repeat, bitloc, fbyte;
+ LONGLONG 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 = (long) ((fbit + 7) / 8);
+ bitloc = (long) (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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG 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)",
+ (long) 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG 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)",
+ (long) 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/vendor/cfitsio/getcols.c b/vendor/cfitsio/getcols.c
new file mode 100644
index 00000000..7033d6c9
--- /dev/null
+++ b/vendor/cfitsio/getcols.c
@@ -0,0 +1,835 @@
+/* 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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, dlen;
+ long ii, jj;
+ tcolumn *colptr;
+ char message[FLEN_ERRMSG], *carray, keyname[FLEN_KEYWORD];
+ char cform[20], dispfmt[20], tmpstr[400], *flgarray, tmpnull[80];
+ unsigned char byteval;
+ float *earray;
+ double *darray, tscale = 1.0;
+ LONGLONG *llarray;
+
+ 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((size_t) 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((size_t) (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((size_t) (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 if (tcode == TLONGLONG)
+ {
+ /* allocate memory for the array of LONGLONG values */
+ llarray = (LONGLONG *) calloc((size_t) nelem, sizeof(LONGLONG) );
+ flgarray = (char *) calloc((size_t) nelem, sizeof(char) );
+ dwidth = 20; /* max width of displayed long long integer value */
+
+ if (ffgcfjj(fptr, colnum, firstrow, firstelem, nelem,
+ llarray, flgarray, anynul, status) > 0)
+ {
+ free(flgarray);
+ free(llarray);
+ return(*status);
+ }
+
+ /* write the formated string for each value */
+ if (nulval) {
+ strcpy(tmpnull, nulval);
+ nulwidth = strlen(nulval);
+ } else {
+ strcpy(tmpnull, " ");
+ nulwidth = 1;
+ }
+
+ for (ii = 0; ii < nelem; ii++)
+ {
+ if ( flgarray[ii] )
+ {
+ *array[ii] = '\0';
+ if (dwidth < nulwidth)
+ strncat(array[ii], tmpnull, dwidth);
+ else
+ sprintf(array[ii],"%*s",dwidth,tmpnull);
+
+ if (nultyp == 2)
+ nularray[ii] = 1;
+ }
+ else
+ {
+
+#if defined(_MSC_VER)
+ /* Microsoft Visual C++ 6.0 uses '%I64d' syntax for 8-byte integers */
+ sprintf(tmpstr, "%20I64d", llarray[ii]);
+#elif (USE_LL_SUFFIX == 1)
+ sprintf(tmpstr, "%20lld", llarray[ii]);
+#else
+ sprintf(tmpstr, "%20ld", llarray[ii]);
+#endif
+ *array[ii] = '\0';
+ strncat(array[ii], tmpstr, 20);
+ }
+ }
+
+ free(flgarray);
+ free(llarray); /* free the memory */
+
+ }
+ else
+ {
+ /* allocate memory for the array of double values */
+ darray = (double *) calloc((size_t) 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");
+ }
+ }
+ }
+ }
+
+ if (nulval) {
+ strcpy(tmpnull, nulval);
+ nulwidth = strlen(nulval);
+ } else {
+ strcpy(tmpnull, " ");
+ nulwidth = 1;
+ }
+
+ /* write the formated string for each value */
+ 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], tmpnull, dwidth);
+ else
+ sprintf(array[ii],"%*s",dwidth,tmpnull);
+ }
+ else
+ {
+ if (intcol)
+ sprintf(tmpstr, cform, (int) darray[ii]);
+ else
+ sprintf(tmpstr, cform, darray[ii]);
+
+ /* fill field with '*' if number is too wide */
+ dlen = strlen(tmpstr);
+ if (dlen > dwidth) {
+ memset(tmpstr, '*', dwidth);
+ }
+
+ *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 == TLONGLONG) /* 'K' */
+ *width = 20;
+ 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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.
+*/
+{
+ double dtemp;
+ long nullen;
+ int tcode, maxelem, hdutype, nulcheck;
+ long twidth, incre;
+ long ii, jj, ntodo;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull, rowlen, rownum, remain, next;
+ 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, (size_t) 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 (ffgcprll( 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 = (long) repeat;
+ }
+ else if (tcode == TSTRING)
+ {
+ if (ffgcprll( 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 string length is greater than a FITS block (2880 char) then must */
+ /* only read 1 string at a time, to force reading by ffgbyt instead of */
+ /* ffgbytoff (ffgbytoff can't handle this case) */
+ if (twidth > IOBUFLEN) {
+ maxelem = 1;
+ incre = twidth;
+ repeat = 1;
+ }
+
+ 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)
+ nulcheck = 0; /* calling routine does not want to check for nulls */
+
+ else if (nultyp == 1 && nulval && 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 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ readptr = startpos + ((LONGLONG)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 = (long) (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) {
+
+ if (nulval)
+ strcpy(array[ii], nulval);
+ else
+ strcpy(array[ii], " ");
+
+ } else
+ nularray[ii] = 1;
+ }
+ }
+
+ if (*status > 0) /* test for error during previous read operation */
+ {
+ dtemp = (double) next;
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f of data array (ffpcls).",
+ dtemp+1., dtemp+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/vendor/cfitsio/getcolsb.c b/vendor/cfitsio/getcolsb.c
new file mode 100644
index 00000000..f750681d
--- /dev/null
+++ b/vendor/cfitsio/getcolsb.c
@@ -0,0 +1,1991 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ LONGLONG nfits, narray;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1};
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TSBYTE, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TSBYTE, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int nulcheck, readcheck = 0;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre;
+ 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, (size_t) nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (elemincre < 0)
+ readcheck = -1; /* don't do range checking in this case */
+
+ ffgcprll( 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 = (long) minvalue(remain, maxelem);
+ if (elemincre >= 0)
+ {
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+ }
+ else
+ {
+ ntodo = (long) minvalue(ntodo, (elemnum/(-elemincre) +1));
+ }
+
+ readptr = startpos + (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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgclsb).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgclsb).",
+ dtemp+1., dtemp+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 */
+ LONGLONG 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 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 == '.' || *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/vendor/cfitsio/getcolui.c b/vendor/cfitsio/getcolui.c
new file mode 100644
index 00000000..b98790ab
--- /dev/null
+++ b/vendor/cfitsio/getcolui.c
@@ -0,0 +1,1908 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1}, nfits, narray;
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TUSHORT, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TUSHORT, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int nulcheck;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if ( ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgclui).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgclui).",
+ dtemp+1., dtemp+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 */
+ LONGLONG 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 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 == '.' || *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/vendor/cfitsio/getcoluj.c b/vendor/cfitsio/getcoluj.c
new file mode 100644
index 00000000..79fb4b6d
--- /dev/null
+++ b/vendor/cfitsio/getcoluj.c
@@ -0,0 +1,1902 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1}, nfits, narray;
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TULONG, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TULONG, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int nulcheck;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if ( ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgcluj).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgcluj).",
+ dtemp+1., dtemp+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 */
+ LONGLONG 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 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;
+ }
+ }
+ }
+ }
+ 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 == '.' || *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/vendor/cfitsio/getcoluk.c b/vendor/cfitsio/getcoluk.c
new file mode 100644
index 00000000..4467fcaf
--- /dev/null
+++ b/vendor/cfitsio/getcoluk.c
@@ -0,0 +1,1917 @@
+/* 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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 */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ char cdummy;
+ int nullcheck = 1;
+ long inc[] = {1,1,1};
+ LONGLONG fpixel[] = {1,1,1}, nfits, narray;
+ LONGLONG 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;
+ LONGLONG felem, dsize[10], blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ nullvalue = nulval; /* set local variable */
+
+ fits_read_compressed_img(fptr, TUINT, blcll, trcll, 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];
+ LONGLONG blcll[9], trcll[9];
+ 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 */
+
+ for (ii=0; ii < naxis; ii++) {
+ blcll[ii] = blc[ii];
+ trcll[ii] = trc[ii];
+ }
+
+ fits_read_compressed_img(fptr, TUINT, blcll, trcll, 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to read (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to read (1 = 1st) */
+ LONGLONG 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., dtemp;
+ int tcode, maxelem2, hdutype, xcode, decimals;
+ long twidth, incre;
+ long ii, xwidth, ntodo;
+ int nulcheck;
+ LONGLONG repeat, startpos, elemnum, readptr, tnull;
+ LONGLONG rowlen, rownum, remain, next, rowincre, maxelem;
+ 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, (size_t) nelem); /* initialize nullarray */
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if ( ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0 )
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, ((repeat - elemnum - 1)/elemincre +1));
+
+ readptr = startpos + ((LONGLONG)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, 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 */
+ {
+ dtemp = (double) next;
+ if (hdutype > 0)
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from column %d (ffgcluk).",
+ dtemp+1., dtemp+ntodo, colnum);
+ else
+ sprintf(message,
+ "Error reading elements %.0f thru %.0f from image (ffgcluk).",
+ dtemp+1., dtemp+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 */
+ LONGLONG 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 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;
+ }
+ }
+ }
+ }
+ 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 == '.' || *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/vendor/cfitsio/getkey.c b/vendor/cfitsio/getkey.c
new file mode 100644
index 00000000..09bf13f1
--- /dev/null
+++ b/vendor/cfitsio/getkey.c
@@ -0,0 +1,3242 @@
+/* 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);
+
+ if (nexist)
+ *nexist = (int) (( ((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 = (int) (((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 = (int) (( ((fptr->Fptr)->headend) - ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) ) / 80);
+ *position = (int) (( ((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;
+ LONGLONG 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 = (long) (( (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;
+ LONGLONG 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= (int) ((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 */
+ const 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 = (unsigned char) 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 = (signed char) longval;
+ }
+ }
+ else if (datatype == TUSHORT)
+ {
+ if (ffgkyj(fptr, keyname, &longval, comm, status) <= 0)
+ {
+ if (longval > (long) USHRT_MAX || longval < 0)
+ *status = NUM_OVERFLOW;
+ else
+ *(unsigned short *) value = (unsigned short) 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 = (short) 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 = (unsigned long) doubleval;
+ }
+ }
+ else if (datatype == TLONG)
+ {
+ ffgkyj(fptr, keyname, (long *) value, comm, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffgkyjj(fptr, keyname, (LONGLONG *) 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 */
+ const 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 */
+ if (card)
+ 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 */
+ const 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 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 */
+ }
+ }
+ else if (namelen == 0 && cardlen == 0)
+ {
+ /* matched a blank keyword */
+ return(*status);
+ }
+ }
+ }
+ }
+ }
+
+ 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 ffgstr( fitsfile *fptr, /* I - FITS file pointer */
+ const char *string, /* I - string to match */
+ char *card, /* O - keyword card */
+ int *status) /* IO - error status */
+/*
+ Read (get) the next keyword record that contains the input character string,
+ returning the entire keyword card up to 80 characters long.
+ The returned card value is null terminated with any trailing blank
+ characters removed.
+*/
+{
+ int nkeys, nextkey, ntodo, stringlen;
+ int jj, kk;
+
+ if (*status > 0)
+ return(*status);
+
+ stringlen = strlen(string);
+ if (stringlen > 80) {
+ return(*status = KEY_NO_EXIST); /* matching string is too long to exist */
+ }
+
+ ffghps(fptr, &nkeys, &nextkey, status); /* get no. keywords and position */
+ 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 (strstr(card, string) != 0) {
+ return(*status); /* found the matching string */
+ }
+ }
+
+ 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 */
+ const 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 */
+ const 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 */
+ const 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 fffree( void *value, /* I - pointer to keyword value */
+ int *status) /* IO - error status */
+/*
+ Free the memory that was previously allocated by CFITSIO,
+ such as by ffgkls or fits_hdr2str
+*/
+{
+ if (*status > 0)
+ return(*status);
+
+ if (value)
+ free(value);
+
+ 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 */
+ const 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 */
+ const 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 ffgkyjj( fitsfile *fptr, /* I - FITS file pointer */
+ const char *keyname, /* I - name of keyword to read */
+ LONGLONG *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 */
+ ffc2j(valstring, value, status); /* convert string to value */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffgkye( fitsfile *fptr, /* I - FITS file pointer */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 ffgknjj( fitsfile *fptr, /* I - FITS file pointer */
+ const char *keyname, /* I - root name of keywords to read */
+ int nstart, /* I - starting index number */
+ int nmax, /* I - maximum number of keywords to return */
+ LONGLONG *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 */
+ ffc2j(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 */
+ const 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 */
+ const 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 ffgtdmll(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 */
+ LONGLONG 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 */
+
+ ffdtdmll(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 ((colptr->tdatatype > 0) && ((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 ffdtdmll(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 */
+ LONGLONG 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.
+*/
+{
+ LONGLONG dimsize;
+ LONGLONG totalpix = 1;
+ char *loc, *lastloc, message[81];
+ tcolumn *colptr;
+ double doublesize;
+
+ 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] = 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++;
+
+ /* Read value as a double because the string to 64-bit int function is */
+ /* platform dependent (strtoll, strtol, _atoI64). This still gives */
+ /* about 48 bits of precision, which is plenty for this purpose. */
+
+ doublesize = strtod(loc, &loc);
+ dimsize = (LONGLONG) (doublesize + 0.1);
+
+ 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 ((colptr->tdatatype > 0) && (colptr->trepeat != totalpix))
+ {
+ sprintf(message,
+ "column vector length, %.0f, does not equal TDIMn array size, %.0f",
+ (double) (colptr->trepeat), (double) 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, ii;
+ LONGLONG lldummy;
+ double ddummy;
+ LONGLONG tnaxes[99];
+
+ ffgphd(fptr, maxdim, simple, bitpix, naxis, tnaxes, pcount, gcount, extend,
+ &ddummy, &ddummy, &lldummy, &idummy, status);
+
+ if (naxis && naxes) {
+ for (ii = 0; (ii < *naxis) && (ii < maxdim); ii++)
+ naxes[ii] = (long) tnaxes[ii];
+ } else if (naxes) {
+ for (ii = 0; ii < maxdim; ii++)
+ naxes[ii] = (long) tnaxes[ii];
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffghprll(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 */
+ LONGLONG 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;
+ LONGLONG lldummy;
+ double ddummy;
+
+ ffgphd(fptr, maxdim, simple, bitpix, naxis, naxes, pcount, gcount, extend,
+ &ddummy, &ddummy, &lldummy, &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 fields;
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char xtension[FLEN_VALUE], message[81];
+ LONGLONG llnaxis1, llnaxis2, pcount;
+
+ 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, &llnaxis1, &llnaxis2, &pcount, &fields, status) > 0)
+ return(*status);
+
+ if (naxis1)
+ *naxis1 = (long) llnaxis1;
+
+ if (naxis2)
+ *naxis2 = (long) llnaxis2;
+
+ if (pcount != 0)
+ {
+ sprintf(message, "PCOUNT = %.0f is illegal in ASCII table; must = 0",
+ (double) 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 ffghtbll(fitsfile *fptr, /* I - FITS file pointer */
+ int maxfield, /* I - maximum no. of columns to read; */
+ LONGLONG *naxis1, /* O - length of table row in bytes */
+ LONGLONG *naxis2, /* O - number of rows in the table */
+ int *tfields, /* O - number of columns in the table */
+ char **ttype, /* O - name of each column */
+ LONGLONG *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 fields;
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char xtension[FLEN_VALUE], message[81];
+ LONGLONG llnaxis1, llnaxis2, pcount;
+
+ 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, &llnaxis1, &llnaxis2, &pcount, &fields, status) > 0)
+ return(*status);
+
+ if (naxis1)
+ *naxis1 = llnaxis1;
+
+ if (naxis2)
+ *naxis2 = llnaxis2;
+
+ if (pcount != 0)
+ {
+ sprintf(message, "PCOUNT = %.0f is illegal in ASCII table; must = 0",
+ (double) 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)
+ {
+ ffgknjj(fptr, "TBCOL", 1, maxf, tbcol, &nfound, status);
+
+ if (*status > 0 || nfound != maxf)
+ {
+ ffpmsg(
+ "Required TBCOL keyword(s) not found in ASCII table header (ffghtbll).");
+ 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 (ffghtbll).");
+ 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 fields;
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char xtension[FLEN_VALUE], message[81];
+ LONGLONG naxis1ll, naxis2ll, pcountll;
+
+ 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, &naxis1ll, &naxis2ll, &pcountll, &fields, status) > 0)
+ return(*status);
+
+ if (naxis2)
+ *naxis2 = (long) naxis2ll;
+
+ if (pcount)
+ *pcount = (long) pcountll;
+
+ 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 ffghbnll(fitsfile *fptr, /* I - FITS file pointer */
+ int maxfield, /* I - maximum no. of columns to read; */
+ LONGLONG *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 */
+ LONGLONG *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 fields;
+ char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
+ char xtension[FLEN_VALUE], message[81];
+ LONGLONG naxis1ll, naxis2ll, pcountll;
+
+ 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, &naxis1ll, &naxis2ll, &pcountll, &fields, status) > 0)
+ return(*status);
+
+ if (naxis2)
+ *naxis2 = naxis2ll;
+
+ if (pcount)
+ *pcount = pcountll;
+
+ 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 */
+ LONGLONG 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 */
+ LONGLONG *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;
+ LONGLONG 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)
+ {
+ ffgiszll(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);
+ ffgtknjj(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 (ffc2jj(value, blank, status) > 0) /* convert to LONGLONG */
+ {
+ /* 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*/
+ LONGLONG *rowlen, /* O - length of a table row, in bytes */
+ LONGLONG *nrows, /* O - number of rows in the table */
+ LONGLONG *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 (ffgtknjj(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 (ffgtknjj(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 (ffgtknjj(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 ffgtknjj(fitsfile *fptr, /* I - FITS file pointer */
+ int numkey, /* I - number of the keyword to read */
+ char *name, /* I - expected name of the keyword */
+ LONGLONG *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
+ {
+ ffc2jj(valuestring, value, status); /* convert to integer */
+
+ if (*status > 0 || *value < 0 )
+ *status = NOT_POS_INT;
+ }
+
+ if (*status > 0)
+ {
+ sprintf(message,
+ "ffgtknjj 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;
+ LONGLONG 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);
+ }
+
+ ffghadll(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 */
+ /* (will reallocate it later to minimize the memory size) */
+
+ *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 */
+ /* minimize the allocated memory */
+ *header = (char *) realloc(*header, (*nkeys *80) + 1);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffcnvthdr2str( 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 */
+/*
+ Same as ffhdr2str, except that if the input HDU is a tile compressed image
+ (stored in a binary table) then it will first convert that header back
+ to that of a normal uncompressed FITS image before concatenating the header
+ keyword records.
+*/
+{
+ fitsfile *tempfptr;
+
+ if (*status > 0)
+ return(*status);
+
+ if (fits_is_compressed_image(fptr, status) )
+ {
+ /* this is a tile compressed image, so need to make an uncompressed */
+ /* copy of the image header in memory before concatenating the keywords */
+ if (fits_create_file(&tempfptr, "mem://", status) > 0) {
+ return(*status);
+ }
+
+ if (fits_img_decompress_header(fptr, tempfptr, status) > 0) {
+ fits_delete_file(tempfptr, status);
+ return(*status);
+ }
+
+ ffhdr2str(tempfptr, exclude_comm, exclist, nexc, header, nkeys, status);
+ fits_close_file(tempfptr, status);
+
+ } else {
+ ffhdr2str(fptr, exclude_comm, exclist, nexc, header, nkeys, status);
+ }
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/group.c b/vendor/cfitsio/group.c
new file mode 100644
index 00000000..2883e720
--- /dev/null
+++ b/vendor/cfitsio/group.c
@@ -0,0 +1,6463 @@
+/* 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>
+
+#if defined(WIN32) || defined(__WIN32__)
+#include <direct.h> /* defines the getcwd function on Windows PCs */
+#endif
+
+#if defined(unix) || defined(__unix__) || defined(__unix)
+#include <unistd.h> /* needed for getcwd prototype on unix machines */
+#endif
+
+#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;
+ 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 tmprootname[FLEN_FILENAME], grootname[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; WDP added test for same filename */
+ /* Now, if either the Fptr values are the same, or the root filenames
+ are the same, then assume these refer to the same file.
+ */
+ fits_parse_rootname(tmpfptr->Fptr->filename, tmprootname, status);
+ fits_parse_rootname(gfptr->Fptr->filename, grootname, status);
+
+ if((tmpfptr->Fptr != gfptr->Fptr) &&
+ strncmp(tmprootname, grootname, FLEN_FILENAME))
+ 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 */
+ /* Now, if either the Fptr values are the same, or the root filenames
+ are the same, then assume these refer to the same file.
+ */
+ fits_parse_rootname(tmpfptr->Fptr->filename, tmprootname, status);
+ fits_parse_rootname(gfptr->Fptr->filename, grootname, status);
+
+ if((tmpfptr->Fptr != gfptr->Fptr) &&
+ strncmp(tmprootname, grootname, FLEN_FILENAME))
+ 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 */
+ /* Now, if either the Fptr values are the same, or the root filenames
+ are the same, then assume these refer to the same file.
+ */
+ fits_parse_rootname(tmpfptr->Fptr->filename, tmprootname, status);
+ fits_parse_rootname(gfptr->Fptr->filename, grootname, status);
+
+ if((tmpfptr->Fptr != gfptr->Fptr) &&
+ strncmp(tmprootname, grootname, FLEN_FILENAME))
+ 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 */
+ /* Now, if either the Fptr values are the same, or the root filenames
+ are the same, then assume these refer to the same file.
+ */
+ fits_parse_rootname(tmpfptr->Fptr->filename, tmprootname, status);
+ fits_parse_rootname(gfptr->Fptr->filename, grootname, status);
+
+ if((tmpfptr->Fptr == gfptr->Fptr) ||
+ strncmp(tmprootname, grootname, FLEN_FILENAME) == 0)
+ {
+ /* 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;
+ int hdutype = 0;
+ int index;
+ 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;
+ char mrootname[FLEN_FILENAME], grootname[FLEN_FILENAME];
+
+ 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);
+ /* Now, if either the Fptr values are the same, or the root filenames
+ are the same, then assume these refer to the same file.
+ */
+ fits_parse_rootname(mfptr->Fptr->filename, mrootname, status);
+ fits_parse_rootname(gfptr->Fptr->filename, grootname, status);
+
+ if((mfptr->Fptr != gfptr->Fptr) &&
+ strncmp(mrootname, grootname, FLEN_FILENAME))
+ 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;
+ 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 )
+ {
+
+ /* SPR 3956, add at the end of the table */
+ *status = fits_copy_col(infptr,outfptr,i,newTfields+1,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);
+
+ /* initialize the relative URL string */
+ relURL[0] = 0;
+
+ 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.
+ 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/vendor/cfitsio/group.h b/vendor/cfitsio/group.h
new file mode 100644
index 00000000..f7aae5b1
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/grparser.c b/vendor/cfitsio/grparser.c
new file mode 100644
index 00000000..a5091ea1
--- /dev/null
+++ b/vendor/cfitsio/grparser.c
@@ -0,0 +1,1379 @@
+/* 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 "fitsio2.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 ('\r' == c) continue; /* carriage return character ? Just ignore it */
+ 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, savec;
+ 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 ('D' == ngp_curline.value[nc]) {
+ /* test if template used a 'D' rather than an 'E' as the exponent character (added by WDP in 12/2010) */
+ savec = nc;
+ ngp_curline.value[nc] = 'E';
+ 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;
+ } else { /* no, this is not a real value */
+ ngp_curline.value[savec] = 'D'; /* restore the original D character */
+ }
+ } else {
+ 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, 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);
+
+ 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/vendor/cfitsio/grparser.h b/vendor/cfitsio/grparser.h
new file mode 100644
index 00000000..56bdea03
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/histo.c b/vendor/cfitsio/histo.c
new file mode 100644
index 00000000..6af856f8
--- /dev/null
+++ b/vendor/cfitsio/histo.c
@@ -0,0 +1,2221 @@
+/* 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) || (defaulttype && *wtname) )
+ *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 ffhist2(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)
+{
+ fitsfile *histptr;
+ int bitpix, colnum[4], wtcolnum;
+ long haxes[4];
+ float amin[4], amax[4], binsize[4], weight;
+
+ 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);
+
+ 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);
+
+
+ /* Calculate the binning parameters: */
+ /* columm numbers, axes length, min values, max values, and binsizes. */
+
+ if (fits_calc_binning(
+ *fptr, naxis, colname, minin, maxin, binsizein, minname, maxname, binname,
+ colnum, haxes, amin, amax, binsize, status) > 0)
+ {
+ ffpmsg("failed to determine binning parameters");
+ return(*status);
+ }
+
+ /* get the histogramming weighting factor, if any */
+ if (*wtcol)
+ {
+ /* first, look for a keyword with the weight value */
+ if (ffgky(*fptr, TFLOAT, wtcol, &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, &wtcolnum, status) > 0)
+ {
+ ffpmsg(
+ "keyword or column for histogram weights doesn't exist: ");
+ ffpmsg(wtcol);
+ return(*status);
+ }
+
+ weight = FLOATNULLVALUE;
+ }
+ }
+ else
+ weight = (float) weightin;
+
+ if (weight <= 0. && weight != FLOATNULLVALUE)
+ {
+ ffpmsg("Illegal histogramming weighting factor <= 0.");
+ return(*status = URL_PARSE_ERROR);
+ }
+
+ if (recip && weight != FLOATNULLVALUE)
+ /* take reciprocal of weight */
+ weight = (float) (1.0 / weight);
+
+ /* size of histogram is now known, so create temp output file */
+ if (fits_create_file(&histptr, outfile, status) > 0)
+ {
+ ffpmsg("failed to create temp output file for histogram");
+ return(*status);
+ }
+
+ /* create output FITS image HDU */
+ if (ffcrim(histptr, bitpix, naxis, haxes, status) > 0)
+ {
+ ffpmsg("failed to create output histogram FITS image");
+ return(*status);
+ }
+
+ /* copy header keywords, converting pixel list WCS keywords to image WCS form */
+ if (fits_copy_pixlist2image(*fptr, histptr, 9, naxis, colnum, status) > 0)
+ {
+ ffpmsg("failed to copy pixel list keywords to new histogram header");
+ return(*status);
+ }
+
+ /* if the table columns have no WCS keywords, then write default keywords */
+ fits_write_keys_histo(*fptr, histptr, naxis, colnum, status);
+
+ /* update the WCS keywords for the ref. pixel location, and pixel size */
+ fits_rebin_wcs(histptr, naxis, amin, binsize, status);
+
+ /* now compute the output image by binning the column values */
+ if (fits_make_hist(*fptr, histptr, bitpix, naxis, haxes, colnum, amin, amax,
+ binsize, weight, wtcolnum, recip, selectrow, status) > 0)
+ {
+ ffpmsg("failed to calculate new histogram values");
+ return(*status);
+ }
+
+ /* finally, close the original file and return ptr to the new image */
+ ffclos(*fptr, status);
+ *fptr = histptr;
+
+ 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 = (int) 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] = (float) 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] = (float) 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] = (float) -binsizein[ii]; /* reverse the sign of binsize */
+ else
+ binsize[ii] = (float) binsizein[ii]; /* binsize has the correct sign */
+
+ ibin = (int) binsize[ii];
+ imin = (int) amin[ii];
+ imax = (int) 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] = (float) (haxes[ii] + 1.); /* add 1. instead of .5 to avoid roundoff */
+
+ if (amin[ii] < amax[ii])
+ {
+ amin[ii] = (float) (amin[ii] - 0.5);
+ amax[ii] = (float) (amax[ii] + 0.5);
+ }
+ else
+ {
+ amin[ii] = (float) (amin[ii] + 0.5);
+ amax[ii] = (float) (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] = (long) (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] = (long) 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 = (float) (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);
+ }
+ }
+ }
+ }
+
+ /* convert any TPn_k keywords to PCi_j; the value remains unchanged */
+ /* also convert any TCn_k to CDi_j; the value is modified by n binning size */
+ /* This is a bit of a kludge, and only works for 2D WCS */
+
+ if (histData.haxis == 2) {
+
+ /* PC1_1 */
+ tstatus = 0;
+ ffkeyn("TP", histData.hcolnum[0], card, &tstatus);
+ strcat(card,"_");
+ ffkeyn(card, histData.hcolnum[0], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
+ if (!tstatus)
+ ffpky(histptr, TDOUBLE, "PC1_1", &dvalue, card, &tstatus);
+
+ tstatus = 0;
+ keyname[1] = 'C';
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
+ if (!tstatus) {
+ dvalue *= binsize[0];
+ ffpky(histptr, TDOUBLE, "CD1_1", &dvalue, card, &tstatus);
+ }
+
+ /* PC1_2 */
+ tstatus = 0;
+ ffkeyn("TP", histData.hcolnum[0], card, &tstatus);
+ strcat(card,"_");
+ ffkeyn(card, histData.hcolnum[1], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
+ if (!tstatus)
+ ffpky(histptr, TDOUBLE, "PC1_2", &dvalue, card, &tstatus);
+
+ tstatus = 0;
+ keyname[1] = 'C';
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
+ if (!tstatus) {
+ dvalue *= binsize[0];
+ ffpky(histptr, TDOUBLE, "CD1_2", &dvalue, card, &tstatus);
+ }
+
+ /* PC2_1 */
+ tstatus = 0;
+ ffkeyn("TP", histData.hcolnum[1], card, &tstatus);
+ strcat(card,"_");
+ ffkeyn(card, histData.hcolnum[0], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
+ if (!tstatus)
+ ffpky(histptr, TDOUBLE, "PC2_1", &dvalue, card, &tstatus);
+
+ tstatus = 0;
+ keyname[1] = 'C';
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
+ if (!tstatus) {
+ dvalue *= binsize[1];
+ ffpky(histptr, TDOUBLE, "CD2_1", &dvalue, card, &tstatus);
+ }
+
+ /* PC2_2 */
+ tstatus = 0;
+ ffkeyn("TP", histData.hcolnum[1], card, &tstatus);
+ strcat(card,"_");
+ ffkeyn(card, histData.hcolnum[1], keyname, &tstatus);
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
+ if (!tstatus)
+ ffpky(histptr, TDOUBLE, "PC2_2", &dvalue, card, &tstatus);
+
+ tstatus = 0;
+ keyname[1] = 'C';
+ ffgky(*fptr, TDOUBLE, keyname, &dvalue, card, &tstatus);
+ if (!tstatus) {
+ dvalue *= binsize[1];
+ ffpky(histptr, TDOUBLE, "CD2_2", &dvalue, card, &tstatus);
+ }
+ }
+
+ /* finally, close the original file and return ptr to the new image */
+ ffclos(*fptr, status);
+ *fptr = histptr;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_calc_binning(
+ fitsfile *fptr, /* IO - pointer to table to be binned ; */
+ int naxis, /* I - number of axes/columns in the binned image */
+ char colname[4][FLEN_VALUE], /* I - optional column names */
+ double *minin, /* I - optional lower bound value for each axis */
+ double *maxin, /* I - optional upper bound value, for each axis */
+ double *binsizein, /* I - optional 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 */
+
+ /* The returned parameters for each axis of the n-dimensional histogram are */
+
+ int *colnum, /* O - column numbers, to be binned */
+ long *haxes, /* O - number of bins in each histogram axis */
+ float *amin, /* O - lower bound of the histogram axes */
+ float *amax, /* O - upper bound of the histogram axes */
+ float *binsize, /* O - width of histogram bins/pixels on each axis */
+ int *status)
+/*_
+ Calculate the actual binning parameters, based on various user input
+ options.
+*/
+{
+ tcolumn *colptr;
+ char *cptr, cpref[4][FLEN_VALUE];
+ char errmsg[FLEN_ERRMSG], keyname[FLEN_KEYWORD];
+ int tstatus, ii;
+ int datatype, repeat, imin, imax, ibin, use_datamax = 0;
+ float datamin, datamax;
+
+ /* check inputs */
+
+ if (*status > 0)
+ return(*status);
+
+ if (naxis > 4)
+ {
+ ffpmsg("histograms with more than 4 dimensions are not supported");
+ 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);
+
+ /* ============================================================= */
+ /* The CPREF keyword, if it exists, gives the preferred columns. */
+ /* Otherwise, assume "X", "Y", "Z", and "T" */
+
+ *cpref[0] = '\0';
+ *cpref[1] = '\0';
+ *cpref[2] = '\0';
+ *cpref[3] = '\0';
+
+ 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);
+
+ }
+ }
+ }
+ }
+
+ /* ============================================================= */
+ /* Main Loop for calculating parameters for each column */
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+
+ /* =========================================================== */
+ /* Determine column Number, based on, in order of priority,
+ 1 input column name, or
+ 2 name given by CPREF keyword, or
+ 3 assume X, Y, Z and T for the name
+ */
+
+ 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], colnum+ii, status)
+ > 0)
+ {
+ strcpy(errmsg, "column for histogram axis doesn't exist: ");
+ strcat(errmsg, colname[ii]);
+ ffpmsg(errmsg);
+ return(*status);
+ }
+
+ /* ================================================================ */
+ /* check tha column is not a vector or a string */
+
+ colptr = ((fptr)->Fptr)->tableptr;
+ colptr += (colnum[ii] - 1);
+
+ repeat = (int) 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, colnum[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);
+ }
+
+ /* ================================================================ */
+ /* get the minimum value */
+
+ datamin = FLOATNULLVALUE;
+ datamax = FLOATNULLVALUE;
+
+ 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 (minin[ii] != DOUBLENULLVALUE)
+ {
+ amin[ii] = (float) minin[ii];
+ }
+ else
+ {
+ ffkeyn("TLMIN", colnum[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, colnum[ii], amin+ii, &datamax, status) > 0)
+ {
+ strcpy(errmsg, "Error calculating datamin and datamax for column: ");
+ strcat(errmsg, colname[ii]);
+ ffpmsg(errmsg);
+ return(*status);
+ }
+ }
+ }
+
+ /* ================================================================ */
+ /* get the maximum value */
+
+ 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 (maxin[ii] != DOUBLENULLVALUE)
+ {
+ amax[ii] = (float) maxin[ii];
+ }
+ else
+ {
+ ffkeyn("TLMAX", colnum[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, colnum[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 */
+ }
+
+
+ /* ================================================================ */
+ /* determine binning size and range */
+
+ 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);
+ }
+
+ /* use TDBINn keyword or else 1 if bin size is not given */
+ if (binsizein[ii] != DOUBLENULLVALUE)
+ {
+ binsize[ii] = (float) binsizein[ii];
+ }
+ else
+ {
+ tstatus = 0;
+ ffkeyn("TDBIN", colnum[ii], keyname, &tstatus);
+
+ if (ffgky(fptr, TDOUBLE, keyname, binsizein + ii, NULL, &tstatus) > 0)
+ {
+ /* make at least 10 bins */
+ binsize[ii] = (amax[ii] - amin[ii]) / 10.F ;
+ if (binsize[ii] > 1.)
+ binsize[ii] = 1.; /* use default bin size */
+ }
+ }
+
+ /* ================================================================ */
+ /* if the min is greater than the max, make the binsize negative */
+ if ( (amin[ii] > amax[ii] && binsize[ii] > 0. ) ||
+ (amin[ii] < amax[ii] && binsize[ii] < 0. ) )
+ binsize[ii] = -binsize[ii]; /* reverse the sign of binsize */
+
+
+ ibin = (int) binsize[ii];
+ imin = (int) amin[ii];
+ imax = (int) 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 */
+ if (amin[ii] < amax[ii])
+ {
+ amin[ii] = (float) (amin[ii] - 0.5);
+ amax[ii] = (float) (amax[ii] + 0.5);
+ }
+ else
+ {
+ amin[ii] = (float) (amin[ii] + 0.5);
+ amax[ii] = (float) (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. */
+
+ haxes[ii] = (long) (((amax[ii] - amin[ii]) / binsize[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 */
+ haxes[ii] = (long) ((amax[ii] - amin[ii]) / binsize[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 */
+ }
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_write_keys_histo(
+ fitsfile *fptr, /* I - pointer to table to be binned */
+ fitsfile *histptr, /* I - pointer to output histogram image HDU */
+ int naxis, /* I - number of axes in the histogram image */
+ int *colnum, /* I - column numbers (array length = naxis) */
+ int *status)
+{
+ /* Write default WCS keywords in the output histogram image header */
+ /* if the keywords do not already exist. */
+
+ int ii, tstatus;
+ char keyname[FLEN_KEYWORD], svalue[FLEN_VALUE];
+ double dvalue;
+
+ if (*status > 0)
+ return(*status);
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ /* CTYPEn */
+ tstatus = 0;
+ ffkeyn("CTYPE", ii+1, keyname, &tstatus);
+ ffgky(histptr, TSTRING, keyname, svalue, NULL, &tstatus);
+
+ if (!tstatus) continue; /* keyword already exists, so skip to next axis */
+
+ /* use column name as the axis name */
+ tstatus = 0;
+ ffkeyn("TTYPE", colnum[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);
+ }
+
+ /* CUNITn, use the column units */
+ tstatus = 0;
+ ffkeyn("TUNIT", colnum[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);
+ }
+
+ /* CRPIXn - Reference Pixel choose first pixel in new image as ref. pix. */
+ dvalue = 1.0;
+ tstatus = 0;
+ ffkeyn("CRPIX", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TDOUBLE, keyname, &dvalue, "Reference Pixel", &tstatus);
+
+ /* CRVALn - Value at the location of the reference pixel */
+ dvalue = 1.0;
+ tstatus = 0;
+ ffkeyn("CRVAL", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TDOUBLE, keyname, &dvalue, "Reference Value", &tstatus);
+
+ /* CDELTn - unit size of pixels */
+ dvalue = 1.0;
+ tstatus = 0;
+ dvalue = 1.;
+ ffkeyn("CDELT", ii + 1, keyname, &tstatus);
+ ffpky(histptr, TDOUBLE, keyname, &dvalue, "Pixel size", &tstatus);
+
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_rebin_wcs(
+ fitsfile *fptr, /* I - pointer to table to be binned */
+ int naxis, /* I - number of axes in the histogram image */
+ float *amin, /* I - first pixel include in each axis */
+ float *binsize, /* I - binning factor for each axis */
+ int *status)
+{
+ /* Update the WCS keywords that define the location of the reference */
+ /* pixel, and the pixel size, along each axis. */
+
+ int ii, jj, tstatus, reset ;
+ char keyname[FLEN_KEYWORD], svalue[FLEN_VALUE];
+ double dvalue;
+
+ if (*status > 0)
+ return(*status);
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ reset = 0; /* flag to reset the reference pixel */
+ tstatus = 0;
+ ffkeyn("CRVAL", ii + 1, keyname, &tstatus);
+ /* get previous (pre-binning) value */
+ ffgky(fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+ if (!tstatus && dvalue == 1.0)
+ reset = 1;
+
+ tstatus = 0;
+ /* CRPIXn - update location of the ref. pix. in the binned image */
+ ffkeyn("CRPIX", ii + 1, keyname, &tstatus);
+
+ /* get previous (pre-binning) value */
+ ffgky(fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+
+ if (!tstatus)
+ {
+ if (dvalue != 1.0)
+ reset = 0;
+
+ /* updated value to give pixel location after binning */
+ dvalue = (dvalue - amin[ii]) / ((double) binsize[ii]) + .5;
+
+ fits_modify_key_dbl(fptr, keyname, dvalue, -14, NULL, &tstatus);
+ } else {
+ reset = 0;
+ }
+
+ /* CDELTn - update unit size of pixels */
+ tstatus = 0;
+ ffkeyn("CDELT", ii + 1, keyname, &tstatus);
+
+ /* get previous (pre-binning) value */
+ ffgky(fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+
+ if (!tstatus)
+ {
+ if (dvalue != 1.0)
+ reset = 0;
+
+ /* updated to give post-binning value */
+ dvalue = dvalue * binsize[ii];
+
+ fits_modify_key_dbl(fptr, keyname, dvalue, -14, NULL, &tstatus);
+ }
+ else
+ { /* no CDELTn keyword, so look for a CDij keywords */
+ reset = 0;
+
+ for (jj = 0; jj < naxis; jj++)
+ {
+ tstatus = 0;
+ ffkeyn("CD", jj + 1, svalue, &tstatus);
+ strcat(svalue,"_");
+ ffkeyn(svalue, ii + 1, keyname, &tstatus);
+
+ /* get previous (pre-binning) value */
+ ffgky(fptr, TDOUBLE, keyname, &dvalue, NULL, &tstatus);
+
+ if (!tstatus)
+ {
+ /* updated to give post-binning value */
+ dvalue = dvalue * binsize[ii];
+
+ fits_modify_key_dbl(fptr, keyname, dvalue, -14, NULL, &tstatus);
+ }
+ }
+ }
+
+ if (reset) {
+ /* the original CRPIX, CRVAL, and CDELT keywords were all = 1.0 */
+ /* In this special case, reset the reference pixel to be the */
+ /* first pixel in the array (instead of possibly far off the array) */
+
+ dvalue = 1.0;
+ ffkeyn("CRPIX", ii + 1, keyname, &tstatus);
+ fits_modify_key_dbl(fptr, keyname, dvalue, -14, NULL, &tstatus);
+
+ ffkeyn("CRVAL", ii + 1, keyname, &tstatus);
+ dvalue = amin[ii] + (binsize[ii] / 2.0);
+ fits_modify_key_dbl(fptr, keyname, dvalue, -14, NULL, &tstatus);
+ }
+
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+
+int fits_make_hist(fitsfile *fptr, /* IO - pointer to table with X and Y cols; */
+ fitsfile *histptr, /* I - pointer to output FITS image */
+ int bitpix, /* I - datatype for image: 16, 32, -32, etc */
+ int naxis, /* I - number of axes in the histogram image */
+ long *naxes, /* I - size of axes in the histogram image */
+ int *colnum, /* I - column numbers (array length = naxis) */
+ float *amin, /* I - minimum histogram value, for each axis */
+ float *amax, /* I - maximum histogram value, for each axis */
+ float *binsize, /* I - bin size along each axis */
+ float weight, /* I - binning weighting factor */
+ int wtcolnum, /* 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, imagetype, datatype;
+ int n_cols = 1;
+ long imin, imax, ibin;
+ long offset = 0;
+ long n_per_loop = -1; /* force whole array to be passed at one time */
+ float taxes[4], tmin[4], tmax[4], tbin[4], maxbin[4];
+ histType histData; /* Structure holding histogram info for iterator */
+ iteratorCol imagepars[1];
+
+ /* check inputs */
+
+ if (*status > 0)
+ return(*status);
+
+ if (naxis > 4)
+ {
+ ffpmsg("histogram has more than 4 dimensions");
+ return(*status = BAD_DIMEN);
+ }
+
+ if (bitpix == BYTE_IMG)
+ imagetype = TBYTE;
+ else if (bitpix == SHORT_IMG)
+ imagetype = TSHORT;
+ else if (bitpix == LONG_IMG)
+ imagetype = TINT;
+ else if (bitpix == FLOAT_IMG)
+ imagetype = TFLOAT;
+ else if (bitpix == DOUBLE_IMG)
+ imagetype = TDOUBLE;
+ else
+ return(*status = BAD_DATATYPE);
+
+ /* reset position to the correct HDU if necessary */
+ if ((fptr)->HDUposition != ((fptr)->Fptr)->curhdu)
+ ffmahd(fptr, ((fptr)->HDUposition) + 1, NULL, status);
+
+ histData.weight = weight;
+ histData.wtcolnum = wtcolnum;
+ histData.wtrecip = recip;
+ histData.tblptr = fptr;
+ histData.himagetype = imagetype;
+ histData.haxis = naxis;
+ histData.rowselector = selectrow;
+
+ for (ii = 0; ii < naxis; ii++)
+ {
+ taxes[ii] = (float) naxes[ii];
+ tmin[ii] = amin[ii];
+ tmax[ii] = amax[ii];
+ if ( (amin[ii] > amax[ii] && binsize[ii] > 0. ) ||
+ (amin[ii] < amax[ii] && binsize[ii] < 0. ) )
+ tbin[ii] = -binsize[ii]; /* reverse the sign of binsize */
+ else
+ tbin[ii] = binsize[ii]; /* binsize has the correct sign */
+
+ imin = (long) tmin[ii];
+ imax = (long) tmax[ii];
+ ibin = (long) tbin[ii];
+
+ /* get the datatype of the column */
+ fits_get_coltype(fptr, colnum[ii], &datatype, NULL, NULL, status);
+
+ if (datatype <= TLONG && (float) imin == tmin[ii] &&
+ (float) imax == tmax[ii] &&
+ (float) ibin == tbin[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. */
+
+ maxbin[ii] = (taxes[ii] + 1.F); /* add 1. instead of .5 to avoid roundoff */
+
+ if (tmin[ii] < tmax[ii])
+ {
+ tmin[ii] = tmin[ii] - 0.5F;
+ tmax[ii] = tmax[ii] + 0.5F;
+ }
+ else
+ {
+ tmin[ii] = tmin[ii] + 0.5F;
+ tmax[ii] = tmax[ii] - 0.5F;
+ }
+ } else { /* not an integer column with integer limits */
+ maxbin[ii] = (tmax[ii] - tmin[ii]) / tbin[ii];
+ }
+ }
+
+ /* Set global variables with histogram parameter values. */
+ /* Use separate scalar variables rather than arrays because */
+ /* it is more efficient when computing the histogram. */
+
+ histData.hcolnum[0] = colnum[0];
+ histData.amin1 = tmin[0];
+ histData.maxbin1 = maxbin[0];
+ histData.binsize1 = tbin[0];
+ histData.haxis1 = (long) taxes[0];
+
+ if (histData.haxis > 1)
+ {
+ histData.hcolnum[1] = colnum[1];
+ histData.amin2 = tmin[1];
+ histData.maxbin2 = maxbin[1];
+ histData.binsize2 = tbin[1];
+ histData.haxis2 = (long) taxes[1];
+
+ if (histData.haxis > 2)
+ {
+ histData.hcolnum[2] = colnum[2];
+ histData.amin3 = tmin[2];
+ histData.maxbin3 = maxbin[2];
+ histData.binsize3 = tbin[2];
+ histData.haxis3 = (long) taxes[2];
+
+ if (histData.haxis > 3)
+ {
+ histData.hcolnum[3] = colnum[3];
+ histData.amin4 = tmin[3];
+ histData.maxbin4 = maxbin[3];
+ histData.binsize4 = tbin[3];
+ histData.haxis4 = (long) taxes[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 */
+ fits_iterate_data(n_cols, imagepars, offset, n_per_loop,
+ ffwritehisto, (void*)&histData, status);
+
+ 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 */
+
+ /* must lock this call in multithreaded environoments because */
+ /* the ffcalchist work routine uses static vaiables that would */
+ /* get clobbered if multiple threads were running at the same time */
+ FFLOCK;
+ fits_iterate_data(ncols, colpars, offset, rows_per_loop,
+ ffcalchist, (void*)histData, &status);
+ FFUNLOCK;
+
+ 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 = (long) 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 = (long) 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 = (long) 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] += (int) histData.weight;
+ else if (histData.himagetype == TSHORT)
+ histData.hist.i[ipix] += (short) 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] += (char) histData.weight;
+ }
+ else if (histData.wtrecip) /* use reciprocal of the weight */
+ {
+ if (histData.himagetype == TINT)
+ histData.hist.j[ipix] += (int) (1./wtcol[ii]);
+ else if (histData.himagetype == TSHORT)
+ histData.hist.i[ipix] += (short) (1./wtcol[ii]);
+ else if (histData.himagetype == TFLOAT)
+ histData.hist.r[ipix] += (float) (1./wtcol[ii]);
+ else if (histData.himagetype == TDOUBLE)
+ histData.hist.d[ipix] += 1./wtcol[ii];
+ else if (histData.himagetype == TBYTE)
+ histData.hist.b[ipix] += (char) (1./wtcol[ii]);
+ }
+ else /* no weights */
+ {
+ if (histData.himagetype == TINT)
+ histData.hist.j[ipix] += (int) wtcol[ii];
+ else if (histData.himagetype == TSHORT)
+ histData.hist.i[ipix] += (short) 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] += (char) wtcol[ii];
+ }
+
+ } /* end of main loop over all rows */
+
+ return(0);
+}
+
diff --git a/vendor/cfitsio/imcompress.c b/vendor/cfitsio/imcompress.c
new file mode 100644
index 00000000..6330bf8d
--- /dev/null
+++ b/vendor/cfitsio/imcompress.c
@@ -0,0 +1,9247 @@
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <math.h>
+# include <ctype.h>
+# include <time.h>
+# include "fitsio2.h"
+
+#define NULL_VALUE -2147483647 /* value used to represent undefined pixels */
+
+/* nearest integer function */
+# define NINT(x) ((x >= 0.) ? (int) (x + 0.5) : (int) (x - 0.5))
+
+/* special quantize level value indicates that floating point image pixels */
+/* should not be quantized and instead losslessly compressed (with GZIP) */
+#define NO_QUANTIZE 9999
+
+
+/* string array for storing the individual column compression stats */
+char results[999][60];
+float trans_ratio[999];
+
+float *fits_rand_value = 0;
+
+int imcomp_write_nocompress_tile(fitsfile *outfptr, long row, int datatype,
+ void *tiledata, long tilelen, int nullcheck, void *nullflagval, int *status);
+int imcomp_convert_tile_tshort(fitsfile *outfptr, void *tiledata, long tilelen,
+ int nullcheck, void *nullflagval, int nullval, int zbitpix, double scale,
+ double zero, double actual_bzero, int *intlength, int *status);
+int imcomp_convert_tile_tushort(fitsfile *outfptr, void *tiledata, long tilelen,
+ int nullcheck, void *nullflagval, int nullval, int zbitpix, double scale,
+ double zero, int *intlength, int *status);
+int imcomp_convert_tile_tint(fitsfile *outfptr, void *tiledata, long tilelen,
+ int nullcheck, void *nullflagval, int nullval, int zbitpix, double scale,
+ double zero, int *intlength, int *status);
+int imcomp_convert_tile_tuint(fitsfile *outfptr, void *tiledata, long tilelen,
+ int nullcheck, void *nullflagval, int nullval, int zbitpix, double scale,
+ double zero, int *intlength, int *status);
+int imcomp_convert_tile_tbyte(fitsfile *outfptr, void *tiledata, long tilelen,
+ int nullcheck, void *nullflagval, int nullval, int zbitpix, double scale,
+ double zero, int *intlength, int *status);
+int imcomp_convert_tile_tsbyte(fitsfile *outfptr, void *tiledata, long tilelen,
+ int nullcheck, void *nullflagval, int nullval, int zbitpix, double scale,
+ double zero, int *intlength, int *status);
+int imcomp_convert_tile_tfloat(fitsfile *outfptr, long row, void *tiledata, long tilelen,
+ long tilenx, long tileny, int nullcheck, void *nullflagval, int nullval, int zbitpix,
+ double scale, double zero, int *intlength, int *flag, double *bscale, double *bzero,int *status);
+int imcomp_convert_tile_tdouble(fitsfile *outfptr, long row, void *tiledata, long tilelen,
+ long tilenx, long tileny, int nullcheck, void *nullflagval, int nullval, int zbitpix,
+ double scale, double zero, int *intlength, int *flag, double *bscale, double *bzero, int *status);
+
+static int unquantize_i1r4(long row,
+ 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 */
+static int unquantize_i2r4(long row,
+ 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 */
+static int unquantize_i4r4(long row,
+ 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 */
+static int unquantize_i1r8(long row,
+ 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 */
+static int unquantize_i2r8(long row,
+ 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 */
+static int unquantize_i4r8(long row,
+ 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 */
+static int imcomp_float2nan(float *indata, long tilelen, int *outdata,
+ float nullflagval, int *status);
+static int imcomp_double2nan(double *indata, long tilelen, LONGLONG *outdata,
+ double nullflagval, int *status);
+static int fits_read_write_compressed_img(fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the array to be returned */
+ LONGLONG *infpixel, /* I - 'bottom left corner' of the subsection */
+ LONGLONG *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 */
+ void *nullval, /* I - value for undefined pixels */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ fitsfile *outfptr, /* I - FITS file pointer */
+ int *status);
+
+static int fits_shuffle_8bytes(char *heap, LONGLONG length, int *status);
+static int fits_shuffle_4bytes(char *heap, LONGLONG length, int *status);
+static int fits_shuffle_2bytes(char *heap, LONGLONG length, int *status);
+static int fits_gzip_heap(fitsfile *infptr, fitsfile *outfptr, int *status);
+static int fits_unshuffle_8bytes(char *heap, LONGLONG length, int *status);
+static int fits_unshuffle_4bytes(char *heap, LONGLONG length, int *status);
+static int fits_unshuffle_2bytes(char *heap, LONGLONG length, int *status);
+static int fits_gunzip_heap(fitsfile *infptr, fitsfile *outfptr, int *status);
+
+/*---------------------------------------------------------------------------*/
+int fits_init_randoms(void) {
+
+/* initialize an array of random numbers */
+
+ int ii;
+ double a = 16807.0;
+ double m = 2147483647.0;
+ double temp, seed;
+
+ FFLOCK;
+
+ if (fits_rand_value) {
+ FFUNLOCK;
+ return(0); /* array is already initialized */
+ }
+
+ /* allocate array for the random number sequence */
+ /* THIS MEMORY IS NEVER FREED */
+ fits_rand_value = calloc(N_RANDOM, sizeof(float));
+
+ if (!fits_rand_value) {
+ FFUNLOCK;
+ return(MEMORY_ALLOCATION);
+ }
+
+ /* We need a portable algorithm that anyone can use to generate this
+ exact same sequence of random number. The C 'rand' function is not
+ suitable because it is not available to Fortran or Java programmers.
+ Instead, use a well known simple algorithm published here:
+ "Random number generators: good ones are hard to find", Communications of the ACM,
+ Volume 31 , Issue 10 (October 1988) Pages: 1192 - 1201
+ */
+
+ /* initialize the random numbers */
+ seed = 1;
+ for (ii = 0; ii < N_RANDOM; ii++) {
+ temp = a * seed;
+ seed = temp -m * ((int) (temp / m) );
+ fits_rand_value[ii] = (float) (seed / m);
+ }
+
+ FFUNLOCK;
+
+ /*
+ IMPORTANT NOTE: the 10000th seed value must have the value 1043618065 if the
+ algorithm has been implemented correctly */
+
+ if ( (int) seed != 1043618065) {
+ ffpmsg("fits_init_randoms generated incorrect random number sequence");
+ return(1);
+ } else {
+ return(0);
+ }
+}
+/*--------------------------------------------------------------------------*/
+void bz_internal_error(int errcode)
+{
+ /* external function declared by the bzip2 code in bzlib_private.h */
+ ffpmsg("bzip2 returned an internal error");
+ ffpmsg("This should never happen");
+ return;
+}
+/*--------------------------------------------------------------------------*/
+int fits_set_compression_type(fitsfile *fptr, /* I - FITS file pointer */
+ int ctype, /* image compression type code; */
+ /* allowed values: RICE_1, GZIP_1, GZIP_2, PLIO_1, */
+ /* HCOMPRESS_1, BZIP2_1, and NOCOMPRESS */
+ 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_quantize_level(fitsfile *fptr, /* I - FITS file pointer */
+ float qlevel, /* floating point quantization level */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies the value of the quantization level, q, 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 (qlevel == 0.)
+ {
+ /* this means don't quantize the floating point values. Instead, */
+ /* the floating point values will be losslessly compressed */
+ (fptr->Fptr)->quantize_level = NO_QUANTIZE;
+ } else {
+
+ (fptr->Fptr)->quantize_level = qlevel;
+
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_set_quantize_dither(fitsfile *fptr, /* I - FITS file pointer */
+ int dither, /* dither type */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies what type of dithering (randomization) should
+ be performed when quantizing floating point images to integer prior to
+ compression. A value of -1 means do no dithering. A value of 0 means
+ used the default SUBTRACTIVE_DITHER_1 (which is equivalent to dither = 1).
+ A value of -1 means do not apply any dither.
+*/
+
+ if (dither == 0) dither = 1;
+ (fptr->Fptr)->request_quantize_dither = dither;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_set_dither_offset(fitsfile *fptr, /* I - FITS file pointer */
+ int offset, /* random dithering offset value (1 to 10000) */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies the value of the offset that should be applied when
+ calculating the random dithering when quantizing floating point iamges.
+ A random offset should be applied to each image to avoid quantization
+ effects when taking the difference of 2 images, or co-adding a set of
+ images. Without this random offset, the corresponding pixel in every image
+ will have exactly the same dithering.
+
+ offset = 0 means use the default random dithering based on system time
+ offset = negative means randomly chose dithering based on 1st tile checksum
+ offset = [1 - 10000] means use that particular dithering pattern
+
+*/
+ /* if positive, ensure that the value is in the range 1 to 10000 */
+ if (offset > 0)
+ (fptr->Fptr)->request_dither_offset = ((offset - 1) % 10000 ) + 1;
+ else
+ (fptr->Fptr)->request_dither_offset = offset;
+
+ 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 IS PROVIDED ONLY FOR BACKWARDS COMPATIBILITY;
+ ALL NEW SOFTWARE SHOULD CALL fits_set_quantize_level INSTEAD
+ ********************************************************************
+ ********************************************************************
+
+ 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.
+
+ Feb 2008: the "noisebits" parameter has been replaced with the more
+ general "quantize level" parameter.
+*/
+ float qlevel;
+
+ if (noisebits < 1 || noisebits > 16)
+ {
+ *status = DATA_COMPRESSION_ERR;
+ return(*status);
+ }
+
+ qlevel = (float) pow (2., (double)noisebits);
+ fits_set_quantize_level(fptr, qlevel, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_set_hcomp_scale(fitsfile *fptr, /* I - FITS file pointer */
+ float scale, /* hcompress scale parameter value */
+ /* (default = 0.) */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies the value of the hcompress scale parameter that
+ 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_hcomp_scale = scale;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_set_hcomp_smooth(fitsfile *fptr, /* I - FITS file pointer */
+ int smooth, /* hcompress smooth parameter value */
+ /* if scale > 1 and smooth != 0, then */
+ /* the image will be smoothed when it is */
+ /* decompressed to remove some of the */
+ /* 'blockiness' in the image produced */
+ /* by the lossy compression */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies the value of the hcompress scale parameter that
+ 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_hcomp_smooth = smooth;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_set_lossy_int(fitsfile *fptr, /* I - FITS file pointer */
+ int lossy_int, /* I - True (!= 0) or False (0) */
+ int *status) /* IO - error status */
+{
+/*
+ This routine specifies whether images with integer pixel values should
+ quantized and compressed the same way float images are compressed.
+ The default is to not do this, and instead apply a lossless compression
+ algorithm to integer images.
+*/
+
+ (fptr->Fptr)->request_lossy_int_compress = lossy_int;
+ 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, GZIP_2, PLIO_1, HCOMPRESS_1, BZIP2_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 IS PROVIDED ONLY FOR BACKWARDS COMPATIBILITY;
+ ALL NEW SOFTWARE SHOULD CALL fits_set_quantize_level INSTEAD
+ ********************************************************************
+ ********************************************************************
+
+
+ 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.
+
+ Feb 2008: code changed to use the more general "quantize level" parameter
+ rather than the "noise bits" parameter. If quantize level is greater than
+ zero, then the previous noisebits parameter is approximately given by
+
+ noise bits = natural logarithm (quantize level) / natural log (2)
+
+ This result is rounded to the nearest integer.
+*/
+ double qlevel;
+
+ qlevel = (fptr->Fptr)->quantize_level;
+
+ if (qlevel > 0. && qlevel < 65537. )
+ *noisebits = (int) ((log(qlevel) / log(2.0)) + 0.5);
+ else
+ *noisebits = 0;
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_quantize_level(fitsfile *fptr, /* I - FITS file pointer */
+ float *qlevel, /* quantize level parameter value */
+ 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.
+*/
+
+ if ((fptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ *qlevel = 0;
+ } else {
+ *qlevel = (fptr->Fptr)->quantize_level;
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_dither_offset(fitsfile *fptr, /* I - FITS file pointer */
+ int *offset, /* dithering offset parameter value */
+ int *status) /* IO - error status */
+{
+/*
+ This routine returns the value of the dithering offset parameter that
+ is 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.
+*/
+
+ *offset = (fptr->Fptr)->request_dither_offset;
+ return(*status);
+}/*--------------------------------------------------------------------------*/
+int fits_get_hcomp_scale(fitsfile *fptr, /* I - FITS file pointer */
+ float *scale, /* Hcompress scale parameter value */
+ 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.
+*/
+
+ *scale = (fptr->Fptr)->request_hcomp_scale;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_get_hcomp_smooth(fitsfile *fptr, /* I - FITS file pointer */
+ int *smooth, /* Hcompress smooth parameter value */
+ int *status) /* IO - error status */
+
+{
+ *smooth = (fptr->Fptr)->request_hcomp_smooth;
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_img_compress(fitsfile *infptr, /* pointer to image to be compressed */
+ fitsfile *outfptr, /* empty HDU for output compressed image */
+ 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.
+
+ This is a high level routine that is called by the fpack and funpack
+ FITS compression utilities.
+*/
+{
+ int bitpix, naxis;
+ long naxes[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);
+ }
+
+ /* if requested, treat integer images same as a float image. */
+ /* Then the pixels will be quantized (lossy algorithm) to achieve */
+ /* higher amounts of compression than with lossless algorithms */
+
+ if ( (outfptr->Fptr)->request_lossy_int_compress != 0 && bitpix > 0)
+ bitpix = FLOAT_IMG; /* compress integer images as if float */
+
+ /* initialize output table */
+ if (imcomp_init_table(outfptr, bitpix, naxis, naxes, 0, status) > 0)
+ return (*status);
+
+ /* Copy the image header keywords to the table header. */
+ if (imcomp_copy_img2comp(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 */
+ /* (except if quantizing an int image, same as a float image) */
+ if ( (outfptr->Fptr)->request_lossy_int_compress == 0 && bitpix > 0)
+ 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);
+
+ /* turn off any intensity scaling (defined by BSCALE and BZERO */
+ /* keywords) so that unscaled values will be written by CFITSIO */
+ /* (except if quantizing an int image, same as a float image) */
+ if ( (outfptr->Fptr)->request_lossy_int_compress == 0 && bitpix > 0)
+ ffpscl(outfptr, 1.0, 0.0, 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 fits_compress_img_OBSOLETE(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 is obsolete and should not be used. The
+ ftools 'fimgzip' task used to call this routine (but that task has been deleted);
+
+ The name of the routine was changed 4/27/2011, to see if anyone complains.
+ If not, then this routine should be deleted from the source code.
+ !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!!
+
+ 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 bitpix, naxis;
+ long naxes[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);
+ }
+
+ /* initialize output table */
+ if (imcomp_init_table(outfptr, bitpix, naxis, naxes, 0, 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 inbitpix,
+ int naxis,
+ long *naxes,
+ int writebitpix, /* write the ZBITPIX, ZNAXIS, and ZNAXES keyword? */
+ int *status)
+/*
+ create a BINTABLE extension for the output compressed image.
+*/
+{
+ char keyname[FLEN_KEYWORD], zcmptype[12];
+ int ii, remain, ncols, bitpix;
+ long nrows;
+ char *ttype[] = {"COMPRESSED_DATA", "ZSCALE", "ZZERO"};
+ char *tform[3];
+ char tf0[4], tf1[4], tf2[4];
+ char *tunit[] = {"\0", "\0", "\0" };
+ char comm[FLEN_COMMENT];
+ long actual_tilesize[MAX_COMPRESS_DIM]; /* Actual size to use for tiles */
+
+ if (*status > 0)
+ return(*status);
+
+ /* check for special case of losslessly compressing floating point */
+ /* images. Only compression algorithm that supports this is GZIP */
+ if ( (outfptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ if (((outfptr->Fptr)->request_compress_type != GZIP_1) &&
+ ((outfptr->Fptr)->request_compress_type != GZIP_2)) {
+ ffpmsg("Lossless compression of floating point images must use GZIP (imcomp_init_table)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+ }
+
+ /* test for the 2 special cases that represent unsigned integers */
+ if (inbitpix == USHORT_IMG)
+ bitpix = SHORT_IMG;
+ else if (inbitpix == ULONG_IMG)
+ bitpix = LONG_IMG;
+ else if (inbitpix == SBYTE_IMG)
+ bitpix = BYTE_IMG;
+ else
+ bitpix = inbitpix;
+
+ /* reset default tile dimensions too if required */
+ memcpy(actual_tilesize, outfptr->Fptr->request_tilesize, MAX_COMPRESS_DIM * sizeof(long));
+
+ if ((outfptr->Fptr)->request_compress_type == HCOMPRESS_1) {
+
+ if (naxis < 2 ) {
+ ffpmsg("Hcompress cannot be used with 1-dimensional images (imcomp_init_table)");
+ return(*status = DATA_COMPRESSION_ERR);
+
+ } else if (naxes[0] < 4 || naxes[1] < 4) {
+ ffpmsg("Hcompress minimum image dimension is 4 pixels (imcomp_init_table)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ if ((actual_tilesize[0] == 0) &&
+ (actual_tilesize[1] == 0) ){
+
+ /* compress the whole image as a single tile */
+ actual_tilesize[0] = naxes[0];
+ actual_tilesize[1] = naxes[1];
+
+ for (ii = 2; ii < naxis; ii++) {
+ /* set all higher tile dimensions = 1 */
+ actual_tilesize[ii] = 1;
+ }
+
+ } else if ((actual_tilesize[0] == 0) &&
+ (actual_tilesize[1] == 1) ){
+
+ /*
+ The Hcompress algorithm is inherently 2D in nature, so the row by row
+ tiling that is used for other compression algorithms is not appropriate.
+ If the image has less than 30 rows, then the entire image will be compressed
+ as a single tile. Otherwise the tiles will consist of 16 rows of the image.
+ This keeps the tiles to a reasonable size, and it also includes enough rows
+ to allow good compression efficiency. If the last tile of the image
+ happens to contain less than 4 rows, then find another tile size with
+ between 14 and 30 rows (preferably even), so that the last tile has
+ at least 4 rows
+ */
+
+ /* 1st tile dimension is the row length of the image */
+ actual_tilesize[0] = naxes[0];
+
+ if (naxes[1] <= 30) { /* use whole image if it is small */
+ actual_tilesize[1] = naxes[1];
+ } else {
+ /* look for another good tile dimension */
+ if (naxes[1] % 16 == 0 || naxes[1] % 16 > 3) {
+ actual_tilesize[1] = 16;
+ } else if (naxes[1] % 24 == 0 || naxes[1] % 24 > 3) {
+ actual_tilesize[1] = 24;
+ } else if (naxes[1] % 20 == 0 || naxes[1] % 20 > 3) {
+ actual_tilesize[1] = 20;
+ } else if (naxes[1] % 30 == 0 || naxes[1] % 30 > 3) {
+ actual_tilesize[1] = 30;
+ } else if (naxes[1] % 28 == 0 || naxes[1] % 28 > 3) {
+ actual_tilesize[1] = 28;
+ } else if (naxes[1] % 26 == 0 || naxes[1] % 26 > 3) {
+ actual_tilesize[1] = 26;
+ } else if (naxes[1] % 22 == 0 || naxes[1] % 22 > 3) {
+ actual_tilesize[1] = 22;
+ } else if (naxes[1] % 18 == 0 || naxes[1] % 18 > 3) {
+ actual_tilesize[1] = 18;
+ } else if (naxes[1] % 14 == 0 || naxes[1] % 14 > 3) {
+ actual_tilesize[1] = 14;
+ } else {
+ actual_tilesize[1] = 17;
+
+ }
+ }
+
+ } else if (actual_tilesize[0] < 4 ||
+ actual_tilesize[1] < 4) {
+
+ /* user-specified tile size is too small */
+ ffpmsg("Hcompress minimum tile dimension is 4 pixels (imcomp_init_table)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ /* check if requested tile size causes the last tile to to have less than 4 pixels */
+ remain = naxes[0] % (actual_tilesize[0]); /* 1st dimension */
+ if (remain > 0 && remain < 4) {
+ (actual_tilesize[0])++; /* try increasing tile size by 1 */
+
+ remain = naxes[0] % (actual_tilesize[0]);
+ if (remain > 0 && remain < 4) {
+ ffpmsg("Last tile along 1st dimension has less than 4 pixels (imcomp_init_table)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+ }
+
+ remain = naxes[1] % (actual_tilesize[1]); /* 2nd dimension */
+ if (remain > 0 && remain < 4) {
+ (actual_tilesize[1])++; /* try increasing tile size by 1 */
+
+ remain = naxes[1] % (actual_tilesize[1]);
+ if (remain > 0 && remain < 4) {
+ ffpmsg("Last tile along 2nd dimension has less than 4 pixels (imcomp_init_table)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+ }
+
+ } /* end, if HCOMPRESS_1 */
+
+ for (ii = 0; ii < naxis; ii++) {
+ if (actual_tilesize[ii] <= 0) {
+ /* tile size of 0 means use the image size of that dimension */
+ actual_tilesize[ii] = naxes[ii];
+ }
+ }
+
+ /* ---- set up array of TFORM strings -------------------------------*/
+ strcpy(tf0, "1PB");
+ strcpy(tf1, "1D");
+ strcpy(tf2, "1D");
+
+ tform[0] = tf0;
+ tform[1] = tf1;
+ tform[2] = tf2;
+
+ /* calculate number of rows in output table */
+ nrows = 1;
+ for (ii = 0; ii < naxis; ii++)
+ {
+ nrows = nrows * ((naxes[ii] - 1)/ (actual_tilesize[ii]) + 1);
+ }
+
+ /* determine the default number of columns in the output table */
+ if (bitpix < 0 && (outfptr->Fptr)->quantize_level != NO_QUANTIZE)
+ ncols = 3; /* quantized and scaled floating point image */
+ else
+ ncols = 1; /* default table has just one 'COMPRESSED_DATA' column */
+
+ if ((outfptr->Fptr)->request_compress_type == RICE_1)
+ {
+ strcpy(zcmptype, "RICE_1");
+ }
+ else if ((outfptr->Fptr)->request_compress_type == GZIP_1)
+ {
+ strcpy(zcmptype, "GZIP_1");
+ }
+ else if ((outfptr->Fptr)->request_compress_type == GZIP_2)
+ {
+ strcpy(zcmptype, "GZIP_2");
+ }
+ else if ((outfptr->Fptr)->request_compress_type == BZIP2_1)
+ {
+ strcpy(zcmptype, "BZIP2_1");
+ }
+ else if ((outfptr->Fptr)->request_compress_type == PLIO_1)
+ {
+ strcpy(zcmptype, "PLIO_1");
+ /* the PLIO compression algorithm outputs short integers, not bytes */
+ strcpy(tform[0], "1PI");
+ }
+ else if ((outfptr->Fptr)->request_compress_type == HCOMPRESS_1)
+ {
+ strcpy(zcmptype, "HCOMPRESS_1");
+ }
+ else if ((outfptr->Fptr)->request_compress_type == NOCOMPRESS)
+ {
+ strcpy(zcmptype, "NOCOMPRESS");
+ }
+ else
+ {
+ ffpmsg("unknown compression type (imcomp_init_table)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ /* create the bintable extension to contain the compressed image */
+ ffcrtb(outfptr, BINARY_TBL, nrows, ncols, ttype,
+ tform, tunit, 0, status);
+
+ /* Add standard header keywords. */
+ ffpkyl (outfptr, "ZIMAGE", 1,
+ "extension contains compressed image", status);
+
+ if (writebitpix) {
+ /* write the keywords defining the datatype and dimensions of */
+ /* the uncompressed image. If not, these keywords will be */
+ /* copied later from the input uncompressed image */
+
+ ffpkyj (outfptr, "ZBITPIX", bitpix,
+ "data type of original image", status);
+ ffpkyj (outfptr, "ZNAXIS", 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, actual_tilesize[ii],
+ "size of tiles to be compressed", status);
+ }
+
+ if (bitpix < 0) {
+
+ if ((outfptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ ffpkys(outfptr, "ZQUANTIZ", "NONE",
+ "Lossless compression without quantization", status);
+ } else {
+
+ /* Unless dithering has been specifically turned off by setting */
+ /* request_quantize_dither = -1, use dithering by default */
+ /* when quantizing floating point images. */
+
+ if ( (outfptr->Fptr)->request_quantize_dither == 0)
+ (outfptr->Fptr)->request_quantize_dither = SUBTRACTIVE_DITHER_1;
+
+ if ((outfptr->Fptr)->request_quantize_dither == SUBTRACTIVE_DITHER_1) {
+ ffpkys(outfptr, "ZQUANTIZ", "SUBTRACTIVE_DITHER_1",
+ "Pixel Quantization Algorithm", status);
+
+ /* also write the associated ZDITHER0 keyword with a default value */
+ /* which may get updated later. */
+ ffpky(outfptr, TINT, "ZDITHER0", &((outfptr->Fptr)->request_dither_offset),
+ "dithering offset when quantizing floats", status);
+ }
+ }
+ }
+
+ ffpkys (outfptr, "ZCMPTYPE", zcmptype,
+ "compression algorithm", status);
+
+ /* write any algorithm-specific keywords */
+ if ((outfptr->Fptr)->request_compress_type == RICE_1)
+ {
+ ffpkys (outfptr, "ZNAME1", "BLOCKSIZE",
+ "compression block size", status);
+
+ /* for now at least, the block size is always 32 */
+ ffpkyj (outfptr, "ZVAL1", 32,
+ "pixels per block", status);
+
+ ffpkys (outfptr, "ZNAME2", "BYTEPIX",
+ "bytes per pixel (1, 2, 4, or 8)", status);
+
+ if (bitpix == BYTE_IMG)
+ ffpkyj (outfptr, "ZVAL2", 1,
+ "bytes per pixel (1, 2, 4, or 8)", status);
+ else if (bitpix == SHORT_IMG)
+ ffpkyj (outfptr, "ZVAL2", 2,
+ "bytes per pixel (1, 2, 4, or 8)", status);
+ else
+ ffpkyj (outfptr, "ZVAL2", 4,
+ "bytes per pixel (1, 2, 4, or 8)", status);
+
+ }
+ else if ((outfptr->Fptr)->request_compress_type == HCOMPRESS_1)
+ {
+ ffpkys (outfptr, "ZNAME1", "SCALE",
+ "HCOMPRESS scale factor", status);
+ ffpkye (outfptr, "ZVAL1", (outfptr->Fptr)->request_hcomp_scale,
+ 7, "HCOMPRESS scale factor", status);
+
+ ffpkys (outfptr, "ZNAME2", "SMOOTH",
+ "HCOMPRESS smooth option", status);
+ ffpkyj (outfptr, "ZVAL2", (long) (outfptr->Fptr)->request_hcomp_smooth,
+ "HCOMPRESS smooth option", status);
+ }
+
+ /* Write the BSCALE and BZERO keywords, if an unsigned integer image */
+ if (inbitpix == USHORT_IMG)
+ {
+ strcpy(comm, "offset data range to that of unsigned short");
+ ffpkyg(outfptr, "BZERO", 32768., 0, comm, status);
+ strcpy(comm, "default scaling factor");
+ ffpkyg(outfptr, "BSCALE", 1.0, 0, comm, status);
+ }
+ else if (inbitpix == SBYTE_IMG)
+ {
+ strcpy(comm, "offset data range to that of signed byte");
+ ffpkyg(outfptr, "BZERO", -128., 0, comm, status);
+ strcpy(comm, "default scaling factor");
+ ffpkyg(outfptr, "BSCALE", 1.0, 0, comm, status);
+ }
+ else if (inbitpix == ULONG_IMG)
+ {
+ strcpy(comm, "offset data range to that of unsigned long");
+ ffpkyg(outfptr, "BZERO", 2147483648., 0, comm, status);
+ strcpy(comm, "default scaling factor");
+ ffpkyg(outfptr, "BSCALE", 1.0, 0, comm, status);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_calc_max_elem (int comptype, int nx, int zbitpix, int blocksize)
+
+/* This function returns the maximum number of bytes in a compressed
+ image line.
+
+ nx = maximum number of pixels in a tile
+ blocksize is only relevant for RICE compression
+*/
+{
+ if (comptype == RICE_1)
+ {
+ if (zbitpix == 16)
+ return (sizeof(short) * nx + nx / blocksize + 2 + 4);
+ else
+ return (sizeof(float) * nx + nx / blocksize + 2 + 4);
+ }
+ else if ((comptype == GZIP_1) || (comptype == GZIP_2))
+ {
+ /* gzip usually compressed by at least a factor of 2 for I*4 images */
+ /* and somewhat less for I*2 images */
+ /* If this size turns out to be too small, then the gzip */
+ /* compression routine will allocate more space as required */
+ /* to be on the safe size, allocate buffer same size as input */
+
+ if (zbitpix == 16)
+ return(nx * 2);
+ else if (zbitpix == 8)
+ return(nx);
+ else
+ return(nx * 4);
+ }
+ else if (comptype == BZIP2_1)
+ {
+ /* To guarantee that the compressed data will fit, allocate an output
+ buffer of size 1% larger than the uncompressed data, plus 600 bytes */
+
+ return((int) (nx * 1.01 * zbitpix / 8. + 601.));
+ }
+ else if (comptype == HCOMPRESS_1)
+ {
+ /* Imperical evidence suggests in the worst case,
+ the compressed stream could be up to 10% larger than the original
+ image. Add 26 byte overhead, only significant for very small tiles
+
+ Possible improvement: may need to allow a larger size for 32-bit images */
+
+ if (zbitpix == 16 || zbitpix == 8)
+
+ return( (int) (nx * 2.2 + 26)); /* will be compressing 16-bit int array */
+ else
+ return( (int) (nx * 4.4 + 26)); /* will be compressing 32-bit int array */
+ }
+ 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 tries to quantize the pixels
+ into scaled integers.
+ - it then compressess the integer pixels, or if the it was not
+ possible to quantize the floating point pixels, then it losslessly
+ compresses them with gzip
+ - writes the compressed byte stream to the output FITS file
+*/
+{
+ double *tiledata;
+ int anynul, gotnulls = 0, datatype;
+ long ii, row;
+ int naxis;
+ double dummy = 0., dblnull = DOUBLENULLVALUE;
+ float fltnull = FLOATNULLVALUE;
+ 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; size depends on which compression
+ algorithm is used:
+
+ Rice and GZIP will compress byte, short, or int arrays without conversion.
+ PLIO requires 4-byte int values, so byte and short arrays must be converted to int.
+ HCompress internally converts byte or short values to ints, and
+ converts int values to 8-byte longlong integers.
+ */
+
+ if ((outfptr->Fptr)->zbitpix == FLOAT_IMG)
+ {
+ datatype = TFLOAT;
+
+ if ( (outfptr->Fptr)->compress_type == HCOMPRESS_1) {
+ /* need twice as much scratch space (8 bytes per pixel) */
+ tiledata = (double*) malloc (maxtilelen * 2 *sizeof (float));
+ } else {
+ tiledata = (double*) malloc (maxtilelen * sizeof (float));
+ }
+ }
+ else if ((outfptr->Fptr)->zbitpix == DOUBLE_IMG)
+ {
+ datatype = TDOUBLE;
+ tiledata = (double*) malloc (maxtilelen * sizeof (double));
+ }
+ else if ((outfptr->Fptr)->zbitpix == SHORT_IMG)
+ {
+ datatype = TSHORT;
+ if ( (outfptr->Fptr)->compress_type == RICE_1 ||
+ (outfptr->Fptr)->compress_type == GZIP_1 ||
+ (outfptr->Fptr)->compress_type == GZIP_2 ||
+ (outfptr->Fptr)->compress_type == BZIP2_1 ||
+ (outfptr->Fptr)->compress_type == NOCOMPRESS) {
+ /* only need buffer of I*2 pixels for gzip, bzip2, and Rice */
+
+ tiledata = (double*) malloc (maxtilelen * sizeof (short));
+ } else {
+ /* need buffer of I*4 pixels for Hcompress and PLIO */
+ tiledata = (double*) malloc (maxtilelen * sizeof (int));
+ }
+ }
+ else if ((outfptr->Fptr)->zbitpix == BYTE_IMG)
+ {
+
+ datatype = TBYTE;
+ if ( (outfptr->Fptr)->compress_type == RICE_1 ||
+ (outfptr->Fptr)->compress_type == BZIP2_1 ||
+ (outfptr->Fptr)->compress_type == GZIP_1 ||
+ (outfptr->Fptr)->compress_type == GZIP_2) {
+ /* only need buffer of I*1 pixels for gzip, bzip2, and Rice */
+
+ tiledata = (double*) malloc (maxtilelen);
+ } else {
+ /* need buffer of I*4 pixels for Hcompress and PLIO */
+ tiledata = (double*) malloc (maxtilelen * sizeof (int));
+ }
+ }
+ else if ((outfptr->Fptr)->zbitpix == LONG_IMG)
+ {
+ datatype = TINT;
+ if ( (outfptr->Fptr)->compress_type == HCOMPRESS_1) {
+ /* need twice as much scratch space (8 bytes per pixel) */
+
+ tiledata = (double*) malloc (maxtilelen * 2 * sizeof (int));
+ } else {
+ /* only need buffer of I*4 pixels for gzip, bzip2, Rice, and PLIO */
+
+ tiledata = (double*) malloc (maxtilelen * sizeof (int));
+ }
+ }
+ else
+ {
+ ffpmsg("Bad image datatype. (imcomp_compress_image)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ 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 */
+ anynul = 0;
+ 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 if (datatype == TINT)
+ {
+ ffgsvk(infptr, 1, naxis, naxes, fpixel, lpixel, incre,
+ 0, (int *) tiledata, &anynul, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffgsvi(infptr, 1, naxis, naxes, fpixel, lpixel, incre,
+ 0, (short *) tiledata, &anynul, status);
+ }
+ else if (datatype == TBYTE)
+ {
+ ffgsvb(infptr, 1, naxis, naxes, fpixel, lpixel, incre,
+ 0, (unsigned char *) tiledata, &anynul, status);
+ }
+ else
+ {
+ ffpmsg("Error bad datatype of image tile to compress");
+ free(tiledata);
+ return (*status);
+ }
+
+ /* now compress the tile, and write to row of binary table */
+ /* NOTE: we don't have to worry about the presence of null values in the
+ array if it is an integer array: the null value is simply encoded
+ in the compressed array just like any other pixel value.
+
+ If it is a floating point array, then we need to check for null
+ only if the anynul parameter returned a true value when reading the tile
+ */
+ if (anynul && datatype == TFLOAT) {
+ imcomp_compress_tile(outfptr, row, datatype, tiledata, tilelen,
+ tile[0], tile[1], 1, &fltnull, status);
+ } else if (anynul && datatype == TDOUBLE) {
+ imcomp_compress_tile(outfptr, row, datatype, tiledata, tilelen,
+ tile[0], tile[1], 1, &dblnull, status);
+ } else {
+ imcomp_compress_tile(outfptr, row, datatype, tiledata, tilelen,
+ tile[0], tile[1], 0, &dummy, 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; only for TFLOAT or TDOUBLE images */
+ if (gotnulls)
+ {
+ ffgcrd(outfptr, "ZCMPTYPE", card, status);
+ ffikyj(outfptr, "ZBLANK", COMPRESS_NULL_VALUE,
+ "null value in the compressed integer array", status);
+ }
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_compress_tile (fitsfile *outfptr,
+ long row, /* tile number = row in the binary table that holds the compressed data */
+ int datatype,
+ void *tiledata,
+ long tilelen,
+ long tilenx,
+ long tileny,
+ int nullcheck,
+ void *nullflagval,
+ 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 losslessly compressed with gzip and then written to the output table.
+
+ This input array may be modified by this routine. If the array is of type TINT
+ or TFLOAT, and the compression type is HCOMPRESS, then it must have been
+ allocated to be twice as large (8 bytes per pixel) to provide scratch space.
+
+ Note that this routine does not fully support the implicit datatype conversion that
+ is supported when writing to normal FITS images. The datatype of the input array
+ must have the same datatype (either signed or unsigned) as the output (compressed)
+ FITS image in some cases.
+*/
+{
+ int *idata; /* quantized integer data */
+ int cn_zblank, zbitpix, nullval;
+ int flag = 1; /* true by default; only = 0 if float data couldn't be quantized */
+ int intlength; /* size of integers to be compressed */
+ double scale, zero, actual_bzero;
+ long ii;
+ size_t clen; /* size of cbuf */
+ short *cbuf; /* compressed data */
+ int nelem = 0; /* number of bytes */
+ size_t gzip_nelem = 0;
+ unsigned int bzlen;
+ int ihcompscale;
+ float hcompscale;
+ double noise2, noise3, noise5;
+ double bscale[1] = {1.}, bzero[1] = {0.}; /* scaling parameters */
+ long hcomp_len;
+ LONGLONG *lldata;
+
+ if (*status > 0)
+ return(*status);
+
+ /* check for special case of losslessly compressing floating point */
+ /* images. Only compression algorithm that supports this is GZIP */
+ if ( (outfptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ if (((outfptr->Fptr)->compress_type != GZIP_1) &&
+ ((outfptr->Fptr)->compress_type != GZIP_2)) {
+ ffpmsg("Lossless compression of floating point images must use GZIP");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+ }
+
+ /* free the previously saved tile if the input tile is for the same row */
+ if ((outfptr->Fptr)->tilerow == row) {
+ if ((outfptr->Fptr)->tiledata) {
+ free((outfptr->Fptr)->tiledata);
+ }
+
+ if ((outfptr->Fptr)->tilenullarray) {
+ free((outfptr->Fptr)->tilenullarray);
+ }
+
+ (outfptr->Fptr)->tiledata = 0;
+ (outfptr->Fptr)->tilenullarray = 0;
+ (outfptr->Fptr)->tilerow = 0;
+ (outfptr->Fptr)->tiledatasize = 0;
+ (outfptr->Fptr)->tiletype = 0;
+ }
+
+ if ( (outfptr->Fptr)->compress_type == NOCOMPRESS) {
+ /* Special case when using NOCOMPRESS for diagnostic purposes in fpack */
+ if (imcomp_write_nocompress_tile(outfptr, row, datatype, tiledata, tilelen,
+ nullcheck, nullflagval, status) > 0) {
+ return(*status);
+ }
+ return(*status);
+ }
+
+ /* =========================================================================== */
+ /* initialize various parameters */
+ idata = (int *) tiledata; /* may overwrite the input tiledata in place */
+
+ /* zbitpix is the BITPIX keyword value in the uncompressed FITS image */
+ zbitpix = (outfptr->Fptr)->zbitpix;
+
+ /* if the tile/image has an integer datatype, see if a null value has */
+ /* been defined (with the BLANK keyword in a normal FITS image). */
+ /* If so, and if the input tile array also contains null pixels, */
+ /* (represented by pixels that have a value = nullflagval) then */
+ /* any pixels whose value = nullflagval, must be set to the value = nullval */
+ /* before the pixel array is compressed. These null pixel values must */
+ /* not be inverse scaled by the BSCALE/BZERO values, if present. */
+
+ cn_zblank = (outfptr->Fptr)->cn_zblank;
+ nullval = (outfptr->Fptr)->zblank;
+
+ if (zbitpix > 0 && cn_zblank != -1) /* If the integer image has no defined null */
+ nullcheck = 0; /* value, then don't bother checking input array for nulls. */
+
+ /* if the BSCALE and BZERO keywords exist, then the input values must */
+ /* be inverse scaled by this factor, before the values are compressed. */
+ /* (The program may have turned off scaling, which over rides the keywords) */
+
+ scale = (outfptr->Fptr)->cn_bscale;
+ zero = (outfptr->Fptr)->cn_bzero;
+ actual_bzero = (outfptr->Fptr)->cn_actual_bzero;
+
+ /* =========================================================================== */
+ /* prepare the tile of pixel values for compression */
+ if (datatype == TSHORT) {
+ imcomp_convert_tile_tshort(outfptr, tiledata, tilelen, nullcheck, nullflagval,
+ nullval, zbitpix, scale, zero, actual_bzero, &intlength, status);
+ } else if (datatype == TUSHORT) {
+ imcomp_convert_tile_tushort(outfptr, tiledata, tilelen, nullcheck, nullflagval,
+ nullval, zbitpix, scale, zero, &intlength, status);
+ } else if (datatype == TBYTE) {
+ imcomp_convert_tile_tbyte(outfptr, tiledata, tilelen, nullcheck, nullflagval,
+ nullval, zbitpix, scale, zero, &intlength, status);
+ } else if (datatype == TSBYTE) {
+ imcomp_convert_tile_tsbyte(outfptr, tiledata, tilelen, nullcheck, nullflagval,
+ nullval, zbitpix, scale, zero, &intlength, status);
+ } else if (datatype == TINT) {
+ imcomp_convert_tile_tint(outfptr, tiledata, tilelen, nullcheck, nullflagval,
+ nullval, zbitpix, scale, zero, &intlength, status);
+ } else if (datatype == TUINT) {
+ imcomp_convert_tile_tuint(outfptr, tiledata, tilelen, nullcheck, nullflagval,
+ nullval, zbitpix, scale, zero, &intlength, status);
+ } else if (datatype == TLONG && sizeof(long) == 8) {
+ ffpmsg("Integer*8 Long datatype is not supported when writing to compressed images");
+ return(*status = BAD_DATATYPE);
+ } else if (datatype == TULONG && sizeof(long) == 8) {
+ ffpmsg("Unsigned integer*8 datatype is not supported when writing to compressed images");
+ return(*status = BAD_DATATYPE);
+ } else if (datatype == TFLOAT) {
+ imcomp_convert_tile_tfloat(outfptr, row, tiledata, tilelen, tilenx, tileny, nullcheck,
+ nullflagval, nullval, zbitpix, scale, zero, &intlength, &flag, bscale, bzero, status);
+ } else if (datatype == TDOUBLE) {
+ imcomp_convert_tile_tdouble(outfptr, row, tiledata, tilelen, tilenx, tileny, nullcheck,
+ nullflagval, nullval, zbitpix, scale, zero, &intlength, &flag, bscale, bzero, status);
+ } else {
+ ffpmsg("unsupported image datatype (imcomp_compress_tile)");
+ return(*status = BAD_DATATYPE);
+ }
+
+ if (*status > 0)
+ return(*status); /* return if error occurs */
+
+ /* =========================================================================== */
+ if (flag) /* now compress the integer data array */
+ {
+ /* allocate buffer for the compressed tile bytes */
+ clen = (outfptr->Fptr)->maxelem;
+ cbuf = (short *) calloc (clen, sizeof (unsigned char));
+
+ if (cbuf == NULL) {
+ ffpmsg("Memory allocation failure. (imcomp_compress_tile)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* =========================================================================== */
+ if ( (outfptr->Fptr)->compress_type == RICE_1)
+ {
+ if (intlength == 2) {
+ nelem = fits_rcomp_short ((short *)idata, tilelen, (unsigned char *) cbuf,
+ clen, (outfptr->Fptr)->rice_blocksize);
+ } else if (intlength == 1) {
+ nelem = fits_rcomp_byte ((signed char *)idata, tilelen, (unsigned char *) cbuf,
+ clen, (outfptr->Fptr)->rice_blocksize);
+ } else {
+ nelem = fits_rcomp (idata, tilelen, (unsigned char *) cbuf,
+ clen, (outfptr->Fptr)->rice_blocksize);
+ }
+
+ if (nelem < 0) /* data compression error condition */
+ {
+ free (cbuf);
+ ffpmsg("error Rice compressing image tile (imcomp_compress_tile)");
+ return (*status = DATA_COMPRESSION_ERR);
+ }
+
+ /* 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)
+ {
+ for (ii = 0; ii < tilelen; ii++) {
+ if (idata[ii] < 0 || idata[ii] > 16777215)
+ {
+ /* plio algorithn only supports positive 24 bit ints */
+ ffpmsg("data out of range for PLIO compression (0 - 2**24)");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+ }
+
+ nelem = pl_p2li (idata, 1, cbuf, tilelen);
+
+ if (nelem < 0) /* data compression error condition */
+ {
+ free (cbuf);
+ ffpmsg("error PLIO compressing image tile (imcomp_compress_tile)");
+ return (*status = DATA_COMPRESSION_ERR);
+ }
+
+ /* Write the compressed byte stream. */
+ ffpcli(outfptr, (outfptr->Fptr)->cn_compressed, row, 1,
+ nelem, cbuf, status);
+ }
+
+ /* =========================================================================== */
+ else if ( ((outfptr->Fptr)->compress_type == GZIP_1) ||
+ ((outfptr->Fptr)->compress_type == GZIP_2) ) {
+
+ if ((outfptr->Fptr)->quantize_level == NO_QUANTIZE && datatype == TFLOAT) {
+ /* Special case of losslessly compressing floating point pixels with GZIP */
+ /* In this case we compress the input tile array directly */
+
+#if BYTESWAPPED
+ ffswap4((int*) tiledata, tilelen);
+#endif
+ if ( (outfptr->Fptr)->compress_type == GZIP_2 )
+ fits_shuffle_4bytes((char *) tiledata, tilelen, status);
+
+ compress2mem_from_mem((char *) tiledata, tilelen * sizeof(float),
+ (char **) &cbuf, &clen, realloc, &gzip_nelem, status);
+
+ } else if ((outfptr->Fptr)->quantize_level == NO_QUANTIZE && datatype == TDOUBLE) {
+ /* Special case of losslessly compressing double pixels with GZIP */
+ /* In this case we compress the input tile array directly */
+
+#if BYTESWAPPED
+ ffswap8((double *) tiledata, tilelen);
+#endif
+ if ( (outfptr->Fptr)->compress_type == GZIP_2 )
+ fits_shuffle_8bytes((char *) tiledata, tilelen, status);
+
+ compress2mem_from_mem((char *) tiledata, tilelen * sizeof(double),
+ (char **) &cbuf, &clen, realloc, &gzip_nelem, status);
+
+ } else {
+
+ /* compress the integer idata array */
+
+#if BYTESWAPPED
+ if (intlength == 2)
+ ffswap2((short *) idata, tilelen);
+ else if (intlength == 4)
+ ffswap4(idata, tilelen);
+#endif
+
+ if (intlength == 2) {
+
+ if ( (outfptr->Fptr)->compress_type == GZIP_2 )
+ fits_shuffle_2bytes((char *) tiledata, tilelen, status);
+
+ compress2mem_from_mem((char *) idata, tilelen * sizeof(short),
+ (char **) &cbuf, &clen, realloc, &gzip_nelem, status);
+
+ } else if (intlength == 1) {
+
+ compress2mem_from_mem((char *) idata, tilelen * sizeof(unsigned char),
+ (char **) &cbuf, &clen, realloc, &gzip_nelem, status);
+
+ } else {
+
+ if ( (outfptr->Fptr)->compress_type == GZIP_2 )
+ fits_shuffle_4bytes((char *) tiledata, tilelen, status);
+
+ compress2mem_from_mem((char *) idata, tilelen * sizeof(int),
+ (char **) &cbuf, &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 == BZIP2_1) {
+
+#if BYTESWAPPED
+ if (intlength == 2)
+ ffswap2((short *) idata, tilelen);
+ else if (intlength == 4)
+ ffswap4(idata, tilelen);
+#endif
+
+ bzlen = (unsigned int) clen;
+
+ /* call bzip2 with blocksize = 900K, verbosity = 0, and default workfactor */
+
+/* bzip2 is not supported in the public release. This is only for test purposes.
+ if (BZ2_bzBuffToBuffCompress( (char *) cbuf, &bzlen,
+ (char *) idata, (unsigned int) (tilelen * intlength), 9, 0, 0) )
+*/
+ {
+ ffpmsg("bzip2 compression error");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ /* Write the compressed byte stream. */
+ ffpclb(outfptr, (outfptr->Fptr)->cn_compressed, row, 1,
+ bzlen, (unsigned char *) cbuf, status);
+
+ /* =========================================================================== */
+ } else if ( (outfptr->Fptr)->compress_type == HCOMPRESS_1) {
+ /*
+ if hcompscale is positive, then we have to multiply
+ the value by the RMS background noise to get the
+ absolute scale value. If negative, then it gives the
+ absolute scale value directly.
+ */
+ hcompscale = (outfptr->Fptr)->hcomp_scale;
+
+ if (hcompscale > 0.) {
+ fits_img_stats_int(idata, tilenx, tileny, nullcheck,
+ nullval, 0,0,0,0,0,0,&noise2,&noise3,&noise5,status);
+
+ /* use the minimum of the 3 noise estimates */
+ if (noise2 != 0. && noise2 < noise3) noise3 = noise2;
+ if (noise5 != 0. && noise5 < noise3) noise3 = noise5;
+
+ hcompscale = (float) (hcompscale * noise3);
+
+ } else if (hcompscale < 0.) {
+
+ hcompscale = hcompscale * -1.0F;
+ }
+
+ ihcompscale = (int) (hcompscale + 0.5);
+
+ hcomp_len = clen; /* allocated size of the buffer */
+
+ if (zbitpix == BYTE_IMG || zbitpix == SHORT_IMG) {
+ fits_hcompress(idata, tilenx, tileny,
+ ihcompscale, (char *) cbuf, &hcomp_len, status);
+
+ } else {
+ /* have to convert idata to an I*8 array, in place */
+ /* idata must have been allocated large enough to do this */
+ lldata = (LONGLONG *) idata;
+
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ lldata[ii] = idata[ii];
+ }
+
+ fits_hcompress64(lldata, tilenx, tileny,
+ ihcompscale, (char *) cbuf, &hcomp_len, status);
+ }
+
+ /* Write the compressed byte stream. */
+ ffpclb(outfptr, (outfptr->Fptr)->cn_compressed, row, 1,
+ hcomp_len, (unsigned char *) cbuf, status);
+ }
+
+ /* =========================================================================== */
+ if ((outfptr->Fptr)->cn_zscale > 0)
+ {
+ /* write the linear scaling parameters for this tile */
+ 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 { /* if flag == 0., floating point data couldn't be quantized */
+
+ /* losslessly compress the data with gzip. */
+
+ /* if gzip2 compressed data column doesn't exist, create it */
+ if ((outfptr->Fptr)->cn_gzip_data < 1) {
+ fits_insert_col(outfptr, 999, "GZIP_COMPRESSED_DATA", "1PB", status);
+
+ if (*status <= 0) /* save the number of this column */
+ ffgcno(outfptr, CASEINSEN, "GZIP_COMPRESSED_DATA",
+ &(outfptr->Fptr)->cn_gzip_data, status);
+ }
+
+ if (datatype == TFLOAT) {
+ /* allocate buffer for the compressed tile bytes */
+ /* make it 10% larger than the original uncompressed data */
+ clen = tilelen * sizeof(float) * 1.1;
+ cbuf = (short *) calloc (clen, sizeof (unsigned char));
+
+ if (cbuf == NULL)
+ {
+ ffpmsg("Memory allocation error. (imcomp_compress_tile)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* convert null values to NaNs in place, if necessary */
+ if (nullcheck == 1) {
+ imcomp_float2nan((float *) tiledata, tilelen, (int *) tiledata,
+ *(float *) (nullflagval), status);
+ }
+
+#if BYTESWAPPED
+ ffswap4((int*) tiledata, tilelen);
+#endif
+ compress2mem_from_mem((char *) tiledata, tilelen * sizeof(float),
+ (char **) &cbuf, &clen, realloc, &gzip_nelem, status);
+
+ } else if (datatype == TDOUBLE) {
+
+ /* allocate buffer for the compressed tile bytes */
+ /* make it 10% larger than the original uncompressed data */
+ clen = tilelen * sizeof(double) * 1.1;
+ cbuf = (short *) calloc (clen, sizeof (unsigned char));
+
+ if (cbuf == NULL)
+ {
+ ffpmsg("Memory allocation error. (imcomp_compress_tile)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* convert null values to NaNs in place, if necessary */
+ if (nullcheck == 1) {
+ imcomp_double2nan((double *) tiledata, tilelen, (LONGLONG *) tiledata,
+ *(double *) (nullflagval), status);
+ }
+
+#if BYTESWAPPED
+ ffswap8((double*) tiledata, tilelen);
+#endif
+ compress2mem_from_mem((char *) tiledata, tilelen * sizeof(double),
+ (char **) &cbuf, &clen, realloc, &gzip_nelem, status);
+ }
+
+ /* Write the compressed byte stream. */
+ ffpclb(outfptr, (outfptr->Fptr)->cn_gzip_data, row, 1,
+ gzip_nelem, (unsigned char *) cbuf, status);
+
+ free(cbuf); /* finished with this buffer */
+ }
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int imcomp_write_nocompress_tile(fitsfile *outfptr,
+ long row,
+ int datatype,
+ void *tiledata,
+ long tilelen,
+ int nullcheck,
+ void *nullflagval,
+ int *status)
+{
+ char coltype[4];
+
+ /* Write the uncompressed image tile pixels to the tile-compressed image file. */
+ /* This is a special case when using NOCOMPRESS for diagnostic purposes in fpack. */
+ /* Currently, this only supports a limited number of data types and */
+ /* does not fully support null-valued pixels in the image. */
+
+ if ((outfptr->Fptr)->cn_uncompressed < 1) {
+ /* uncompressed data column doesn't exist, so append new column to table */
+ if (datatype == TSHORT) {
+ strcpy(coltype, "1PI");
+ } else if (datatype == TINT) {
+ strcpy(coltype, "1PJ");
+ } else if (datatype == TFLOAT) {
+ strcpy(coltype, "1PE");
+ } else {
+ ffpmsg("NOCOMPRESSION option only supported for int*2, int*4, and float*4 images");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ fits_insert_col(outfptr, 999, "UNCOMPRESSED_DATA", coltype, status); /* create column */
+ }
+
+ fits_get_colnum(outfptr, CASEINSEN, "UNCOMPRESSED_DATA",
+ &(outfptr->Fptr)->cn_uncompressed, status); /* save col. num. */
+
+ fits_write_col(outfptr, datatype, (outfptr->Fptr)->cn_uncompressed, row, 1,
+ tilelen, tiledata, status); /* write the tile data */
+ return (*status);
+}
+ /*--------------------------------------------------------------------------*/
+int imcomp_convert_tile_tshort(
+ fitsfile *outfptr,
+ void *tiledata,
+ long tilelen,
+ int nullcheck,
+ void *nullflagval,
+ int nullval,
+ int zbitpix,
+ double scale,
+ double zero,
+ double actual_bzero,
+ int *intlength,
+ int *status)
+{
+ /* Prepare the input tile array of pixels for compression.
+ /* Convert input integer*2 tile array in place to 4 or 8-byte ints for compression, */
+ /* If needed, convert 4 or 8-byte ints and do null value substitution. */
+ /* Note that the calling routine must have allocated the input array big enough */
+ /* to be able to do this. */
+
+ short *sbuff;
+ int flagval, *idata;
+ long ii;
+
+ /* We only support writing this integer*2 tile data to a FITS image with
+ BITPIX = 16 and with BZERO = 0 and BSCALE = 1. */
+
+ if (zbitpix != SHORT_IMG || scale != 1.0 || zero != 0.0) {
+ ffpmsg("Datatype conversion/scaling is not supported when writing to compressed images");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ sbuff = (short *) tiledata;
+ idata = (int *) tiledata;
+
+ if ( (outfptr->Fptr)->compress_type == RICE_1 || (outfptr->Fptr)->compress_type == GZIP_1
+ || (outfptr->Fptr)->compress_type == GZIP_2 || (outfptr->Fptr)->compress_type == BZIP2_1 )
+ {
+ /* don't have to convert to int if using gzip, bzip2 or Rice compression */
+ *intlength = 2;
+
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ flagval = *(short *) (nullflagval);
+ if (flagval != nullval) {
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (sbuff[ii] == (short) flagval)
+ sbuff[ii] = (short) nullval;
+ }
+ }
+ }
+ } else if ((outfptr->Fptr)->compress_type == HCOMPRESS_1) {
+ /* have to convert to int if using HCOMPRESS */
+ *intlength = 4;
+
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ flagval = *(short *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (sbuff[ii] == (short) flagval)
+ idata[ii] = nullval;
+ else
+ idata[ii] = (int) sbuff[ii];
+ }
+ } else { /* just do the data type conversion to int */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ idata[ii] = (int) sbuff[ii];
+ }
+ } else {
+ /* have to convert to int if using PLIO */
+ *intlength = 4;
+ if (zero == 0. && actual_bzero == 32768.) {
+ /* Here we are compressing unsigned 16-bit integers that have */
+ /* been offset by -32768 using the standard FITS convention. */
+ /* Since PLIO cannot deal with negative values, we must apply */
+ /* the shift of 32786 to the values to make them all positive. */
+ /* The inverse negative shift will be applied in */
+ /* imcomp_decompress_tile when reading the compressed tile. */
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ flagval = *(short *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (sbuff[ii] == (short) flagval)
+ idata[ii] = nullval;
+ else
+ idata[ii] = (int) sbuff[ii] + 32768;
+ }
+ } else { /* just do the data type conversion to int */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ idata[ii] = (int) sbuff[ii] + 32768;
+ }
+ } else {
+ /* This is not an unsigned 16-bit integer array, so process normally */
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ flagval = *(short *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (sbuff[ii] == (short) flagval)
+ idata[ii] = nullval;
+ else
+ idata[ii] = (int) sbuff[ii];
+ }
+ } else { /* just do the data type conversion to int */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ idata[ii] = (int) sbuff[ii];
+ }
+ }
+ }
+ return(*status);
+}
+ /*--------------------------------------------------------------------------*/
+int imcomp_convert_tile_tushort(
+ fitsfile *outfptr,
+ void *tiledata,
+ long tilelen,
+ int nullcheck,
+ void *nullflagval,
+ int nullval,
+ int zbitpix,
+ double scale,
+ double zero,
+ int *intlength,
+ int *status)
+{
+ /* Prepare the input tile array of pixels for compression.
+ /* Convert input integer*2 tile array in place to 4 or 8-byte ints for compression, */
+ /* If needed, convert 4 or 8-byte ints and do null value substitution. */
+ /* Note that the calling routine must have allocated the input array big enough */
+ /* to be able to do this. */
+
+ unsigned short *usbuff;
+ short *sbuff;
+ int flagval, *idata;
+ long ii;
+
+ /* datatype of input array is unsigned short. We only support writing this datatype
+ to a FITS image with BITPIX = 16 and with BZERO = 0 and BSCALE = 32768. */
+
+ if (zbitpix != SHORT_IMG || scale != 1.0 || zero != 32768.) {
+ ffpmsg("Implicit datatype conversion is not supported when writing to compressed images");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ usbuff = (unsigned short *) tiledata;
+ sbuff = (short *) tiledata;
+ idata = (int *) tiledata;
+
+ if ((outfptr->Fptr)->compress_type == RICE_1 || (outfptr->Fptr)->compress_type == GZIP_1
+ || (outfptr->Fptr)->compress_type == GZIP_2 || (outfptr->Fptr)->compress_type == BZIP2_1)
+ {
+ /* don't have to convert to int if using gzip, bzip2, or Rice compression */
+ *intlength = 2;
+
+ /* offset the unsigned value by -32768 to a signed short value. */
+ /* It is more efficient to do this by just flipping the most significant of the 16 bits */
+
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ flagval = *(unsigned short *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (usbuff[ii] == (unsigned short) flagval)
+ sbuff[ii] = (short) nullval;
+ else
+ usbuff[ii] = (usbuff[ii]) ^ 0x8000;
+ }
+ } else {
+ /* just offset the pixel values by 32768 (by flipping the MSB */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ usbuff[ii] = (usbuff[ii]) ^ 0x8000;
+ }
+ } else {
+ /* have to convert to int if using HCOMPRESS or PLIO */
+ *intlength = 4;
+
+ if (nullcheck == 1) {
+ /* offset the pixel values by 32768, and */
+ /* reset pixels equal to flagval to nullval */
+ flagval = *(unsigned short *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (usbuff[ii] == (unsigned short) flagval)
+ idata[ii] = nullval;
+ else
+ idata[ii] = ((int) usbuff[ii]) - 32768;
+ }
+ } else { /* just do the data type conversion to int */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ idata[ii] = ((int) usbuff[ii]) - 32768;
+ }
+ }
+
+ return(*status);
+}
+ /*--------------------------------------------------------------------------*/
+int imcomp_convert_tile_tint(
+ fitsfile *outfptr,
+ void *tiledata,
+ long tilelen,
+ int nullcheck,
+ void *nullflagval,
+ int nullval,
+ int zbitpix,
+ double scale,
+ double zero,
+ int *intlength,
+ int *status)
+{
+ /* Prepare the input tile array of pixels for compression.
+ /* Convert input integer*2 tile array in place to 4 or 8-byte ints for compression, */
+ /* If needed, convert 4 or 8-byte ints and do null value substitution. */
+ /* Note that the calling routine must have allocated the input array big enough */
+ /* to be able to do this. */
+
+ int flagval, *idata;
+ long ii;
+
+
+ /* datatype of input array is int. We only support writing this datatype
+ to a FITS image with BITPIX = 32 and with BZERO = 0 and BSCALE = 1. */
+
+ if (zbitpix != LONG_IMG || scale != 1.0 || zero != 0.) {
+ ffpmsg("Implicit datatype conversion is not supported when writing to compressed images");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ idata = (int *) tiledata;
+ *intlength = 4;
+
+ if (nullcheck == 1) {
+ /* no datatype conversion is required for any of the compression algorithms,
+ except possibly for HCOMPRESS (to I*8), which is handled later.
+ Just reset pixels equal to flagval to the FITS null value */
+ flagval = *(int *) (nullflagval);
+ if (flagval != nullval) {
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (idata[ii] == flagval)
+ idata[ii] = nullval;
+ }
+ }
+ }
+
+ return(*status);
+}
+ /*--------------------------------------------------------------------------*/
+int imcomp_convert_tile_tuint(
+ fitsfile *outfptr,
+ void *tiledata,
+ long tilelen,
+ int nullcheck,
+ void *nullflagval,
+ int nullval,
+ int zbitpix,
+ double scale,
+ double zero,
+ int *intlength,
+ int *status)
+{
+ /* Prepare the input tile array of pixels for compression.
+ /* Convert input integer*2 tile array in place to 4 or 8-byte ints for compression, */
+ /* If needed, convert 4 or 8-byte ints and do null value substitution. */
+ /* Note that the calling routine must have allocated the input array big enough */
+ /* to be able to do this. */
+
+ int flagval, *idata;
+ unsigned int *uintbuff, uintflagval;
+ long ii;
+
+
+ /* datatype of input array is unsigned int. We only support writing this datatype
+ to a FITS image with BITPIX = 32 and with BZERO = 0 and BSCALE = 2147483648. */
+
+ if (zbitpix != LONG_IMG || scale != 1.0 || zero != 2147483648.) {
+ ffpmsg("Implicit datatype conversion is not supported when writing to compressed images");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ *intlength = 4;
+ idata = (int *) tiledata;
+ uintbuff = (unsigned int *) tiledata;
+
+ /* offset the unsigned value by -2147483648 to a signed int value. */
+ /* It is more efficient to do this by just flipping the most significant of the 32 bits */
+
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to nullval and */
+ /* offset the other pixel values (by flipping the MSB) */
+ uintflagval = *(unsigned int *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (uintbuff[ii] == uintflagval)
+ idata[ii] = nullval;
+ else
+ uintbuff[ii] = (uintbuff[ii]) ^ 0x80000000;
+ }
+ } else {
+ /* just offset the pixel values (by flipping the MSB) */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ uintbuff[ii] = (uintbuff[ii]) ^ 0x80000000;
+ }
+
+ return(*status);
+}
+ /*--------------------------------------------------------------------------*/
+int imcomp_convert_tile_tbyte(
+ fitsfile *outfptr,
+ void *tiledata,
+ long tilelen,
+ int nullcheck,
+ void *nullflagval,
+ int nullval,
+ int zbitpix,
+ double scale,
+ double zero,
+ int *intlength,
+ int *status)
+{
+ /* Prepare the input tile array of pixels for compression.
+ /* Convert input integer*2 tile array in place to 4 or 8-byte ints for compression, */
+ /* If needed, convert 4 or 8-byte ints and do null value substitution. */
+ /* Note that the calling routine must have allocated the input array big enough */
+ /* to be able to do this. */
+
+ int flagval, *idata;
+ long ii;
+ unsigned char *usbbuff;
+
+ /* datatype of input array is unsigned byte. We only support writing this datatype
+ to a FITS image with BITPIX = 8 and with BZERO = 0 and BSCALE = 1. */
+
+ if (zbitpix != BYTE_IMG || scale != 1.0 || zero != 0.) {
+ ffpmsg("Implicit datatype conversion is not supported when writing to compressed images");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ idata = (int *) tiledata;
+ usbbuff = (unsigned char *) tiledata;
+
+ if ( (outfptr->Fptr)->compress_type == RICE_1 || (outfptr->Fptr)->compress_type == GZIP_1
+ || (outfptr->Fptr)->compress_type == GZIP_2 || (outfptr->Fptr)->compress_type == BZIP2_1 )
+ {
+ /* don't have to convert to int if using gzip, bzip2, or Rice compression */
+ *intlength = 1;
+
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ flagval = *(unsigned char *) (nullflagval);
+ if (flagval != nullval) {
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (usbbuff[ii] == (unsigned char) flagval)
+ usbbuff[ii] = (unsigned char) nullval;
+ }
+ }
+ }
+ } else {
+ /* have to convert to int if using HCOMPRESS or PLIO */
+ *intlength = 4;
+
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ flagval = *(unsigned char *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (usbbuff[ii] == (unsigned char) flagval)
+ idata[ii] = nullval;
+ else
+ idata[ii] = (int) usbbuff[ii];
+ }
+ } else { /* just do the data type conversion to int */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ idata[ii] = (int) usbbuff[ii];
+ }
+ }
+
+ return(*status);
+}
+ /*--------------------------------------------------------------------------*/
+int imcomp_convert_tile_tsbyte(
+ fitsfile *outfptr,
+ void *tiledata,
+ long tilelen,
+ int nullcheck,
+ void *nullflagval,
+ int nullval,
+ int zbitpix,
+ double scale,
+ double zero,
+ int *intlength,
+ int *status)
+{
+ /* Prepare the input tile array of pixels for compression.
+ /* Convert input integer*2 tile array in place to 4 or 8-byte ints for compression, */
+ /* If needed, convert 4 or 8-byte ints and do null value substitution. */
+ /* Note that the calling routine must have allocated the input array big enough */
+ /* to be able to do this. */
+
+ int flagval, *idata;
+ long ii;
+ signed char *sbbuff;
+
+ /* datatype of input array is signed byte. We only support writing this datatype
+ to a FITS image with BITPIX = 8 and with BZERO = 0 and BSCALE = -128. */
+
+ if (zbitpix != BYTE_IMG|| scale != 1.0 || zero != -128.) {
+ ffpmsg("Implicit datatype conversion is not supported when writing to compressed images");
+ return(*status = DATA_COMPRESSION_ERR);
+ }
+
+ idata = (int *) tiledata;
+ sbbuff = (signed char *) tiledata;
+
+ if ( (outfptr->Fptr)->compress_type == RICE_1 || (outfptr->Fptr)->compress_type == GZIP_1
+ || (outfptr->Fptr)->compress_type == GZIP_2 || (outfptr->Fptr)->compress_type == BZIP2_1 )
+ {
+ /* don't have to convert to int if using gzip, bzip2 or Rice compression */
+ *intlength = 1;
+
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ /* offset the other pixel values (by flipping the MSB) */
+
+ flagval = *(signed char *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (sbbuff[ii] == (signed char) flagval)
+ sbbuff[ii] = (signed char) nullval;
+ else
+ sbbuff[ii] = (sbbuff[ii]) ^ 0x80; }
+ } else { /* just offset the pixel values (by flipping the MSB) */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ sbbuff[ii] = (sbbuff[ii]) ^ 0x80;
+ }
+
+ } else {
+ /* have to convert to int if using HCOMPRESS or PLIO */
+ *intlength = 4;
+
+ if (nullcheck == 1) {
+ /* reset pixels equal to flagval to the FITS null value, prior to compression */
+ flagval = *(signed char *) (nullflagval);
+ for (ii = tilelen - 1; ii >= 0; ii--) {
+ if (sbbuff[ii] == (signed char) flagval)
+ idata[ii] = nullval;
+ else
+ idata[ii] = ((int) sbbuff[ii]) + 128;
+ }
+ } else { /* just do the data type conversion to int */
+ for (ii = tilelen - 1; ii >= 0; ii--)
+ idata[ii] = ((int) sbbuff[ii]) + 128;
+ }
+ }
+
+ return(*status);
+}
+ /*--------------------------------------------------------------------------*/
+int imcomp_convert_tile_tfloat(
+ fitsfile *outfptr,
+ long row,
+ void *tiledata,
+ long tilelen,
+ long tilenx,
+ long tileny,
+ int nullcheck,
+ void *nullflagval,
+ int nullval,
+ int zbitpix,
+ double scale,
+ double zero,
+ int *intlength,
+ int *flag,
+ double *bscale,
+ double *bzero,
+ int *status)
+{
+ /* Prepare the input tile array of pixels for compression.
+ /* Convert input integer*2 tile array in place to 4 or 8-byte ints for compression, */
+ /* If needed, convert 4 or 8-byte ints and do null value substitution. */
+ /* Note that the calling routine must have allocated the input array big enough */
+ /* to be able to do this. */
+
+ int flagval, *idata;
+ long irow, ii;
+ float floatnull;
+ unsigned char *usbbuff;
+ unsigned long dithersum;
+ int iminval = 0, imaxval = 0; /* min and max quantized integers */
+
+ *intlength = 4;
+ idata = (int *) tiledata;
+
+ /* if the tile-compressed table contains zscale and zzero columns */
+ /* then scale and quantize the input floating point data. */
+
+ if ((outfptr->Fptr)->cn_zscale > 0) {
+ /* quantize the float values into integers */
+
+ if (nullcheck == 1)
+ floatnull = *(float *) (nullflagval);
+ else
+ floatnull = FLOATNULLVALUE; /* NaNs are represented by this, by default */
+
+ if ((outfptr->Fptr)->quantize_dither == SUBTRACTIVE_DITHER_1) {
+
+ /* see if the dithering offset value needs to be initialized */
+ if ((outfptr->Fptr)->request_dither_offset == 0 && (outfptr->Fptr)->dither_offset == 0) {
+
+ /* This means randomly choose the dithering offset based on the system time. */
+ /* The offset will have a value between 1 and 10000, inclusive. */
+ /* The time function returns an integer value that is incremented each second. */
+ /* The clock function returns the elapsed CPU time, in integer CLOCKS_PER_SEC units. */
+ /* The CPU time returned by clock is typically (on linux PC) only good to 0.01 sec */
+ /* Summing the 2 quantities may help avoid cases where 2 executions of the program */
+ /* (perhaps in a multithreaded environoment) end up with exactly the same dither_offset */
+ /* value. The sum is incremented by the current HDU number in the file to provide */
+ /* further randomization. This randomization is desireable if multiple compressed */
+ /* images will be summed (or differenced). In such cases, the benefits of dithering */
+ /* may be lost if all the images use exactly the same sequence of random numbers when */
+ /* calculating the dithering offsets. */
+
+ (outfptr->Fptr)->dither_offset =
+ (( (int)time(NULL) + ( (int) clock() / (int) (CLOCKS_PER_SEC / 100)) + (outfptr->Fptr)->curhdu) % 10000) + 1;
+
+ /* update the header keyword with this new value */
+ fits_update_key(outfptr, TINT, "ZDITHER0", &((outfptr->Fptr)->dither_offset),
+ NULL, status);
+
+ } else if ((outfptr->Fptr)->request_dither_offset < 0 && (outfptr->Fptr)->dither_offset < 0) {
+
+ /* this means randomly choose the dithering offset based on some hash function */
+ /* of the first input tile of data to be quantized and compressed. This ensures that */
+ /* the same offset value is used for a given image every time it is compressed. */
+
+ usbbuff = (unsigned char *) tiledata;
+ dithersum = 0;
+ for (ii = 0; ii < 4 * tilelen; ii++) {
+ dithersum += usbbuff[ii]; /* doesn't matter if there is an integer overflow */
+ }
+ (outfptr->Fptr)->dither_offset = ((int) (dithersum % 10000)) + 1;
+
+ /* update the header keyword with this new value */
+ fits_update_key(outfptr, TINT, "ZDITHER0", &((outfptr->Fptr)->dither_offset),
+ NULL, status);
+ }
+
+ /* subtract 1 to convert from 1-based to 0-based element number */
+ irow = row + (outfptr->Fptr)->dither_offset - 1; /* dither the quantized values */
+
+ } else {
+ irow = 0; /* do not dither the quantized values */
+ }
+
+ *flag = fits_quantize_float (irow, (float *) tiledata, tilenx, tileny,
+ nullcheck, floatnull, (outfptr->Fptr)->quantize_level, idata,
+ bscale, bzero, &iminval, &imaxval);
+
+ if (*flag > 1)
+ return(*status = *flag);
+ }
+ else if ((outfptr->Fptr)->quantize_level != NO_QUANTIZE)
+ {
+ /* if floating point pixels are not being losslessly compressed, then */
+ /* input float data is implicitly converted (truncated) to integers */
+ if ((scale != 1. || zero != 0.)) /* must scale the values */
+ imcomp_nullscalefloats((float *) tiledata, tilelen, idata, scale, zero,
+ nullcheck, *(float *) (nullflagval), nullval, status);
+ else
+ imcomp_nullfloats((float *) tiledata, tilelen, idata,
+ nullcheck, *(float *) (nullflagval), nullval, status);
+ }
+ else if ((outfptr->Fptr)->quantize_level == NO_QUANTIZE)
+ {
+ /* just convert null values to NaNs in place, if necessary, then do lossless gzip compression */
+ if (nullcheck == 1) {
+ imcomp_float2nan((float *) tiledata, tilelen, (int *) tiledata,
+ *(float *) (nullflagval), status);
+ }
+ }
+
+ return(*status);
+}
+ /*--------------------------------------------------------------------------*/
+int imcomp_convert_tile_tdouble(
+ fitsfile *outfptr,
+ long row,
+ void *tiledata,
+ long tilelen,
+ long tilenx,
+ long tileny,
+ int nullcheck,
+ void *nullflagval,
+ int nullval,
+ int zbitpix,
+ double scale,
+ double zero,
+ int *intlength,
+ int *flag,
+ double *bscale,
+ double *bzero,
+ int *status)
+{
+ /* Prepare the input tile array of pixels for compression.
+ /* Convert input integer*2 tile array in place to 4 or 8-byte ints for compression, */
+ /* If needed, convert 4 or 8-byte ints and do null value substitution. */
+ /* Note that the calling routine must have allocated the input array big enough */
+ /* to be able to do this. */
+
+ int flagval, *idata;
+ long irow, ii;
+ double doublenull;
+ unsigned char *usbbuff;
+ unsigned long dithersum;
+ int iminval = 0, imaxval = 0; /* min and max quantized integers */
+
+ *intlength = 4;
+ idata = (int *) tiledata;
+
+ /* 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)
+ {
+ if (nullcheck == 1)
+ doublenull = *(double *) (nullflagval);
+ else
+ doublenull = DOUBLENULLVALUE;
+
+ /* quantize the double values into integers */
+ if ((outfptr->Fptr)->quantize_dither == SUBTRACTIVE_DITHER_1) {
+
+ /* see if the dithering offset value needs to be initialized (see above) */
+ if ((outfptr->Fptr)->request_dither_offset == 0 && (outfptr->Fptr)->dither_offset == 0) {
+
+ (outfptr->Fptr)->dither_offset =
+ (( (int)time(NULL) + ( (int) clock() / (int) (CLOCKS_PER_SEC / 100)) + (outfptr->Fptr)->curhdu) % 10000) + 1;
+
+ /* update the header keyword with this new value */
+ fits_update_key(outfptr, TINT, "ZDITHER0", &((outfptr->Fptr)->dither_offset),
+ NULL, status);
+
+ } else if ((outfptr->Fptr)->request_dither_offset < 0 && (outfptr->Fptr)->dither_offset < 0) {
+
+ usbbuff = (unsigned char *) tiledata;
+ dithersum = 0;
+ for (ii = 0; ii < 8 * tilelen; ii++) {
+ dithersum += usbbuff[ii];
+ }
+ (outfptr->Fptr)->dither_offset = ((int) (dithersum % 10000)) + 1;
+
+ /* update the header keyword with this new value */
+ fits_update_key(outfptr, TINT, "ZDITHER0", &((outfptr->Fptr)->dither_offset),
+ NULL, status);
+ }
+
+ irow = row + (outfptr->Fptr)->dither_offset - 1; /* dither the quantized values */
+
+ } else {
+ irow = 0; /* do not dither the quantized values */
+ }
+
+ *flag = fits_quantize_double (irow, (double *) tiledata, tilenx, tileny,
+ nullcheck, doublenull, (outfptr->Fptr)->quantize_level, idata,
+ bscale, bzero, &iminval, &imaxval);
+
+ if (*flag > 1)
+ return(*status = *flag);
+ }
+ else if ((outfptr->Fptr)->quantize_level != NO_QUANTIZE)
+ {
+ /* if floating point pixels are not being losslessly compressed, then */
+ /* input float data is implicitly converted (truncated) to integers */
+ if ((scale != 1. || zero != 0.)) /* must scale the values */
+ imcomp_nullscaledoubles((double *) tiledata, tilelen, idata, scale, zero,
+ nullcheck, *(double *) (nullflagval), nullval, status);
+ else
+ imcomp_nulldoubles((double *) tiledata, tilelen, idata,
+ nullcheck, *(double *) (nullflagval), nullval, status);
+ }
+ else if ((outfptr->Fptr)->quantize_level == NO_QUANTIZE)
+ {
+ /* just convert null values to NaNs in place, if necessary, then do lossless gzip compression */
+ if (nullcheck == 1) {
+ imcomp_double2nan((double *) tiledata, tilelen, (LONGLONG *) tiledata,
+ *(double *) (nullflagval), status);
+ }
+ }
+
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_nullscale(
+ int *idata,
+ long tilelen,
+ int nullflagval,
+ int nullval,
+ double scale,
+ double zero,
+ int *status)
+/*
+ do null value substitution AND scaling of the integer array.
+ If array value = nullflagval, then set the value to nullval.
+ Otherwise, inverse scale the integer value.
+*/
+{
+ long ii;
+ double dvalue;
+
+ for (ii=0; ii < tilelen; ii++)
+ {
+ if (idata[ii] == nullflagval)
+ idata[ii] = nullval;
+ else
+ {
+ dvalue = (idata[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_nullvalues(
+ int *idata,
+ long tilelen,
+ int nullflagval,
+ int nullval,
+ int *status)
+/*
+ do null value substitution.
+ If array value = nullflagval, then set the value to nullval.
+*/
+{
+ long ii;
+
+ for (ii=0; ii < tilelen; ii++)
+ {
+ if (idata[ii] == nullflagval)
+ idata[ii] = nullval;
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_scalevalues(
+ int *idata,
+ long tilelen,
+ double scale,
+ double zero,
+ int *status)
+/*
+ do inverse scaling the integer values.
+*/
+{
+ long ii;
+ double dvalue;
+
+ for (ii=0; ii < tilelen; ii++)
+ {
+ dvalue = (idata[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_nullscalei2(
+ short *idata,
+ long tilelen,
+ short nullflagval,
+ short nullval,
+ double scale,
+ double zero,
+ int *status)
+/*
+ do null value substitution AND scaling of the integer array.
+ If array value = nullflagval, then set the value to nullval.
+ Otherwise, inverse scale the integer value.
+*/
+{
+ long ii;
+ double dvalue;
+
+ for (ii=0; ii < tilelen; ii++)
+ {
+ if (idata[ii] == nullflagval)
+ idata[ii] = nullval;
+ else
+ {
+ dvalue = (idata[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_nullvaluesi2(
+ short *idata,
+ long tilelen,
+ short nullflagval,
+ short nullval,
+ int *status)
+/*
+ do null value substitution.
+ If array value = nullflagval, then set the value to nullval.
+*/
+{
+ long ii;
+
+ for (ii=0; ii < tilelen; ii++)
+ {
+ if (idata[ii] == nullflagval)
+ idata[ii] = nullval;
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_scalevaluesi2(
+ short *idata,
+ long tilelen,
+ double scale,
+ double zero,
+ int *status)
+/*
+ do inverse scaling the integer values.
+*/
+{
+ long ii;
+ double dvalue;
+
+ for (ii=0; ii < tilelen; ii++)
+ {
+ dvalue = (idata[ii] - zero) / scale;
+
+ if (dvalue < DSHRT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = SHRT_MIN;
+ }
+ else if (dvalue > DSHRT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = SHRT_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_nullfloats(
+ float *fdata,
+ long tilelen,
+ int *idata,
+ int nullcheck,
+ float nullflagval,
+ int nullval,
+ int *status)
+/*
+ do null value substitution of the float array.
+ If array value = nullflagval, then set the output value to FLOATNULLVALUE.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 1) /* must check for null values */
+ {
+ for (ii=0; ii < tilelen; ii++)
+ {
+ if (fdata[ii] == nullflagval)
+ idata[ii] = nullval;
+ else
+ {
+ dvalue = fdata[ii];
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ }
+ else /* don't have to worry about null values */
+ {
+ for (ii=0; ii < tilelen; ii++)
+ {
+ dvalue = fdata[ii];
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_nullscalefloats(
+ float *fdata,
+ long tilelen,
+ int *idata,
+ double scale,
+ double zero,
+ int nullcheck,
+ float nullflagval,
+ int nullval,
+ int *status)
+/*
+ do null value substitution of the float array.
+ If array value = nullflagval, then set the output value to FLOATNULLVALUE.
+ Otherwise, inverse scale the integer value.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 1) /* must check for null values */
+ {
+ for (ii=0; ii < tilelen; ii++)
+ {
+ if (fdata[ii] == nullflagval)
+ idata[ii] = nullval;
+ else
+ {
+ dvalue = (fdata[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0.)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ }
+ else /* don't have to worry about null values */
+ {
+ for (ii=0; ii < tilelen; ii++)
+ {
+ dvalue = (fdata[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0.)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_nulldoubles(
+ double *fdata,
+ long tilelen,
+ int *idata,
+ int nullcheck,
+ double nullflagval,
+ int nullval,
+ int *status)
+/*
+ do null value substitution of the float array.
+ If array value = nullflagval, then set the output value to FLOATNULLVALUE.
+ Otherwise, inverse scale the integer value.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 1) /* must check for null values */
+ {
+ for (ii=0; ii < tilelen; ii++)
+ {
+ if (fdata[ii] == nullflagval)
+ idata[ii] = nullval;
+ else
+ {
+ dvalue = fdata[ii];
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0.)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ }
+ else /* don't have to worry about null values */
+ {
+ for (ii=0; ii < tilelen; ii++)
+ {
+ dvalue = fdata[ii];
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0.)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ return(*status);
+}
+/*---------------------------------------------------------------------------*/
+int imcomp_nullscaledoubles(
+ double *fdata,
+ long tilelen,
+ int *idata,
+ double scale,
+ double zero,
+ int nullcheck,
+ double nullflagval,
+ int nullval,
+ int *status)
+/*
+ do null value substitution of the float array.
+ If array value = nullflagval, then set the output value to FLOATNULLVALUE.
+ Otherwise, inverse scale the integer value.
+*/
+{
+ long ii;
+ double dvalue;
+
+ if (nullcheck == 1) /* must check for null values */
+ {
+ for (ii=0; ii < tilelen; ii++)
+ {
+ if (fdata[ii] == nullflagval)
+ idata[ii] = nullval;
+ else
+ {
+ dvalue = (fdata[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0.)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ }
+ else /* don't have to worry about null values */
+ {
+ for (ii=0; ii < tilelen; ii++)
+ {
+ dvalue = (fdata[ii] - zero) / scale;
+
+ if (dvalue < DINT_MIN)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MIN;
+ }
+ else if (dvalue > DINT_MAX)
+ {
+ *status = OVERFLOW_ERR;
+ idata[ii] = INT32_MAX;
+ }
+ else
+ {
+ if (dvalue >= 0.)
+ idata[ii] = (int) (dvalue + .5);
+ else
+ idata[ii] = (int) (dvalue - .5);
+ }
+ }
+ }
+ 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 */
+ 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;
+ int tstatus, buffpixsiz;
+ void *buffer;
+ char *bnullarray = 0, card[FLEN_CARD];
+
+ 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);
+
+
+ /* ===================================================================== */
+
+
+ if (datatype == TSHORT || datatype == TUSHORT)
+ {
+ pixlen = sizeof(short);
+ }
+ else if (datatype == TINT || datatype == TUINT)
+ {
+ pixlen = sizeof(int);
+ }
+ else if (datatype == TBYTE || datatype == TSBYTE)
+ {
+ pixlen = 1;
+ }
+ else if (datatype == TLONG || datatype == TULONG)
+ {
+ pixlen = sizeof(long);
+ }
+ else if (datatype == TFLOAT)
+ {
+ pixlen = sizeof(float);
+ }
+ else if (datatype == TDOUBLE)
+ {
+ pixlen = sizeof(double);
+ }
+ else
+ {
+ ffpmsg("unsupported datatype for compressing image");
+ return(*status = BAD_DATATYPE);
+ }
+
+ /* ===================================================================== */
+
+ /* allocate scratch space for processing one tile of the image */
+ buffpixsiz = pixlen; /* this is the minimum pixel size */
+
+ if ( (fptr->Fptr)->compress_type == HCOMPRESS_1) { /* need 4 or 8 bytes per pixel */
+ if ((fptr->Fptr)->zbitpix == BYTE_IMG ||
+ (fptr->Fptr)->zbitpix == SHORT_IMG )
+ buffpixsiz = maxvalue(buffpixsiz, 4);
+ else
+ buffpixsiz = 8;
+ }
+ else if ( (fptr->Fptr)->compress_type == PLIO_1) { /* need 4 bytes per pixel */
+ buffpixsiz = maxvalue(buffpixsiz, 4);
+ }
+ else if ( (fptr->Fptr)->compress_type == RICE_1 ||
+ (fptr->Fptr)->compress_type == GZIP_1 ||
+ (fptr->Fptr)->compress_type == GZIP_2 ||
+ (fptr->Fptr)->compress_type == BZIP2_1) { /* need 1, 2, or 4 bytes per pixel */
+ if ((fptr->Fptr)->zbitpix == BYTE_IMG)
+ buffpixsiz = maxvalue(buffpixsiz, 1);
+ else if ((fptr->Fptr)->zbitpix == SHORT_IMG)
+ buffpixsiz = maxvalue(buffpixsiz, 2);
+ else
+ buffpixsiz = maxvalue(buffpixsiz, 4);
+ }
+ else
+ {
+ ffpmsg("unsupported image compression algorithm");
+ return(*status = BAD_DATATYPE);
+ }
+
+ /* cast to double to force alignment on 8-byte addresses */
+ buffer = (double *) calloc ((fptr->Fptr)->maxtilelen, buffpixsiz);
+
+ 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],
+ tlpixel[0] - tfpixel[0] + 1,
+ tlpixel[1] - tfpixel[1] + 1,
+ nullcheck, nullval,
+ status);
+ }
+ }
+ }
+ }
+ }
+ }
+ free(buffer);
+
+
+ if ((fptr->Fptr)->zbitpix < 0 && nullcheck != 0) {
+/*
+ This is a floating point FITS image with possible null values.
+ It is too messy to test if any null values are actually written, so
+ just assume so. We need to make sure that the
+ ZBLANK keyword is present in the compressed image header. If it is not
+ there then we need to insert the keyword.
+*/
+ tstatus = 0;
+ ffgcrd(fptr, "ZBLANK", card, &tstatus);
+
+ if (tstatus) { /* have to insert the ZBLANK keyword */
+ ffgcrd(fptr, "ZCMPTYPE", card, status);
+ ffikyj(fptr, "ZBLANK", COMPRESS_NULL_VALUE,
+ "null value in the compressed integer array", status);
+
+ /* set this value into the internal structure; it is used if */
+ /* the program reads back the values from the array */
+
+ (fptr->Fptr)->zblank = COMPRESS_NULL_VALUE;
+ (fptr->Fptr)->cn_zblank = -1; /* flag for a constant ZBLANK */
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_write_compressed_pixels(fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the array to be written */
+ LONGLONG fpixel, /* I - 'first pixel to write */
+ LONGLONG 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;
+ LONGLONG 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 written */
+ 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] = (long) (tfirst / dimsize[ii]);
+ lastcoord[ii] = (long) (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] = (long) last0;
+ lastcoord[1] = (long) 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_img_decompress (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.
+*/
+
+{
+ int ii, datatype = 0;
+ int nullcheck, anynul;
+ LONGLONG fpixel[MAX_COMPRESS_DIM], lpixel[MAX_COMPRESS_DIM];
+ long inc[MAX_COMPRESS_DIM];
+ long imgsize;
+ float *nulladdr, fnulval;
+ double dnulval;
+
+ if (fits_img_decompress_header(infptr, outfptr, status) > 0)
+ {
+ 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;
+ }
+ else if ((infptr->Fptr)->zbitpix == SHORT_IMG)
+ {
+ datatype = TSHORT;
+ }
+ else if ((infptr->Fptr)->zbitpix == LONG_IMG)
+ {
+ datatype = TINT;
+ }
+ 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;
+ }
+ 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;
+ }
+
+ /* 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;
+ }
+
+ /* uncompress the input image and write to output image, one tile at a time */
+
+ fits_read_write_compressed_img(infptr, datatype, fpixel, lpixel, inc,
+ nullcheck, nulladdr, &anynul, outfptr, status);
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_decompress_img (fitsfile *infptr, /* image (bintable) to uncompress */
+ fitsfile *outfptr, /* empty HDU for output uncompressed image */
+ int *status) /* IO - error status */
+
+/*
+ THIS IS AN OBSOLETE ROUTINE. USE fits_img_decompress instead!!!
+
+ 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;
+ LONGLONG 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_img_decompress_header(fitsfile *infptr, /* image (bintable) to uncompress */
+ fitsfile *outfptr, /* empty HDU for output uncompressed image */
+ int *status) /* IO - error status */
+
+/*
+ This routine reads the header of the input tile compressed image and
+ converts it to that of a standard uncompress FITS image.
+*/
+
+{
+ int writeprime = 0;
+ int hdupos, inhdupos, numkeys;
+ int nullprime = 0, copyprime = 0, norec = 0, tstatus;
+ char card[FLEN_CARD];
+ int ii, datatype = 0, naxis, bitpix;
+ long naxes[MAX_COMPRESS_DIM];
+
+ if (*status > 0)
+ return(*status);
+ else if (*status == -1) {
+ *status = 0;
+ writeprime = 1;
+ }
+
+ if (!fits_is_compressed_image(infptr, status) )
+ {
+ ffpmsg("CHDU is not a compressed image (fits_img_decompress)");
+ return(*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ /* get information about the state of the output file; does it already */
+ /* contain any keywords and HDUs? */
+ fits_get_hdu_num(infptr, &inhdupos); /* Get the current output HDU position */
+ fits_get_hdu_num(outfptr, &hdupos); /* Get the current output HDU position */
+ fits_get_hdrspace(outfptr, &numkeys, 0, status);
+
+ /* Was the input compressed HDU originally the primary array image? */
+ tstatus = 0;
+ if (!fits_read_card(infptr, "ZSIMPLE", card, &tstatus)) {
+ /* yes, input HDU was a primary array (not an IMAGE extension) */
+ /* Now determine if we can uncompress it into the primary array of */
+ /* the output file. This is only possible if the output file */
+ /* currently only contains a null primary array, with no addition */
+ /* header keywords and with no following extension in the FITS file. */
+
+ if (hdupos == 1) { /* are we positioned at the primary array? */
+ if (numkeys == 0) { /* primary HDU is completely empty */
+ nullprime = 1;
+ } else {
+ fits_get_img_param(outfptr, MAX_COMPRESS_DIM, &bitpix, &naxis, naxes, status);
+
+ if (naxis == 0) { /* is this a null image? */
+ nullprime = 1;
+
+ if (inhdupos == 2) /* must be at the first extension */
+ copyprime = 1;
+ }
+ }
+ }
+ }
+
+ if (nullprime) {
+ /* We will delete the existing keywords in the null primary array
+ and uncompress the input image into the primary array of the output.
+ Some of these keywords may be added back to the uncompressed image
+ header later.
+ */
+
+ for (ii = numkeys; ii > 0; ii--)
+ fits_delete_record(outfptr, ii, status);
+
+ } else {
+
+ /* if the ZTENSION keyword doesn't exist, then we have to
+ write the required keywords manually */
+ tstatus = 0;
+ if (fits_read_card(infptr, "ZTENSION", card, &tstatus)) {
+
+ /* 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);
+ }
+
+ norec = 1; /* the required keywords have already been written */
+
+ } else { /* the input compressed image does have ZTENSION keyword */
+
+ if (writeprime) { /* convert the image extension to a primary array */
+ /* have to write the required keywords manually */
+
+ /* 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);
+ }
+
+ norec = 1; /* the required keywords have already been written */
+
+ } else { /* write the input compressed image to an image extension */
+
+ if (numkeys == 0) { /* the output file is currently completely empty */
+
+ /* In this case, the input is a compressed IMAGE extension. */
+ /* Since the uncompressed output file is currently completely empty, */
+ /* we need to write a null primary array before uncompressing the */
+ /* image extension */
+
+ ffcrim(outfptr, 8, 0, naxes, status); /* naxes is not used */
+
+ /* now create the empty extension to uncompress into */
+ if (fits_create_hdu(outfptr, status) > 0)
+ {
+ ffpmsg("error creating output decompressed image HDU");
+ return (*status);
+ }
+
+ } else {
+ /* just create a new empty extension, then copy all the required */
+ /* keywords into it. */
+ fits_create_hdu(outfptr, status);
+ }
+ }
+ }
+
+ }
+
+ if (*status > 0) {
+ ffpmsg("error creating output decompressed image HDU");
+ return (*status);
+ }
+
+ /* Copy the table header to the image header. */
+
+ if (imcomp_copy_comp2img(infptr, outfptr, norec, status) > 0)
+ {
+ ffpmsg("error copying header keywords from compressed image");
+ }
+
+ if (copyprime) {
+ /* append any unexpected keywords from the primary array.
+ This includes any keywords except SIMPLE, BITPIX, NAXIS,
+ EXTEND, COMMENT, HISTORY, CHECKSUM, and DATASUM.
+ */
+
+ fits_movabs_hdu(infptr, 1, NULL, status); /* move to primary array */
+
+ /* do this so that any new keywords get written before any blank
+ keywords that may have been appended by imcomp_copy_comp2img */
+ fits_set_hdustruc(outfptr, status);
+
+ if (imcomp_copy_prime2img(infptr, outfptr, status) > 0)
+ {
+ ffpmsg("error copying primary keywords from compressed file");
+ }
+
+ fits_movabs_hdu(infptr, 2, NULL, status); /* move back to where we were */
+ }
+
+ return (*status);
+}
+/*---------------------------------------------------------------------------*/
+int fits_read_compressed_img(fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the array to be returned */
+ LONGLONG *infpixel, /* I - 'bottom left corner' of the subsection */
+ LONGLONG *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;
+ double testnullval = 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 = malloc ((fptr->Fptr)->maxtilelen * sizeof (short));
+ pixlen = sizeof(short);
+ if (nullval)
+ testnullval = *(short *) nullval;
+ }
+ else if (datatype == TINT)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (int));
+ pixlen = sizeof(int);
+ if (nullval)
+ testnullval = *(int *) nullval;
+ }
+ else if (datatype == TLONG)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (long));
+ pixlen = sizeof(long);
+ if (nullval)
+ testnullval = *(long *) nullval;
+ }
+ else if (datatype == TFLOAT)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (float));
+ pixlen = sizeof(float);
+ if (nullval)
+ testnullval = *(float *) nullval;
+ }
+ else if (datatype == TDOUBLE)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (double));
+ pixlen = sizeof(double);
+ if (nullval)
+ testnullval = *(double *) nullval;
+ }
+ else if (datatype == TUSHORT)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (unsigned short));
+ pixlen = sizeof(short);
+ if (nullval)
+ testnullval = *(unsigned short *) nullval;
+ }
+ else if (datatype == TUINT)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (unsigned int));
+ pixlen = sizeof(int);
+ if (nullval)
+ testnullval = *(unsigned int *) nullval;
+ }
+ else if (datatype == TULONG)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (unsigned long));
+ pixlen = sizeof(long);
+ if (nullval)
+ testnullval = *(unsigned long *) nullval;
+ }
+ else if (datatype == TBYTE || datatype == TSBYTE)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (char));
+ pixlen = 1;
+ if (nullval)
+ testnullval = *(unsigned char *) nullval;
+ }
+ else
+ {
+ ffpmsg("unsupported datatype for uncompressing image");
+ return(*status = BAD_DATATYPE);
+ }
+
+ /* If nullcheck ==1 and nullval == 0, then this means that the */
+ /* calling routine does not want to check for null pixels in the array */
+ if (nullcheck == 1 && testnullval == 0.)
+ nullcheck = 0;
+
+ 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] = (long) infpixel[ii];
+ lpixel[ii] = (long) inlpixel[ii];
+ inc[ii] = ininc[ii];
+ }
+ else
+ {
+ fpixel[ii] = (long) inlpixel[ii];
+ lpixel[ii] = (long) 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];
+ }
+
+ if (anynul)
+ *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];
+
+/*
+printf("row %d, %d %d, %d %d, %d %d; %d\n",
+ irow, tfpixel[0],tlpixel[0],tfpixel[1],tlpixel[1],tfpixel[2],tlpixel[2],
+ thistilesize[0]);
+*/
+ /* 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 */
+/*
+printf(" pixlen=%d, ndim=%d, %d %d %d, %d %d %d, %d %d %d\n",
+ pixlen, ndim, fpixel[0],lpixel[0],inc[0],fpixel[1],lpixel[1],inc[1],
+ fpixel[2],lpixel[2],inc[2]);
+*/
+ /* 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_write_compressed_img(fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the array to be returned */
+ LONGLONG *infpixel, /* I - 'bottom left corner' of the subsection */
+ LONGLONG *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 */
+ void *nullval, /* I - value for undefined pixels */
+ int *anynul, /* O - set to 1 if any values are null; else 0 */
+ fitsfile *outfptr, /* I - FITS file pointer */
+ int *status) /* IO - error status */
+/*
+ This is similar to fits_read_compressed_img, except that it writes
+ the pixels to the output image, on a tile by tile basis instead of returning
+ the array.
+*/
+{
+ 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;
+ double testnullval = 0.;
+ LONGLONG firstelem;
+
+ 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 = malloc ((fptr->Fptr)->maxtilelen * sizeof (short));
+ pixlen = sizeof(short);
+ if (nullval)
+ testnullval = *(short *) nullval;
+ }
+ else if (datatype == TINT)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (int));
+ pixlen = sizeof(int);
+ if (nullval)
+ testnullval = *(int *) nullval;
+ }
+ else if (datatype == TLONG)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (long));
+ pixlen = sizeof(long);
+ if (nullval)
+ testnullval = *(long *) nullval;
+ }
+ else if (datatype == TFLOAT)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (float));
+ pixlen = sizeof(float);
+ if (nullval)
+ testnullval = *(float *) nullval;
+ }
+ else if (datatype == TDOUBLE)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (double));
+ pixlen = sizeof(double);
+ if (nullval)
+ testnullval = *(double *) nullval;
+ }
+ else if (datatype == TUSHORT)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (unsigned short));
+ pixlen = sizeof(short);
+ if (nullval)
+ testnullval = *(unsigned short *) nullval;
+ }
+ else if (datatype == TUINT)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (unsigned int));
+ pixlen = sizeof(int);
+ if (nullval)
+ testnullval = *(unsigned int *) nullval;
+ }
+ else if (datatype == TULONG)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (unsigned long));
+ pixlen = sizeof(long);
+ if (nullval)
+ testnullval = *(unsigned long *) nullval;
+ }
+ else if (datatype == TBYTE || datatype == TSBYTE)
+ {
+ buffer = malloc ((fptr->Fptr)->maxtilelen * sizeof (char));
+ pixlen = 1;
+ if (nullval)
+ testnullval = *(unsigned char *) nullval;
+ }
+ else
+ {
+ ffpmsg("unsupported datatype for uncompressing image");
+ return(*status = BAD_DATATYPE);
+ }
+
+ /* If nullcheck ==1 and nullval == 0, then this means that the */
+ /* calling routine does not want to check for null pixels in the array */
+ if (nullcheck == 1 && testnullval == 0.)
+ nullcheck = 0;
+
+ if (buffer == NULL)
+ {
+ ffpmsg("Out of memory (fits_read_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++)
+ {
+ /* support for mirror-reversed image sections */
+ if (infpixel[ii] <= inlpixel[ii])
+ {
+ fpixel[ii] = (long) infpixel[ii];
+ lpixel[ii] = (long) inlpixel[ii];
+ inc[ii] = ininc[ii];
+ }
+ else
+ {
+ fpixel[ii] = (long) inlpixel[ii];
+ lpixel[ii] = (long) 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)
+ {
+ 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];
+ }
+
+ if (anynul)
+ *anynul = 0; /* initialize */
+
+ firstelem = 1;
+
+ /* 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);
+
+ /* write the image to the output file */
+
+ if (tilenul && anynul) {
+ /* this assumes that the tiled pixels are in the same order
+ as in the uncompressed FITS image. This is not necessarily
+ the case, but it almost alway is in practice.
+ Note that null checking is not performed for integer images,
+ so this could only be a problem for tile compressed floating
+ point images that use an unconventional tiling pattern.
+ */
+ fits_write_imgnull(outfptr, datatype, firstelem, thistilesize[0],
+ buffer, nullval, status);
+ } else {
+ fits_write_subset(outfptr, datatype, tfpixel, tlpixel,
+ buffer, status);
+ }
+
+ firstelem += thistilesize[0];
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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 */
+ LONGLONG fpixel, /* I - 'first pixel to read */
+ LONGLONG 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 nplane, inc[MAX_COMPRESS_DIM];
+ LONGLONG tfirst, tlast, last0, last1, dimsize[MAX_COMPRESS_DIM];
+ LONGLONG 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 = (long) 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 */
+ LONGLONG *firstcoord, /* coordinate of first pixel to read */
+ LONGLONG *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. */
+ LONGLONG 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 + (long) (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 + (long) ((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)
+ *anynul = 1;
+
+ *nread = *nread + (long) (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, doffset;
+ 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, "GZIP_2") )
+ (infptr->Fptr)->compress_type = GZIP_2;
+ else if (!FSTRCMP(value, "BZIP2_1") )
+ (infptr->Fptr)->compress_type = BZIP2_1;
+ else if (!FSTRCMP(value, "PLIO_1") )
+ (infptr->Fptr)->compress_type = PLIO_1;
+ else if (!FSTRCMP(value, "NOCOMPRESS") )
+ (infptr->Fptr)->compress_type = NOCOMPRESS;
+ else
+ {
+ ffpmsg("Unknown image compression type:");
+ ffpmsg(value);
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ /* get the floating point to integer quantization type, if present. */
+ /* FITS files produced before 2009 will not have this keyword */
+ tstatus = 0;
+ if (ffgky(infptr, TSTRING, "ZQUANTIZ", value, NULL, &tstatus) > 0)
+ {
+ (infptr->Fptr)->quantize_dither = 0;
+ } else {
+ if (!FSTRCMP(value, "NONE") )
+ (infptr->Fptr)->quantize_level = NO_QUANTIZE;
+ else if (!FSTRCMP(value, "SUBTRACTIVE_DITHER_1") )
+ (infptr->Fptr)->quantize_dither = SUBTRACTIVE_DITHER_1;
+ else
+ (infptr->Fptr)->quantize_dither = 0;
+ }
+
+ /* get the floating point quantization dithering offset, if present. */
+ /* FITS files produced before October 2009 will not have this keyword */
+ tstatus = 0;
+ if (ffgky(infptr, TINT, "ZDITHER0", &doffset, NULL, &tstatus) > 0)
+ {
+ /* by default start with 1st element of random sequence */
+ (infptr->Fptr)->dither_offset = 1;
+ } else {
+ (infptr->Fptr)->dither_offset = doffset;
+ }
+
+ 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);
+ }
+
+ tstatus = 0;
+ if (ffgky(infptr, TINT,"ZVAL2", &(infptr->Fptr)->rice_bytepix,
+ NULL, &tstatus) > 0)
+ {
+ (infptr->Fptr)->rice_bytepix = 4; /* default value */
+ }
+
+ if ((infptr->Fptr)->rice_blocksize < 16 &&
+ (infptr->Fptr)->rice_bytepix > 8) {
+ /* values are reversed */
+ tstatus = (infptr->Fptr)->rice_bytepix;
+ (infptr->Fptr)->rice_bytepix = (infptr->Fptr)->rice_blocksize;
+ (infptr->Fptr)->rice_blocksize = tstatus;
+ }
+ } else if ((infptr->Fptr)->compress_type == HCOMPRESS_1 ) {
+
+ if (ffgky(infptr, TFLOAT,"ZVAL1", &(infptr->Fptr)->hcomp_scale,
+ NULL, status) > 0)
+ {
+ ffpmsg("required ZVAL1 compression keyword not found");
+ return(*status);
+ }
+
+ tstatus = 0;
+ ffgky(infptr, TINT,"ZVAL2", &(infptr->Fptr)->hcomp_smooth,
+ 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)->zbitpix, (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;
+ ffgcno(infptr,CASEINSEN, "GZIP_COMPRESSED_DATA",
+ &(infptr->Fptr)->cn_gzip_data, &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)
+ {
+ /* ZBLANK 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 */
+
+ } else {
+ /* ZBLANK keyword doesn't exist; see if there is a BLANK keyword */
+ tstatus = 0;
+ if (ffgky(infptr, TINT, "BLANK", &(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;
+ (infptr->Fptr)->cn_actual_bzero = 0.0;
+ } else {
+ (infptr->Fptr)->cn_actual_bzero = (infptr->Fptr)->cn_bzero;
+ }
+
+ 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_copy_img2comp(fitsfile *infptr, fitsfile *outfptr, int *status)
+/*
+ This routine copies the header keywords from the uncompressed input image
+ and to the compressed image (in a binary table)
+*/
+{
+ char card[FLEN_CARD], card2[FLEN_CARD]; /* a header record */
+ int nkeys, nmore, ii, jj, tstatus, bitpix;
+
+ /* tile compressed image keyword translation table */
+ /* INPUT OUTPUT */
+ /* 01234567 01234567 */
+ char *patterns[][2] = {{"SIMPLE", "ZSIMPLE" },
+ {"XTENSION", "ZTENSION" },
+ {"BITPIX", "ZBITPIX" },
+ {"NAXIS", "ZNAXIS" },
+ {"NAXISm", "ZNAXISm" },
+ {"EXTEND", "ZEXTEND" },
+ {"BLOCKED", "ZBLOCKED"},
+ {"PCOUNT", "ZPCOUNT" },
+ {"GCOUNT", "ZGCOUNT" },
+
+ {"CHECKSUM","ZHECKSUM"}, /* save original checksums */
+ {"DATASUM", "ZDATASUM"},
+
+ {"*", "+" }}; /* copy all other keywords */
+ int npat;
+
+ if (*status > 0)
+ return(*status);
+
+ /* write a default EXTNAME keyword if it doesn't exist in input file*/
+ fits_read_card(infptr, "EXTNAME", card, status);
+
+ if (*status) {
+ *status = 0;
+ strcpy(card, "EXTNAME = 'COMPRESSED_IMAGE'");
+ fits_write_record(outfptr, card, status);
+ }
+
+ /* copy all the keywords from the input file to the output */
+ npat = sizeof(patterns)/sizeof(patterns[0][0])/2;
+ fits_translate_keywords(infptr, outfptr, 1, patterns, npat,
+ 0, 0, 0, status);
+
+
+ if ( (outfptr->Fptr)->request_lossy_int_compress != 0) {
+
+ /* request was made to compress integer images as if they had float pixels. */
+ /* If input image has positive bitpix value, then reset the output ZBITPIX */
+ /* value to -32. */
+
+ fits_read_key(infptr, TINT, "BITPIX", &bitpix, NULL, status);
+
+ if (*status <= 0 && bitpix > 0) {
+ fits_modify_key_lng(outfptr, "ZBITPIX", -32, NULL, status);
+
+ /* also delete the BSCALE, BZERO, and BLANK keywords */
+ tstatus = 0;
+ fits_delete_key(outfptr, "BSCALE", &tstatus);
+ tstatus = 0;
+ fits_delete_key(outfptr, "BZERO", &tstatus);
+ tstatus = 0;
+ fits_delete_key(outfptr, "BLANK", &tstatus);
+ }
+ }
+
+ /*
+ For compatibility with software that uses an older version of CFITSIO,
+ we must make certain that the new ZQUANTIZ keyword, if it exists, must
+ occur after the other peudo-required keywords (e.g., ZSIMPLE, ZBITPIX,
+ etc.). Do this by trying to delete the keyword. If that succeeds (and
+ thus the keyword did exist) then rewrite the keyword at the end of header.
+ In principle this should not be necessary once all software has upgraded
+ to a newer version of CFITSIO (version number greater than 3.181, newer
+ than August 2009).
+
+ Do the same for the new ZDITHER0 keyword.
+ */
+
+ tstatus = 0;
+ if (fits_read_card(outfptr, "ZQUANTIZ", card, &tstatus) == 0)
+ {
+ fits_delete_key(outfptr, "ZQUANTIZ", status);
+
+ /* rewrite the deleted keyword at the end of the header */
+ fits_write_record(outfptr, card, status);
+
+ fits_write_history(outfptr,
+ "Image was compressed by CFITSIO using scaled integer quantization:", status);
+ sprintf(card2, " q = %f / quantized level scaling parameter",
+ (outfptr->Fptr)->quantize_level);
+ fits_write_history(outfptr, card2, status);
+ fits_write_history(outfptr, card+10, status);
+ }
+
+ tstatus = 0;
+ if (fits_read_card(outfptr, "ZDITHER0", card, &tstatus) == 0)
+ {
+ fits_delete_key(outfptr, "ZDITHER0", status);
+
+ /* rewrite the deleted keyword at the end of the header */
+ fits_write_record(outfptr, card, status);
+ }
+
+
+ ffghsp(infptr, &nkeys, &nmore, status); /* get number of keywords in image */
+
+ nmore = nmore / 36; /* how many completely empty header blocks are there? */
+
+ /* preserve the same number of spare header blocks in the output header */
+
+ for (jj = 0; jj < nmore; jj++)
+ for (ii = 0; ii < 36; ii++)
+ fits_write_record(outfptr, " ", status);
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_copy_comp2img(fitsfile *infptr, fitsfile *outfptr,
+ int norec, int *status)
+/*
+ This routine copies the header keywords from the compressed input image
+ and to the uncompressed image (in a binary table)
+*/
+{
+ char card[FLEN_CARD]; /* a header record */
+ char *patterns[40][2];
+ char negative[] = "-";
+ int ii,jj, npat, nreq, nsp, tstatus = 0;
+ int nkeys, nmore;
+
+ /* tile compressed image keyword translation table */
+ /* INPUT OUTPUT */
+ /* 01234567 01234567 */
+
+ /* only translate these if required keywords not already written */
+ char *reqkeys[][2] = {
+ {"ZSIMPLE", "SIMPLE" },
+ {"ZTENSION", "XTENSION"},
+ {"ZBITPIX", "BITPIX" },
+ {"ZNAXIS", "NAXIS" },
+ {"ZNAXISm", "NAXISm" },
+ {"ZEXTEND", "EXTEND" },
+ {"ZBLOCKED", "BLOCKED"},
+ {"ZPCOUNT", "PCOUNT" },
+ {"ZGCOUNT", "GCOUNT" },
+ {"ZHECKSUM", "CHECKSUM"}, /* restore original checksums */
+ {"ZDATASUM", "DATASUM"}};
+
+ /* other special keywords */
+ char *spkeys[][2] = {
+ {"XTENSION", "-" },
+ {"BITPIX", "-" },
+ {"NAXIS", "-" },
+ {"NAXISm", "-" },
+ {"PCOUNT", "-" },
+ {"GCOUNT", "-" },
+ {"TFIELDS", "-" },
+ {"TTYPEm", "-" },
+ {"TFORMm", "-" },
+ {"ZIMAGE", "-" },
+ {"ZQUANTIZ", "-" },
+ {"ZDITHER0", "-" },
+ {"ZTILEm", "-" },
+ {"ZCMPTYPE", "-" },
+ {"ZBLANK", "-" },
+ {"ZNAMEm", "-" },
+ {"ZVALm", "-" },
+
+ {"CHECKSUM","-" }, /* delete checksums */
+ {"DATASUM", "-" },
+ {"EXTNAME", "+" }, /* we may change this, below */
+ {"*", "+" }};
+
+
+ if (*status > 0)
+ return(*status);
+
+ nreq = sizeof(reqkeys)/sizeof(reqkeys[0][0])/2;
+ nsp = sizeof(spkeys)/sizeof(spkeys[0][0])/2;
+
+ /* construct translation patterns */
+
+ for (ii = 0; ii < nreq; ii++) {
+ patterns[ii][0] = reqkeys[ii][0];
+
+ if (norec)
+ patterns[ii][1] = negative;
+ else
+ patterns[ii][1] = reqkeys[ii][1];
+ }
+
+ for (ii = 0; ii < nsp; ii++) {
+ patterns[ii+nreq][0] = spkeys[ii][0];
+ patterns[ii+nreq][1] = spkeys[ii][1];
+ }
+
+ npat = nreq + nsp;
+
+ /* see if the EXTNAME keyword should be copied or not */
+ fits_read_card(infptr, "EXTNAME", card, &tstatus);
+
+ if (tstatus == 0) {
+ if (!strncmp(card, "EXTNAME = 'COMPRESSED_IMAGE'", 28))
+ patterns[npat-2][1] = negative;
+ }
+
+ /* translate and copy the keywords from the input file to the output */
+ fits_translate_keywords(infptr, outfptr, 1, patterns, npat,
+ 0, 0, 0, status);
+
+ ffghsp(infptr, &nkeys, &nmore, status); /* get number of keywords in image */
+
+ nmore = nmore / 36; /* how many completely empty header blocks are there? */
+
+ /* preserve the same number of spare header blocks in the output header */
+
+ for (jj = 0; jj < nmore; jj++)
+ for (ii = 0; ii < 36; ii++)
+ fits_write_record(outfptr, " ", status);
+
+
+ return (*status);
+}
+/*--------------------------------------------------------------------------*/
+int imcomp_copy_prime2img(fitsfile *infptr, fitsfile *outfptr, int *status)
+/*
+ This routine copies any unexpected keywords from the primary array
+ of the compressed input image into the header of the uncompressed image
+ (which is the primary array of the output file).
+*/
+{
+ int nsp;
+
+ /* keywords that will not be copied */
+ char *spkeys[][2] = {
+ {"SIMPLE", "-" },
+ {"BITPIX", "-" },
+ {"NAXIS", "-" },
+ {"NAXISm", "-" },
+ {"PCOUNT", "-" },
+ {"EXTEND", "-" },
+ {"GCOUNT", "-" },
+ {"CHECKSUM","-" },
+ {"DATASUM", "-" },
+ {"EXTNAME", "-" },
+ {"HISTORY", "-" },
+ {"COMMENT", "-" },
+ {"*", "+" }};
+
+ if (*status > 0)
+ return(*status);
+
+ nsp = sizeof(spkeys)/sizeof(spkeys[0][0])/2;
+
+ /* translate and copy the keywords from the input file to the output */
+ fits_translate_keywords(infptr, outfptr, 1, spkeys, nsp,
+ 0, 0, 0, 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;
+ int tiledatatype, pixlen; /* uncompressed integer data */
+ size_t idatalen, tilebytesize;
+ int ii, tnull; /* value in the data which represents nulls */
+ unsigned char *cbuf; /* compressed data */
+ unsigned char charnull = 0;
+ short snull = 0;
+ int blocksize;
+ float fnulval=0;
+ float *tempfloat = 0;
+ double dnulval=0;
+ double bscale, bzero, actual_bzero, dummy = 0; /* scaling parameters */
+ long nelem = 0, offset = 0, tilesize; /* number of bytes */
+ int smooth, nx, ny, scale; /* hcompress parameters */
+
+ if (*status > 0)
+ return(*status);
+
+ /* **************************************************************** */
+ /* check if this tile was cached; if so, just copy it out */
+ if (nrow == (infptr->Fptr)->tilerow && datatype == (infptr->Fptr)->tiletype ) {
+
+ memcpy(buffer, (infptr->Fptr)->tiledata, (infptr->Fptr)->tiledatasize);
+
+ if (nullcheck == 2)
+ memcpy(bnullarray, (infptr->Fptr)->tilenullarray, tilelen);
+
+ *anynul = (infptr->Fptr)->tileanynull;
+ 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) /* special case: tile was not compressed normally */
+ {
+ if ((infptr->Fptr)->cn_uncompressed >= 1 ) {
+
+ /* This option of writing the uncompressed floating point data */
+ /* to the tile compressed file was used until about May 2011. */
+ /* This was replaced by the more efficient option of gzipping the */
+ /* floating point data before writing it to the tile-compressed file */
+
+ /* no compressed data, so simply read the uncompressed data */
+ /* directly from the UNCOMPRESSED_DATA column */
+ ffgdes (infptr, (infptr->Fptr)->cn_uncompressed, nrow, &nelem,
+ &offset, status);
+
+ if (nelem == 0 && offset == 0) /* this should never happen */
+ return (*status = NO_COMPRESSED_TILE);
+
+ if (nullcheck <= 1) { /* set any null values in the array = nulval */
+ fits_read_col(infptr, datatype, (infptr->Fptr)->cn_uncompressed,
+ nrow, 1, nelem, nulval, buffer, anynul, status);
+ } else { /* set the bnullarray = 1 for any null values in the array */
+ fits_read_colnull(infptr, datatype, (infptr->Fptr)->cn_uncompressed,
+ nrow, 1, nelem, buffer, bnullarray, anynul, status);
+ }
+ } else if ((infptr->Fptr)->cn_gzip_data >= 1) {
+
+ /* This is the newer option, that was introduced in May 2011 */
+ /* floating point data was not quantized, so read the losslessly */
+ /* compressed data from the GZIP_COMPRESSED_DATA column */
+
+ ffgdes (infptr, (infptr->Fptr)->cn_gzip_data, nrow, &nelem,
+ &offset, status);
+
+ if (nelem == 0 && offset == 0) /* this should never happen */
+ return (*status = NO_COMPRESSED_TILE);
+
+ /* allocate memory for the compressed tile of data */
+ cbuf = (unsigned char *) malloc (nelem);
+ if (cbuf == NULL) {
+ ffpmsg("error allocating memory for gzipped tile (imcomp_decompress_tile)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* read array of compressed bytes */
+ if (fits_read_col(infptr, TBYTE, (infptr->Fptr)->cn_gzip_data, nrow,
+ 1, nelem, &charnull, cbuf, NULL, status) > 0) {
+ ffpmsg("error reading compressed byte stream from binary table");
+ free (cbuf);
+ return (*status);
+ }
+
+ /* size of the returned (uncompressed) data buffer, in bytes */
+ if ((infptr->Fptr)->zbitpix == FLOAT_IMG) {
+ idatalen = tilelen * sizeof(float);
+ } else if ((infptr->Fptr)->zbitpix == DOUBLE_IMG) {
+ idatalen = tilelen * sizeof(double);
+ } else {
+ /* this should never happen! */
+ ffpmsg("incompatible data type in gzipped floating-point tile-compressed image");
+ free (cbuf);
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ if (datatype == TDOUBLE && (infptr->Fptr)->zbitpix == FLOAT_IMG) {
+ /* have to allocat a temporary buffer for the uncompressed data in the */
+ /* case where a gzipped "float" tile is returned as a "double" array */
+ tempfloat = (float*) malloc (idatalen);
+
+ if (tempfloat == NULL) {
+ ffpmsg("Memory allocation failure for tempfloat. (imcomp_decompress_tile)");
+ free (cbuf);
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* uncompress the data into temp buffer */
+ if (uncompress2mem_from_mem ((char *)cbuf, nelem,
+ (char **) &tempfloat, &idatalen, NULL, &tilebytesize, status)) {
+ ffpmsg("failed to gunzip the image tile");
+ free (tempfloat);
+ free (cbuf);
+ return (*status);
+ }
+ } else {
+
+ /* uncompress the data directly into the output buffer in all other cases */
+ if (uncompress2mem_from_mem ((char *)cbuf, nelem,
+ (char **) &buffer, &idatalen, NULL, &tilebytesize, status)) {
+ ffpmsg("failed to gunzip the image tile");
+ free (cbuf);
+ return (*status);
+ }
+ }
+
+ free(cbuf);
+
+ /* do byte swapping and null value substitution for the tile of pixels */
+ if (tilebytesize == 4 * tilelen) { /* float pixels */
+
+#if BYTESWAPPED
+ if (tempfloat)
+ ffswap4((int *) tempfloat, tilelen);
+ else
+ ffswap4((int *) buffer, tilelen);
+#endif
+ if (datatype == TFLOAT) {
+ if (nulval) {
+ fnulval = *(float *) nulval;
+ }
+
+ fffr4r4((float *) buffer, (long) tilelen, 1., 0., nullcheck,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ } else if (datatype == TDOUBLE) {
+ if (nulval) {
+ dnulval = *(double *) nulval;
+ }
+
+ /* note that the R*4 data are in the tempfloat array in this case */
+ fffr4r8((float *) tempfloat, (long) tilelen, 1., 0., nullcheck,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ free(tempfloat);
+
+ } else {
+ ffpmsg("implicit data type conversion is not supported for gzipped image tiles");
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+ } else if (tilebytesize == 8 * tilelen) { /* double pixels */
+
+#if BYTESWAPPED
+ ffswap8((double *) buffer, tilelen);
+#endif
+ if (datatype == TFLOAT) {
+ if (nulval) {
+ fnulval = *(float *) nulval;
+ }
+
+ fffr8r4((double *) buffer, (long) tilelen, 1., 0., nullcheck,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ } else if (datatype == TDOUBLE) {
+ if (nulval) {
+ dnulval = *(double *) nulval;
+ }
+
+ fffr8r8((double *) buffer, (long) tilelen, 1., 0., nullcheck,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ } else {
+ ffpmsg("implicit data type conversion is not supported in tile-compressed images");
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+ } else {
+ ffpmsg("error: uncompressed tile has wrong size");
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ /* end of special case of losslessly gzipping a floating-point image tile */
+ } else { /* this should never happen */
+ *status = NO_COMPRESSED_TILE;
+ }
+
+ return(*status);
+ }
+
+ /* **************************************************************** */
+ /* deal with the normal case of a compressed tile of pixels */
+ if (nullcheck == 2) {
+ for (ii = 0; ii < tilelen; ii++) /* initialize the null flage array */
+ bnullarray[ii] = 0;
+ }
+
+ if (anynul)
+ *anynul = 0;
+
+ /* get linear scaling and offset values, if they exist */
+ actual_bzero = (infptr->Fptr)->cn_actual_bzero;
+ 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");
+ return (*status);
+ }
+
+ /* test if floating-point FITS image also has non-default BSCALE and */
+ /* BZERO keywords. If so, we have to combine the 2 linear scaling factors. */
+
+ if ( ((infptr->Fptr)->zbitpix == FLOAT_IMG ||
+ (infptr->Fptr)->zbitpix == DOUBLE_IMG )
+ &&
+ ((infptr->Fptr)->cn_bscale != 1.0 ||
+ (infptr->Fptr)->cn_bzero != 0.0 ) )
+ {
+ bscale = bscale * (infptr->Fptr)->cn_bscale;
+ bzero = bzero * (infptr->Fptr)->cn_bscale + (infptr->Fptr)->cn_bzero;
+ }
+ }
+
+ 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");
+ return (*status);
+ }
+ }
+
+ /* ************************************************************* */
+ /* allocate memory for the uncompressed array of tile integers */
+ /* The size depends on the datatype and the compression type. */
+
+ if ((infptr->Fptr)->compress_type == HCOMPRESS_1 &&
+ ((infptr->Fptr)->zbitpix != BYTE_IMG &&
+ (infptr->Fptr)->zbitpix != SHORT_IMG) ) {
+
+ idatalen = tilelen * sizeof(LONGLONG); /* 8 bytes per pixel */
+
+ } else if ( (infptr->Fptr)->compress_type == RICE_1 &&
+ (infptr->Fptr)->zbitpix == BYTE_IMG &&
+ (infptr->Fptr)->rice_bytepix == 1) {
+
+ idatalen = tilelen * sizeof(char); /* 1 byte per pixel */
+ } else if ( ( (infptr->Fptr)->compress_type == GZIP_1 ||
+ (infptr->Fptr)->compress_type == GZIP_2 ||
+ (infptr->Fptr)->compress_type == BZIP2_1 ) &&
+ (infptr->Fptr)->zbitpix == BYTE_IMG ) {
+
+ idatalen = tilelen * sizeof(char); /* 1 byte per pixel */
+ } else if ( (infptr->Fptr)->compress_type == RICE_1 &&
+ (infptr->Fptr)->zbitpix == SHORT_IMG &&
+ (infptr->Fptr)->rice_bytepix == 2) {
+
+ idatalen = tilelen * sizeof(short); /* 2 bytes per pixel */
+ } else if ( ( (infptr->Fptr)->compress_type == GZIP_1 ||
+ (infptr->Fptr)->compress_type == GZIP_2 ||
+ (infptr->Fptr)->compress_type == BZIP2_1 ) &&
+ (infptr->Fptr)->zbitpix == SHORT_IMG ) {
+
+ idatalen = tilelen * sizeof(short); /* 2 bytes per pixel */
+ } else if ( ( (infptr->Fptr)->compress_type == GZIP_1 ||
+ (infptr->Fptr)->compress_type == GZIP_2 ||
+ (infptr->Fptr)->compress_type == BZIP2_1 ) &&
+ (infptr->Fptr)->zbitpix == DOUBLE_IMG ) {
+
+ idatalen = tilelen * sizeof(double); /* 8 bytes per pixel */
+ } else {
+ idatalen = tilelen * sizeof(int); /* all other cases have int pixels */
+ }
+
+ idata = (int*) malloc (idatalen);
+ if (idata == NULL) {
+ ffpmsg("Memory allocation failure for idata. (imcomp_decompress_tile)");
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* ************************************************************* */
+ /* allocate memory for the compressed bytes */
+
+ if ((infptr->Fptr)->compress_type == PLIO_1) {
+ cbuf = (unsigned char *) malloc (nelem * sizeof (short));
+ } else {
+ cbuf = (unsigned char *) malloc (nelem);
+ }
+ if (cbuf == NULL) {
+ ffpmsg("Out of memory for cbuf. (imcomp_decompress_tile)");
+ free(idata);
+ return (*status = MEMORY_ALLOCATION);
+ }
+
+ /* ************************************************************* */
+ /* read the compressed bytes from the FITS file */
+
+ if ((infptr->Fptr)->compress_type == PLIO_1) {
+ fits_read_col(infptr, TSHORT, (infptr->Fptr)->cn_compressed, nrow,
+ 1, nelem, &snull, (short *) cbuf, NULL, status);
+ } else {
+ fits_read_col(infptr, TBYTE, (infptr->Fptr)->cn_compressed, nrow,
+ 1, nelem, &charnull, cbuf, NULL, status);
+ }
+
+ if (*status > 0) {
+ ffpmsg("error reading compressed byte stream from binary table");
+ free (cbuf);
+ free(idata);
+ return (*status);
+ }
+
+ /* ************************************************************* */
+ /* call the algorithm-specific code to uncompress the tile */
+
+ if ((infptr->Fptr)->compress_type == RICE_1) {
+
+ blocksize = (infptr->Fptr)->rice_blocksize;
+
+ if ((infptr->Fptr)->rice_bytepix == 1 ) {
+ *status = fits_rdecomp_byte (cbuf, nelem, (unsigned char *)idata,
+ tilelen, blocksize);
+ tiledatatype = TBYTE;
+ } else if ((infptr->Fptr)->rice_bytepix == 2 ) {
+ *status = fits_rdecomp_short (cbuf, nelem, (unsigned short *)idata,
+ tilelen, blocksize);
+ tiledatatype = TSHORT;
+ } else {
+ *status = fits_rdecomp (cbuf, nelem, (unsigned int *)idata,
+ tilelen, blocksize);
+ tiledatatype = TINT;
+ }
+
+ /* ************************************************************* */
+ } else if ((infptr->Fptr)->compress_type == HCOMPRESS_1) {
+
+ smooth = (infptr->Fptr)->hcomp_smooth;
+
+ if ( ((infptr->Fptr)->zbitpix == BYTE_IMG || (infptr->Fptr)->zbitpix == SHORT_IMG)) {
+ *status = fits_hdecompress(cbuf, smooth, idata, &nx, &ny,
+ &scale, status);
+ } else { /* zbitpix = LONG_IMG (32) */
+ /* idata must have been allocated twice as large for this to work */
+ *status = fits_hdecompress64(cbuf, smooth, (LONGLONG *) idata, &nx, &ny,
+ &scale, status);
+ }
+
+ tiledatatype = TINT;
+
+ /* ************************************************************* */
+ } else if ((infptr->Fptr)->compress_type == PLIO_1) {
+
+ pl_l2pi ((short *) cbuf, 1, idata, tilelen); /* uncompress the data */
+ tiledatatype = TINT;
+
+ /* ************************************************************* */
+ } else if ( ((infptr->Fptr)->compress_type == GZIP_1) ||
+ ((infptr->Fptr)->compress_type == GZIP_2) ) {
+
+ uncompress2mem_from_mem ((char *)cbuf, nelem,
+ (char **) &idata, &idatalen, realloc, &tilebytesize, status);
+
+ /* determine the data type of the uncompressed array, and */
+ /* do byte unshuffling and unswapping if needed */
+ if (tilebytesize == (size_t) (tilelen * 2)) {
+ /* this is a short I*2 array */
+ tiledatatype = TSHORT;
+
+ if ( (infptr->Fptr)->compress_type == GZIP_2 )
+ fits_unshuffle_2bytes((char *) idata, tilelen, status);
+
+#if BYTESWAPPED
+ ffswap2((short *) idata, tilelen);
+#endif
+
+ } else if (tilebytesize == (size_t) (tilelen * 4)) {
+ /* this is a int I*4 array (or maybe R*4) */
+ tiledatatype = TINT;
+
+ if ( (infptr->Fptr)->compress_type == GZIP_2 )
+ fits_unshuffle_4bytes((char *) idata, tilelen, status);
+
+#if BYTESWAPPED
+ ffswap4(idata, tilelen);
+#endif
+
+ } else if (tilebytesize == (size_t) (tilelen * 8)) {
+ /* this is a R*8 double array */
+ tiledatatype = TDOUBLE;
+
+ if ( (infptr->Fptr)->compress_type == GZIP_2 )
+ fits_unshuffle_8bytes((char *) idata, tilelen, status);
+#if BYTESWAPPED
+ ffswap8((double *) idata, tilelen);
+#endif
+
+ } else if (tilebytesize == (size_t) tilelen) {
+
+ /* this is an unsigned char I*1 array */
+ tiledatatype = TBYTE;
+
+ } else {
+ ffpmsg("error: uncompressed tile has wrong size");
+ free(idata);
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ /* ************************************************************* */
+ } else if ((infptr->Fptr)->compress_type == BZIP2_1) {
+
+/* BZIP2 is not supported in the public release; this is only for test purposes
+
+ if (BZ2_bzBuffToBuffDecompress ((char *) idata, &idatalen,
+ (char *)cbuf, (unsigned int) nelem, 0, 0) )
+*/
+ {
+ ffpmsg("bzip2 decompression error");
+ free(idata);
+ free (cbuf);
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ if ((infptr->Fptr)->zbitpix == BYTE_IMG) {
+ tiledatatype = TBYTE;
+ } else if ((infptr->Fptr)->zbitpix == SHORT_IMG) {
+ tiledatatype = TSHORT;
+#if BYTESWAPPED
+ ffswap2((short *) idata, tilelen);
+#endif
+ } else {
+ tiledatatype = TINT;
+#if BYTESWAPPED
+ ffswap4(idata, tilelen);
+#endif
+ }
+
+ /* ************************************************************* */
+ } else {
+ ffpmsg("unknown compression algorithm");
+ free(idata);
+ return (*status = DATA_DECOMPRESSION_ERR);
+ }
+
+ free(cbuf);
+ if (*status) { /* error uncompressing the tile */
+ free(idata);
+ return (*status);
+ }
+
+ /* ************************************************************* */
+ /* 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)
+ {
+ pixlen = sizeof(short);
+
+ if ((infptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ /* the floating point pixels were losselessly compressed with GZIP */
+ /* Just have to copy the values to the output array */
+
+ if (tiledatatype == TINT) {
+ fffr4i2((float *) idata, tilelen, bscale, bzero, nullcheck,
+ *(short *) nulval, bnullarray, anynul,
+ (short *) buffer, status);
+ } else {
+ fffr8i2((double *) idata, tilelen, bscale, bzero, nullcheck,
+ *(short *) nulval, bnullarray, anynul,
+ (short *) buffer, status);
+ }
+ } else if (tiledatatype == TINT)
+ if ((infptr->Fptr)->compress_type == PLIO_1 &&
+ bzero == 0. && actual_bzero == 32768.) {
+ /* special case where unsigned 16-bit integers have been */
+ /* offset by +32768 when using PLIO */
+ fffi4i2(idata, tilelen, bscale, -32768., nullcheck, tnull,
+ *(short *) nulval, bnullarray, anynul,
+ (short *) buffer, status);
+ } else {
+ fffi4i2(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(short *) nulval, bnullarray, anynul,
+ (short *) buffer, status);
+ }
+ else if (tiledatatype == TSHORT)
+ fffi2i2((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ *(short *) nulval, bnullarray, anynul,
+ (short *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1i2((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ *(short *) nulval, bnullarray, anynul,
+ (short *) buffer, status);
+ }
+ else if (datatype == TINT)
+ {
+ pixlen = sizeof(int);
+
+ if ((infptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ /* the floating point pixels were losselessly compressed with GZIP */
+ /* Just have to copy the values to the output array */
+
+ if (tiledatatype == TINT) {
+ fffr4int((float *) idata, tilelen, bscale, bzero, nullcheck,
+ *(int *) nulval, bnullarray, anynul,
+ (int *) buffer, status);
+ } else {
+ fffr8int((double *) idata, tilelen, bscale, bzero, nullcheck,
+ *(int *) nulval, bnullarray, anynul,
+ (int *) buffer, status);
+ }
+ } else if (tiledatatype == TINT)
+ fffi4int(idata, (long) tilelen, bscale, bzero, nullcheck, tnull,
+ *(int *) nulval, bnullarray, anynul,
+ (int *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2int((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ *(int *) nulval, bnullarray, anynul,
+ (int *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1int((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ *(int *) nulval, bnullarray, anynul,
+ (int *) buffer, status);
+ }
+ else if (datatype == TLONG)
+ {
+ pixlen = sizeof(long);
+
+ if ((infptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ /* the floating point pixels were losselessly compressed with GZIP */
+ /* Just have to copy the values to the output array */
+
+ if (tiledatatype == TINT) {
+ fffr4i4((float *) idata, tilelen, bscale, bzero, nullcheck,
+ *(long *) nulval, bnullarray, anynul,
+ (long *) buffer, status);
+ } else {
+ fffr8i4((double *) idata, tilelen, bscale, bzero, nullcheck,
+ *(long *) nulval, bnullarray, anynul,
+ (long *) buffer, status);
+ }
+ } else if (tiledatatype == TINT)
+ fffi4i4(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(long *) nulval, bnullarray, anynul,
+ (long *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2i4((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ *(long *) nulval, bnullarray, anynul,
+ (long *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1i4((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ *(long *) nulval, bnullarray, anynul,
+ (long *) buffer, status);
+ }
+ else if (datatype == TFLOAT)
+ {
+ pixlen = sizeof(float);
+ if (nulval) {
+ fnulval = *(float *) nulval;
+ }
+
+ if ((infptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ /* the floating point pixels were losselessly compressed with GZIP */
+ /* Just have to copy the values to the output array */
+
+ if (tiledatatype == TINT) {
+ fffr4r4((float *) idata, tilelen, bscale, bzero, nullcheck,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ } else {
+ fffr8r4((double *) idata, tilelen, bscale, bzero, nullcheck,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ }
+
+ } else if ((infptr->Fptr)->quantize_dither == SUBTRACTIVE_DITHER_1) {
+
+ /* use the new dithering algorithm (introduced in July 2009) */
+
+ if (tiledatatype == TINT)
+ unquantize_i4r4(nrow + (infptr->Fptr)->dither_offset - 1, idata,
+ tilelen, bscale, bzero, nullcheck, tnull,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ unquantize_i2r4(nrow + (infptr->Fptr)->dither_offset - 1, (short *)idata,
+ tilelen, bscale, bzero, nullcheck, (short) tnull,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ unquantize_i1r4(nrow + (infptr->Fptr)->dither_offset - 1, (unsigned char *)idata,
+ tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+
+ } else { /* use the old "round to nearest level" quantization algorithm */
+
+ if (tiledatatype == TINT)
+ fffi4r4(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2r4((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1r4((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ fnulval, bnullarray, anynul,
+ (float *) buffer, status);
+ }
+ }
+ else if (datatype == TDOUBLE)
+ {
+ pixlen = sizeof(double);
+ if (nulval) {
+ dnulval = *(double *) nulval;
+ }
+
+ if ((infptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ /* the floating point pixels were losselessly compressed with GZIP */
+ /* Just have to copy the values to the output array */
+
+ if (tiledatatype == TINT) {
+ fffr4r8((float *) idata, tilelen, bscale, bzero, nullcheck,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ } else {
+ fffr8r8((double *) idata, tilelen, bscale, bzero, nullcheck,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ }
+
+ } else if ((infptr->Fptr)->quantize_dither == SUBTRACTIVE_DITHER_1) {
+
+ /* use the new dithering algorithm (introduced in July 2009) */
+ if (tiledatatype == TINT)
+ unquantize_i4r8(nrow + (infptr->Fptr)->dither_offset - 1, idata,
+ tilelen, bscale, bzero, nullcheck, tnull,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ unquantize_i2r8(nrow + (infptr->Fptr)->dither_offset - 1, (short *)idata,
+ tilelen, bscale, bzero, nullcheck, (short) tnull,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ unquantize_i1r8(nrow + (infptr->Fptr)->dither_offset - 1, (unsigned char *)idata,
+ tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+
+ } else { /* use the old "round to nearest level" quantization algorithm */
+
+ if (tiledatatype == TINT)
+ fffi4r8(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2r8((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1r8((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ dnulval, bnullarray, anynul,
+ (double *) buffer, status);
+ }
+ }
+ else if (datatype == TBYTE)
+ {
+ pixlen = sizeof(char);
+ if (tiledatatype == TINT)
+ fffi4i1(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(unsigned char *) nulval, bnullarray, anynul,
+ (unsigned char *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2i1((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ *(unsigned char *) nulval, bnullarray, anynul,
+ (unsigned char *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1i1((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ *(unsigned char *) nulval, bnullarray, anynul,
+ (unsigned char *) buffer, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ pixlen = sizeof(char);
+ if (tiledatatype == TINT)
+ fffi4s1(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(signed char *) nulval, bnullarray, anynul,
+ (signed char *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2s1((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ *(signed char *) nulval, bnullarray, anynul,
+ (signed char *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1s1((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ *(signed char *) nulval, bnullarray, anynul,
+ (signed char *) buffer, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ pixlen = sizeof(short);
+
+ if ((infptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ /* the floating point pixels were losselessly compressed with GZIP */
+ /* Just have to copy the values to the output array */
+
+ if (tiledatatype == TINT) {
+ fffr4u2((float *) idata, tilelen, bscale, bzero, nullcheck,
+ *(unsigned short *) nulval, bnullarray, anynul,
+ (unsigned short *) buffer, status);
+ } else {
+ fffr8u2((double *) idata, tilelen, bscale, bzero, nullcheck,
+ *(unsigned short *) nulval, bnullarray, anynul,
+ (unsigned short *) buffer, status);
+ }
+ } else if (tiledatatype == TINT)
+ fffi4u2(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(unsigned short *) nulval, bnullarray, anynul,
+ (unsigned short *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2u2((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ *(unsigned short *) nulval, bnullarray, anynul,
+ (unsigned short *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1u2((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ *(unsigned short *) nulval, bnullarray, anynul,
+ (unsigned short *) buffer, status);
+ }
+ else if (datatype == TUINT)
+ {
+ pixlen = sizeof(int);
+
+ if ((infptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ /* the floating point pixels were losselessly compressed with GZIP */
+ /* Just have to copy the values to the output array */
+
+ if (tiledatatype == TINT) {
+ fffr4uint((float *) idata, tilelen, bscale, bzero, nullcheck,
+ *(unsigned int *) nulval, bnullarray, anynul,
+ (unsigned int *) buffer, status);
+ } else {
+ fffr8uint((double *) idata, tilelen, bscale, bzero, nullcheck,
+ *(unsigned int *) nulval, bnullarray, anynul,
+ (unsigned int *) buffer, status);
+ }
+ } else if (tiledatatype == TINT)
+ fffi4uint(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(unsigned int *) nulval, bnullarray, anynul,
+ (unsigned int *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2uint((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ *(unsigned int *) nulval, bnullarray, anynul,
+ (unsigned int *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1uint((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ *(unsigned int *) nulval, bnullarray, anynul,
+ (unsigned int *) buffer, status);
+ }
+ else if (datatype == TULONG)
+ {
+ pixlen = sizeof(long);
+
+ if ((infptr->Fptr)->quantize_level == NO_QUANTIZE) {
+ /* the floating point pixels were losselessly compressed with GZIP */
+ /* Just have to copy the values to the output array */
+
+ if (tiledatatype == TINT) {
+ fffr4u4((float *) idata, tilelen, bscale, bzero, nullcheck,
+ *(unsigned long *) nulval, bnullarray, anynul,
+ (unsigned long *) buffer, status);
+ } else {
+ fffr8u4((double *) idata, tilelen, bscale, bzero, nullcheck,
+ *(unsigned long *) nulval, bnullarray, anynul,
+ (unsigned long *) buffer, status);
+ }
+ } else if (tiledatatype == TINT)
+ fffi4u4(idata, tilelen, bscale, bzero, nullcheck, tnull,
+ *(unsigned long *) nulval, bnullarray, anynul,
+ (unsigned long *) buffer, status);
+ else if (tiledatatype == TSHORT)
+ fffi2u4((short *)idata, tilelen, bscale, bzero, nullcheck, (short) tnull,
+ *(unsigned long *) nulval, bnullarray, anynul,
+ (unsigned long *) buffer, status);
+ else if (tiledatatype == TBYTE)
+ fffi1u4((unsigned char *)idata, tilelen, bscale, bzero, nullcheck, (unsigned char) tnull,
+ *(unsigned long *) nulval, bnullarray, anynul,
+ (unsigned long *) buffer, status);
+ }
+ else
+ *status = BAD_DATATYPE;
+
+ free(idata); /* don't need the uncompressed tile any more */
+
+ /* **************************************************************** */
+ /* cache the tile, in case the application wants it again */
+
+ /* Don't cache the tile if tile is a single row of the image;
+ it is less likely that the cache will be used in this cases,
+ so it is not worth the time and the memory overheads.
+ */
+ if ((infptr->Fptr)->znaxis[0] != (infptr->Fptr)->tilesize[0] ||
+ (infptr->Fptr)->tilesize[1] != 1 )
+ {
+ tilesize = pixlen * tilelen;
+
+ /* check that tile size/type has not changed */
+ if (tilesize != (infptr->Fptr)->tiledatasize ||
+ datatype != (infptr->Fptr)->tiletype ) {
+
+ if ((infptr->Fptr)->tiledata) {
+ free((infptr->Fptr)->tiledata);
+ }
+
+ (infptr->Fptr)->tiledata = 0;
+
+ if ((infptr->Fptr)->tilenullarray) {
+ free((infptr->Fptr)->tilenullarray);
+ }
+
+ (infptr->Fptr)->tilenullarray = 0;
+ (infptr->Fptr)->tilerow = 0;
+ (infptr->Fptr)->tiledatasize = 0;
+ (infptr->Fptr)->tiletype = 0;
+
+ /* allocate new array(s) */
+ (infptr->Fptr)->tiledata = malloc(tilesize);
+ if ((infptr->Fptr)->tiledata == 0)
+ return (*status);
+
+ if (nullcheck == 2) { /* also need array of null pixel flags */
+ (infptr->Fptr)->tilenullarray = malloc(tilelen);
+ if ((infptr->Fptr)->tilenullarray == 0)
+ return (*status);
+ }
+
+ (infptr->Fptr)->tiledatasize = tilesize;
+ (infptr->Fptr)->tiletype = datatype;
+ }
+
+ /* copy the tile array(s) into cache buffer */
+ memcpy((infptr->Fptr)->tiledata, buffer, tilesize);
+
+ if (nullcheck == 2) {
+ if ((infptr->Fptr)->tilenullarray == 0) {
+ (infptr->Fptr)->tilenullarray = malloc(tilelen);
+ }
+ memcpy((infptr->Fptr)->tilenullarray, bnullarray, tilelen);
+ }
+
+ (infptr->Fptr)->tilerow = nrow;
+ (infptr->Fptr)->tileanynull = *anynul;
+ }
+
+ 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);
+}
+/*--------------------------------------------------------------------------*/
+static int unquantize_i1r4(long row, /* tile number = row number in table */
+ 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 */
+/*
+ Unquantize byte values into the scaled floating point values
+*/
+{
+ long ii;
+ int nextrand, iseed;
+
+ if (!fits_rand_value)
+ if (fits_init_randoms()) return(MEMORY_ALLOCATION);
+
+ /* initialize the index to the next random number in the list */
+ iseed = (int) ((row - 1) % N_RANDOM);
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = (float) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ 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) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ }
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int unquantize_i2r4(long row, /* seed for random values */
+ 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 */
+/*
+ Unquantize short integer values into the scaled floating point values
+*/
+{
+ long ii;
+ int nextrand, iseed;
+
+ if (!fits_rand_value)
+ if (fits_init_randoms()) return(MEMORY_ALLOCATION);
+
+ /* initialize the index to the next random number in the list */
+ iseed = (int) ((row - 1) % N_RANDOM);
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = (float) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ 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) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ }
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int unquantize_i4r4(long row, /* tile number = row number in table */
+ 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 */
+/*
+ Unquantize int integer values into the scaled floating point values
+*/
+{
+ long ii;
+ int nextrand, iseed;
+
+ if (fits_rand_value == 0)
+ if (fits_init_randoms()) return(MEMORY_ALLOCATION);
+
+ /* initialize the index to the next random number in the list */
+ iseed = (int) ((row - 1) % N_RANDOM);
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = (float) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ 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) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ }
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int unquantize_i1r8(long row, /* tile number = row number in table */
+ 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 */
+/*
+ Unquantize byte values into the scaled floating point values
+*/
+{
+ long ii;
+ int nextrand, iseed;
+
+ if (!fits_rand_value)
+ if (fits_init_randoms()) return(MEMORY_ALLOCATION);
+
+ /* initialize the index to the next random number in the list */
+ iseed = (int) ((row - 1) % N_RANDOM);
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = (double) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ 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) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ }
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int unquantize_i2r8(long row, /* tile number = row number in table */
+ 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 */
+/*
+ Unquantize short integer values into the scaled floating point values
+*/
+{
+ long ii;
+ int nextrand, iseed;
+
+ if (!fits_rand_value)
+ if (fits_init_randoms()) return(MEMORY_ALLOCATION);
+
+ /* initialize the index to the next random number in the list */
+ iseed = (int) ((row - 1) % N_RANDOM);
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = (double) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ 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) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ }
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int unquantize_i4r8(long row, /* tile number = row number in table */
+ 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 */
+/*
+ Unquantize int integer values into the scaled floating point values
+*/
+{
+ long ii;
+ int nextrand, iseed;
+
+ if (fits_rand_value == 0)
+ if (fits_init_randoms()) return(MEMORY_ALLOCATION);
+
+ /* initialize the index to the next random number in the list */
+ iseed = (int) ((row - 1) % N_RANDOM);
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+
+ if (nullcheck == 0) /* no null checking required */
+ {
+ for (ii = 0; ii < ntodo; ii++)
+ {
+ output[ii] = (double) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ }
+ else /* must check for null values */
+ {
+ 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) (((double) input[ii] - fits_rand_value[nextrand] + 0.5) * scale + zero);
+ }
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+
+ }
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int imcomp_float2nan(float *indata,
+ long tilelen,
+ int *outdata,
+ float nullflagval,
+ int *status)
+/*
+ convert pixels that are equal to nullflag to NaNs.
+ Note that indata and outdata point to the same location.
+*/
+{
+ int ii;
+
+ for (ii = 0; ii < tilelen; ii++) {
+
+ if (indata[ii] == nullflagval)
+ outdata[ii] = -1; /* integer -1 has the same bit pattern as a real*4 NaN */
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int imcomp_double2nan(double *indata,
+ long tilelen,
+ LONGLONG *outdata,
+ double nullflagval,
+ int *status)
+/*
+ convert pixels that are equal to nullflag to NaNs.
+ Note that indata and outdata point to the same location.
+*/
+{
+ int ii;
+
+ for (ii = 0; ii < tilelen; ii++) {
+
+ if (indata[ii] == nullflagval)
+ outdata[ii] = -1; /* integer -1 has the same bit pattern as a real*8 NaN */
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_transpose_table(fitsfile *infptr, fitsfile *outfptr, int *status)
+
+/*
+ Transpose the elements in the input table columns from row-major order into
+ column-major order, and write to the output table (which may be the same as
+ the input table). For example, a table with 10000 rows and 2 '1I' columns
+ will be transformed into a 1 row table with 2 '10000I' columns.
+
+ In addition, compress each column of data and write as a 1-row variable length
+ array column.
+*/
+{
+ LONGLONG nrows, incolwidth[999], inrepeat[999], outcolstart[1000], outbytespan[999];
+ LONGLONG headstart, datastart, dataend, startbyte, jj, kk, naxis1;
+ long repeat, width, pcount;
+ int ii, ncols, coltype, hdutype, ltrue = 1;
+ char *buffer, *cptr, keyname[9], tform[40], colcode[999], colname[999][50];
+ char comm[FLEN_COMMENT], *compressed_data;
+ size_t dlen, datasize;
+ float cratio[999];
+
+ if (*status > 0)
+ return(*status);
+
+ fits_get_hdu_type(infptr, &hdutype, status);
+ if (hdutype != BINARY_TBL) {
+ *status = NOT_BTABLE;
+ return(*status);
+ }
+
+ fits_get_num_rowsll(infptr, &nrows, status);
+ fits_get_num_cols(infptr, &ncols, status);
+ fits_read_key(infptr, TLONGLONG, "NAXIS1", &naxis1, NULL, status);
+ if (*status > 0)
+ return(*status);
+
+ if (nrows < 1 || ncols < 1) {
+ /* just copy the HDU if the table has 0 columns or rows */
+ if (infptr != outfptr) { /* copy input header to the output */
+ fits_copy_hdu (infptr, outfptr, 0, status);
+ }
+ return(*status);
+ }
+
+ /* allocate space for the transposed table */
+ buffer = calloc((size_t) naxis1, (size_t) nrows);
+ if (!buffer) {
+ ffpmsg("Could not allocate buffer for transformed table");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ if (infptr != outfptr) { /* copy input header to the output */
+ fits_copy_header(infptr, outfptr, status);
+ }
+
+ outcolstart[0] = 0;
+
+ /* do initial setup for each column */
+ for (ii = 0; ii < ncols; ii++) {
+
+ /* get the column name */
+ fits_make_keyn("TTYPE", ii+1, keyname, status);
+ fits_read_key(outfptr, TSTRING, keyname, colname[ii], comm, status);
+
+ /* get the column type, repeat count, and unit width */
+ fits_make_keyn("TFORM", ii+1, keyname, status);
+ fits_read_key(outfptr, TSTRING, keyname, tform, comm, status);
+
+ /* preserve the original TFORM value and comment string */
+ keyname[0] = 'Z';
+ fits_write_key(outfptr, TSTRING, keyname, tform, comm, status);
+ keyname[0] = 'T';
+
+ fits_binary_tform(tform, &coltype, &repeat, &width, status);
+
+ /* BIT columns are a difficult case */
+ /* round up to a multiple of 8 bits */
+/*
+ if (coltype == TBIT) {
+ repeat = (repeat + 7) / 8 * 8;
+ }
+*/
+
+ cptr = tform;
+ while(isdigit(*cptr)) cptr++;
+ colcode[ii] = *cptr; /* save the column type code */
+
+ /* all columns are now VLAs */
+ fits_modify_key_str(outfptr, keyname, "1PB", "&", status);
+
+ if (coltype == TBIT) {
+ repeat = (repeat + 7) / 8; /* convert from bits to bytes */
+ } else if (coltype == TSTRING) {
+ width = 1; /* ignore the optional 'w' in 'rAw' format */
+ } else if (coltype < 0) { /* pointer to variable length array */
+ width = 8;
+ if (colcode[ii] == 'Q') width = 16; /* this is a 'Q' not a 'P' column */
+ repeat = 1;
+ }
+
+ inrepeat[ii] = repeat;
+
+ /* width (in bytes) of each element and field in the INPUT row-major table */
+ incolwidth[ii] = repeat * width;
+
+ /* starting offset of each field in the OUTPUT column-major table */
+ outcolstart[ii + 1] = outcolstart[ii] + incolwidth[ii] * nrows;
+
+ /* length of each sequence of bytes, after sorting them in signicant order */
+ outbytespan[ii] = (incolwidth[ii] * nrows) / width;
+ }
+
+ /* the transformed table has only 1 row */
+ /* output table width 8 bytes per column */
+ fits_modify_key_lng(outfptr, "NAXIS2", 1, "&", status);
+ fits_modify_key_lng(outfptr, "NAXIS1", ncols * 8, "&", status);
+
+ /* move to the start of the input table */
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ ffmbyt(infptr, datastart, 0, status);
+
+ /* now transpose the table into an array in memory */
+ for (jj = 0; jj < nrows; jj++) { /* loop over rows */
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ kk = 0;
+
+ cptr = buffer + (outcolstart[ii] + (jj * incolwidth[ii])); /* addr to copy to */
+
+ startbyte = (infptr->Fptr)->bytepos; /* save the starting byte location */
+
+ ffgbyt(infptr, incolwidth[ii], cptr, status); /* copy all the bytes */
+
+ if (incolwidth[ii] >= MINDIRECT) { /* have to explicitly move to next byte */
+ ffmbyt(infptr, startbyte + incolwidth[ii], 0, status);
+ }
+ }
+ }
+
+ fits_set_hdustruc(outfptr, status);
+
+ /* now compress each column with GZIP and write out to output table */
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ datasize = (size_t) (outcolstart[ii + 1] - outcolstart[ii]);
+
+ /* allocate memory for the compressed data */
+ compressed_data = malloc(datasize);
+ if (!compressed_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+
+ /* gzip compress the data */
+ compress2mem_from_mem(buffer + outcolstart[ii], datasize,
+ &compressed_data, &datasize, realloc,
+ &dlen, status);
+
+ /* write the compressed data to the output column */
+ fits_set_tscale(outfptr, ii + 1, 1.0, 0.0, status); /* turn off any data scaling, first */
+ fits_write_col(outfptr, TBYTE, ii + 1, 1, 1, dlen, compressed_data, status);
+
+ cratio[ii] = (float) datasize / (float) dlen;
+ free(compressed_data); /* don't need the compressed data any more */
+
+ sprintf(results[ii]," %3d %10.10s %4d %c %5.2f", ii+1, colname[ii], (int) inrepeat[ii],colcode[ii],cratio[ii]);
+ trans_ratio[ii] = cratio[ii];
+ }
+
+ /* save the original PCOUNT value */
+ fits_read_key(infptr, TLONG, "PCOUNT", &pcount, comm, status);
+ fits_write_key(outfptr, TLONG, "ZPCOUNT", &pcount, comm, status);
+
+ fits_write_key(outfptr, TLONGLONG, "ZNAXIS1", &naxis1, "original rows width",
+ status);
+ fits_write_key(outfptr, TLONGLONG, "ZNAXIS2", &nrows, "original number of rows",
+ status);
+
+ fits_write_key(outfptr, TLOGICAL, "TVIRTUAL", &ltrue,
+ "this is a virtual table", status);
+ fits_write_key(outfptr, TSTRING, "ZMETHOD", "TRANSPOSED_SHUFFLED_GZIP",
+ "table compression method", status);
+
+ fits_set_hdustruc(outfptr, status);
+
+ /* copy the heap from input to output file */
+ fits_gzip_heap(infptr, outfptr, status);
+
+ free(buffer);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_compress_table_rice(fitsfile *infptr, fitsfile *outfptr, int *status)
+
+/*
+ Transpose the elements in the input table columns from row-major order into
+ column-major order, and write to the output table (which may be the same as
+ the input table). For example, a table with 10000 rows and 2 '1I' columns
+ will be transformed into a 1 row table with 2 '10000I' columns.
+
+ Integer columns are then compressed with Rice; all other columns compressed
+ with GZIP. In addition, the bytes in the floating point numeric data values
+ (columns with TFORM = E, and D) are shuffled so that the most significant
+ byte of every element occurs first in the array, followed by the next most
+ significant byte, and so on to the least significant byte. Thus, if you
+ have 3 4-byte numeric values, the bytes 012301230123 get shuffled to
+ 000111222333
+*/
+{
+ LONGLONG nrows, incolwidth[999], inrepeat[999], outcolstart[1000], outbytespan[999];
+ LONGLONG headstart, datastart, dataend, startbyte, jj, kk, naxis1;
+ long repeat, width, pcount;
+ int ii, ncols, coltype, hdutype, ltrue = 1;
+ char *buffer, *cptr, keyname[9], tform[40], colcode[999], tempstring[20];
+ char comm[FLEN_COMMENT], *compressed_data;
+ float cratio[999];
+
+ size_t dlen, datasize;
+
+ if (*status > 0)
+ return(*status);
+
+ fits_get_hdu_type(infptr, &hdutype, status);
+ if (hdutype != BINARY_TBL) {
+ *status = NOT_BTABLE;
+ return(*status);
+ }
+
+ fits_get_num_rowsll(infptr, &nrows, status);
+ fits_get_num_cols(infptr, &ncols, status);
+ fits_read_key(infptr, TLONGLONG, "NAXIS1", &naxis1, NULL, status);
+ if (*status > 0)
+ return(*status);
+
+ if (nrows < 1 || ncols < 1) {
+ /* just copy the HDU if the table has 0 columns or rows */
+ if (infptr != outfptr) { /* copy input header to the output */
+ fits_copy_hdu (infptr, outfptr, 0, status);
+ }
+ return(*status);
+ }
+
+ /* allocate space for the transposed table */
+ buffer = calloc((size_t) naxis1, (size_t) nrows);
+ if (!buffer) {
+ ffpmsg("Could not allocate buffer for transformed table");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ if (infptr != outfptr) { /* copy input header to the output */
+ fits_copy_header(infptr, outfptr, status);
+ }
+
+ outcolstart[0] = 0;
+ for (ii = 0; ii < ncols; ii++) {
+
+ /* get the column type, repeat count, and unit width */
+ fits_make_keyn("TFORM", ii+1, keyname, status);
+ fits_read_key(outfptr, TSTRING, keyname, tform, comm, status);
+
+ /* preserve the original TFORM value and comment string */
+ keyname[0] = 'Z';
+ fits_write_key(outfptr, TSTRING, keyname, tform, comm, status);
+ keyname[0] = 'T';
+
+ fits_binary_tform(tform, &coltype, &repeat, &width, status);
+
+ /* BIT columns are a difficult case */
+ /* round up to a multiple of 8 bits */
+/*
+ if (coltype == TBIT) {
+ repeat = (repeat + 7) / 8 * 8;
+ }
+*/
+ cptr = tform;
+ while(isdigit(*cptr)) cptr++;
+ colcode[ii] = *cptr; /* save the column type code */
+
+/* all columns are now VLAs */
+ fits_modify_key_str(outfptr, keyname, "1PB", "&", status);
+
+ if (coltype == TBIT) {
+ repeat = (repeat + 7) / 8; /* convert from bits to bytes */
+ } else if (coltype == TSTRING) {
+ width = 1; /* ignore the optional 'w' in 'rAw' format */
+ } else if (coltype < 0) { /* pointer to variable length array */
+ width = 8;
+ if (colcode[ii] == 'Q') width = 16; /* this is a 'Q' not a 'P' column */
+ repeat = 1;
+ }
+
+ inrepeat[ii] = repeat;
+
+ /* width (in bytes) of each element and field in the INPUT row-major table */
+ incolwidth[ii] = repeat * width;
+
+ /* starting offset of each field in the OUTPUT column-major table */
+ outcolstart[ii + 1] = outcolstart[ii] + incolwidth[ii] * nrows;
+
+ /* length of each sequence of bytes, after sorting them in signicant order */
+ outbytespan[ii] = (incolwidth[ii] * nrows) / width;
+ }
+
+ /* the transformed table has only 1 row */
+ /* output table width 8 bytes per column */
+
+ fits_modify_key_lng(outfptr, "NAXIS2", 1, "&", status);
+ fits_modify_key_lng(outfptr, "NAXIS1", ncols * 8, "&", status);
+
+ /* move to the start of the input table */
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ ffmbyt(infptr, datastart, 0, status);
+
+ for (jj = 0; jj < nrows; jj++) { /* loop over rows */
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ kk = 0;
+
+ switch (colcode[ii]) {
+ /* separate the byte planes for the 2-byte, 4-byte, and 8-byte numeric columns */
+
+ case 'E':
+ while(kk < incolwidth[ii]) {
+ cptr = buffer + (outcolstart[ii] + (jj * inrepeat[ii]) + kk/4);
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ kk += 4;
+ }
+ break;
+
+ case 'D':
+ case 'K':
+ while(kk < incolwidth[ii]) {
+ cptr = buffer + (outcolstart[ii] + (jj * inrepeat[ii]) + kk/8);
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ kk += 8;
+ }
+ break;
+
+ default: /* don't bother separating the bytes for other column types */
+ cptr = buffer + (outcolstart[ii] + (jj * incolwidth[ii])); /* addr to copy to */
+ startbyte = (infptr->Fptr)->bytepos; /* save the starting byte location */
+
+ ffgbyt(infptr, incolwidth[ii], cptr, status); /* copy all the bytes */
+
+ if (incolwidth[ii] >= MINDIRECT) { /* have to explicitly move to next byte */
+ ffmbyt(infptr, startbyte + incolwidth[ii], 0, status);
+ }
+ }
+ }
+ }
+
+ fits_set_hdustruc(outfptr, status);
+
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ datasize = (size_t) (outcolstart[ii + 1] - outcolstart[ii]);
+ /* allocate memory for the compressed data */
+ compressed_data = malloc(datasize*2);
+ if (!compressed_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+
+
+ switch (colcode[ii]) {
+
+
+ case 'I':
+#if BYTESWAPPED
+ ffswap2((short *) (buffer + outcolstart[ii]), datasize / 2);
+#endif
+ dlen = fits_rcomp_short ((short *)(buffer + outcolstart[ii]), datasize / 2, (unsigned char *) compressed_data,
+ datasize * 2, 32);
+
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "RICE_1",
+ "compression algorithm for column", status);
+
+ break;
+
+ case 'J':
+
+#if BYTESWAPPED
+ ffswap4((int *) (buffer + outcolstart[ii]), datasize / 4);
+#endif
+ dlen = fits_rcomp ((int *)(buffer + outcolstart[ii]), datasize / 4, (unsigned char *) compressed_data,
+ datasize * 2, 32);
+
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "RICE_1",
+ "compression algorithm for column", status);
+ break;
+
+ case 'B':
+ dlen = fits_rcomp_byte ((signed char *)(buffer + outcolstart[ii]), datasize, (unsigned char *) compressed_data,
+ datasize * 2, 32);
+
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "RICE_1",
+ "compression algorithm for column", status);
+ break;
+
+ default:
+ /* gzip compress the data */
+ compress2mem_from_mem(buffer + outcolstart[ii], datasize,
+ &compressed_data, &datasize, realloc, &dlen, status);
+
+
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "GZIP_2",
+ "compression algorithm for column", status);
+
+ } /* end of switch block */
+
+ if (dlen != 0)
+ cratio[ii] = (float) datasize / (float) dlen; /* compression ratio of the column */
+
+ /* write the compressed data to the output column */
+ fits_set_tscale(outfptr, ii + 1, 1.0, 0.0, status); /* turn off any data scaling, first */
+ fits_write_col(outfptr, TBYTE, ii + 1, 1, 1, dlen, compressed_data, status);
+
+ free(compressed_data); /* don't need the compressed data any more */
+/* printf(" %c %5.2f\n",colcode[ii],cratio[ii]); */
+
+ sprintf(tempstring," %5.2f\n",cratio[ii]);
+/*
+ if (colcode[ii] == 'I' || colcode[ii] == 'J' || colcode[ii] == 'B')
+ sprintf(tempstring," %5.2f\n",cratio[ii]);
+ else
+ sprintf(tempstring," \n");
+*/
+ strcat(results[ii],tempstring);
+ } /* end of loop over ncols */
+
+ printf(" Trans Shuf Rice\n");
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+ printf("%s", results[ii]);
+ }
+
+ /* save the original PCOUNT value */
+ fits_read_key(infptr, TLONG, "PCOUNT", &pcount, comm, status);
+ fits_write_key(outfptr, TLONG, "ZPCOUNT", &pcount, comm, status);
+
+
+ fits_write_key(outfptr, TLONGLONG, "ZNAXIS1", &naxis1, "original rows width",
+ status);
+ fits_write_key(outfptr, TLONGLONG, "ZNAXIS2", &nrows, "original number of rows",
+ status);
+
+ fits_write_key(outfptr, TLOGICAL, "ZTABLE", &ltrue,
+ "this is a compressed table", status);
+
+ free(buffer);
+
+ fits_gzip_heap(infptr, outfptr, status);
+ fits_set_hdustruc(outfptr, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_compress_table_fast(fitsfile *infptr, fitsfile *outfptr, int *status)
+
+/*
+ Compress the input FITS binary table using the 'fast' method, which consists
+ of (a) transposing the rows and columns, and (b) shuffling the bytes for
+ the I, J, K, E, and D columns so that the most significant byte of every
+ element occurs first in the array, followed by the next most significant byte,
+ and so on to the least significant byte. Thus, if you have 3 4-byte numeric
+ values, the bytes 012301230123 get shuffled to 000111222333
+
+ Finally, (c) compress each column of bytes with gzip and copy to the output table.
+
+*/
+{
+ LONGLONG nrows, incolwidth[999], inrepeat[999], outcolstart[1000], outbytespan[999];
+ LONGLONG headstart, datastart, dataend, startbyte, jj, kk, naxis1;
+ long repeat, width, pcount;
+ int ii, ncols, coltype, hdutype, ltrue = 1;
+ char *buffer, *cptr, keyname[9], tform[40], colcode[999];
+ char comm[FLEN_COMMENT], *compressed_data, tempstring[20];
+ size_t dlen, datasize;
+ float cratio[999];
+
+ if (*status > 0)
+ return(*status);
+
+ fits_get_hdu_type(infptr, &hdutype, status);
+ if (hdutype != BINARY_TBL) {
+ *status = NOT_BTABLE;
+ return(*status);
+ }
+
+ fits_get_num_rowsll(infptr, &nrows, status);
+ fits_get_num_cols(infptr, &ncols, status);
+ fits_read_key(infptr, TLONGLONG, "NAXIS1", &naxis1, NULL, status);
+ if (*status > 0)
+ return(*status);
+
+ if (nrows < 1 || ncols < 1) {
+ /* just copy the HDU if the table has 0 columns or rows */
+ if (infptr != outfptr) { /* copy input header to the output */
+ fits_copy_hdu (infptr, outfptr, 0, status);
+ }
+ return(*status);
+ }
+
+ /* allocate space for the transposed table */
+ buffer = calloc((size_t) naxis1, (size_t) nrows);
+ if (!buffer) {
+ ffpmsg("Could not allocate buffer for transformed table");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ if (infptr != outfptr) { /* copy input header to the output */
+ fits_copy_header(infptr, outfptr, status);
+ }
+
+ fits_write_key_log(outfptr, "ZTABLE", 1,
+ "extension contains compressed binary table", status);
+
+ fits_write_key(outfptr, TLONGLONG, "ZTILELEN", &nrows,
+ "number of rows in each tile", status);
+
+ fits_write_key(outfptr, TLONGLONG, "ZNAXIS1", &naxis1, "original rows width",
+ status);
+ fits_write_key(outfptr, TLONGLONG, "ZNAXIS2", &nrows, "original number of rows",
+ status);
+
+ /* save the original PCOUNT value */
+ fits_read_key(infptr, TLONG, "PCOUNT", &pcount, comm, status);
+ fits_write_key(outfptr, TLONG, "ZPCOUNT", &pcount, comm, status);
+
+ /* reset the PCOUNT keyword to zero */
+ pcount = 0;
+ fits_modify_key_lng(outfptr, "PCOUNT", pcount, NULL, status);
+
+ outcolstart[0] = 0;
+ for (ii = 0; ii < ncols; ii++) {
+
+ /* get the column type, repeat count, and unit width */
+ fits_make_keyn("TFORM", ii+1, keyname, status);
+ fits_read_key(outfptr, TSTRING, keyname, tform, comm, status);
+
+ /* preserve the original TFORM value and comment string */
+ keyname[0] = 'Z';
+ fits_write_key(outfptr, TSTRING, keyname, tform, comm, status);
+ keyname[0] = 'T';
+
+ /* all columns are now VLAs */
+ fits_modify_key_str(outfptr, keyname, "1PB", "&", status);
+
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "GZIP_2",
+ "compression algorithm for column", status);
+
+ fits_binary_tform(tform, &coltype, &repeat, &width, status);
+
+ cptr = tform;
+ while(isdigit(*cptr)) cptr++;
+ colcode[ii] = *cptr; /* save the column type code */
+
+ if (coltype == TBIT) {
+ repeat = (repeat + 7) / 8; /* convert from bits to bytes */
+ } else if (coltype == TSTRING) {
+ width = 1; /* ignore the optional 'w' in 'rAw' format */
+ } else if (coltype < 0) { /* pointer to variable length array */
+ width = 8;
+ if (colcode[ii] == 'Q') width = 16; /* this is a 'Q' not a 'P' column */
+ repeat = 1;
+ }
+
+ inrepeat[ii] = repeat;
+
+ /* width (in bytes) of each element and field in the INPUT row-major table */
+ incolwidth[ii] = repeat * width;
+
+ /* starting offset of each field in the OUTPUT column-major table */
+ outcolstart[ii + 1] = outcolstart[ii] + incolwidth[ii] * nrows;
+
+ /* length of each sequence of bytes, after sorting them in signicant order */
+ outbytespan[ii] = (incolwidth[ii] * nrows) / width;
+
+ }
+
+ /* the transformed table has only 1 row */
+ /* output table width 8 bytes per column */
+
+ fits_modify_key_lng(outfptr, "NAXIS2", 1, "&", status);
+ fits_modify_key_lng(outfptr, "NAXIS1", ncols * 8, "&", status);
+
+ /* move to the start of the input table */
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ ffmbyt(infptr, datastart, 0, status);
+
+ for (jj = 0; jj < nrows; jj++) { /* loop over rows */
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ kk = 0;
+
+ switch (colcode[ii]) {
+ /* separate the byte planes for the 2-byte, 4-byte, and 8-byte numeric columns */
+ case 'I':
+ while(kk < incolwidth[ii]) {
+
+ cptr = buffer + (outcolstart[ii] + (jj * inrepeat[ii]) + kk/2);
+ ffgbyt(infptr, 1, cptr, status); /* copy 1st byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 2nd byte */
+ kk += 2;
+ }
+
+ break;
+
+ case 'J':
+ case 'E':
+ while(kk < incolwidth[ii]) {
+ cptr = buffer + (outcolstart[ii] + (jj * inrepeat[ii]) + kk/4);
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ kk += 4;
+ }
+ break;
+
+ case 'D':
+ case 'K':
+ while(kk < incolwidth[ii]) {
+ cptr = buffer + (outcolstart[ii] + (jj * inrepeat[ii]) + kk/8);
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ cptr += outbytespan[ii];
+ ffgbyt(infptr, 1, cptr, status); /* copy 1 byte */
+ kk += 8;
+ }
+ break;
+
+ default: /* don't bother separating the bytes for other column types */
+ cptr = buffer + (outcolstart[ii] + (jj * incolwidth[ii])); /* addr to copy to */
+
+ startbyte = (infptr->Fptr)->bytepos; /* save the starting byte location */
+
+ ffgbyt(infptr, incolwidth[ii], cptr, status); /* copy all the bytes */
+
+ if (incolwidth[ii] >= MINDIRECT) { /* have to explicitly move to next byte */
+ ffmbyt(infptr, startbyte + incolwidth[ii], 0, status);
+ }
+ }
+ }
+ }
+
+ fits_set_hdustruc(outfptr, status);
+
+ /* now compress each column */
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ /* write the compression type code for this column */
+ switch (colcode[ii]) {
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'E':
+ case 'D':
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "GZIP_2",
+ "compression algorithm for column", status);
+ break;
+ default:
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "GZIP_1",
+ "compression algorithm for column", status);
+ }
+
+ datasize = (size_t) (outcolstart[ii + 1] - outcolstart[ii]);
+
+ /* allocate memory for the compressed data */
+ compressed_data = malloc(datasize);
+ if (!compressed_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+
+ /* gzip compress the data */
+ compress2mem_from_mem(buffer + outcolstart[ii], datasize,
+ &compressed_data, &datasize, realloc,
+ &dlen, status);
+
+ /* write the compressed data to the output column */
+ fits_set_tscale(outfptr, ii + 1, 1.0, 0.0, status); /* turn off any data scaling, first */
+ fits_write_col(outfptr, TBYTE, ii + 1, 1, 1, dlen, compressed_data, status);
+
+ cratio[ii] = (float) datasize / (float) dlen;
+ free(compressed_data); /* don't need the compressed data any more */
+
+ sprintf(tempstring," %5.2f",cratio[ii]);
+
+ strcat(results[ii],tempstring);
+ }
+
+ free(buffer);
+
+ /* shuffle and compress the input heap and append to the output file */
+
+ fits_gzip_heap(infptr, outfptr, status);
+ fits_set_hdustruc(outfptr, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_compress_table_best(fitsfile *infptr, fitsfile *outfptr, int *status)
+
+/*
+ Compress the input FITS binary table using the 'best' compression method, i.e,
+ whichever method produces the highest compression for each column.
+
+ First, transpose the rows and columns in the table, then, depending on the
+ data type of the column, try the different compression methods to see
+ which one produces the highest amount of compression.
+
+*/
+{
+ LONGLONG nrows, incolwidth[999], inrepeat[999], outcolstart[1000], outbytespan[999];
+ LONGLONG headstart, datastart, dataend, startbyte, jj, naxis1;
+ long repeat, width, pcount;
+ int ii, ncols, coltype, hdutype, ltrue = 1;
+ char *buffer, *cptr, keyname[9], tform[40], colcode[999];
+ char comm[FLEN_COMMENT];
+ char *gzip1_data = 0, *gzip2_data = 0, *rice_data = 0;
+ size_t gzip1_len, gzip2_len, rice_len, datasize, buffsize;
+
+ if (*status > 0)
+ return(*status);
+
+ fits_get_hdu_type(infptr, &hdutype, status);
+ if (hdutype != BINARY_TBL) {
+ *status = NOT_BTABLE;
+ return(*status);
+ }
+
+ fits_get_num_rowsll(infptr, &nrows, status);
+ fits_get_num_cols(infptr, &ncols, status);
+ fits_read_key(infptr, TLONGLONG, "NAXIS1", &naxis1, NULL, status);
+ if (*status > 0)
+ return(*status);
+
+ if (nrows < 1 || ncols < 1) {
+ /* just copy the HDU if the table has 0 columns or rows */
+ if (infptr != outfptr) { /* copy input header to the output */
+ fits_copy_hdu (infptr, outfptr, 0, status);
+ }
+ return(*status);
+ }
+
+ /* allocate space for the transposed table */
+ buffer = calloc((size_t) naxis1, (size_t) nrows);
+ if (!buffer) {
+ ffpmsg("Could not allocate buffer for transformed table");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ if (infptr != outfptr) { /* copy input header to the output */
+ fits_copy_header(infptr, outfptr, status);
+ }
+
+ fits_write_key_log(outfptr, "ZTABLE", 1,
+ "extension contains compressed binary table", status);
+
+ fits_write_key(outfptr, TLONGLONG, "ZTILELEN", &nrows,
+ "number of rows in each tile", status);
+
+ fits_write_key(outfptr, TLONGLONG, "ZNAXIS1", &naxis1, "original rows width",
+ status);
+ fits_write_key(outfptr, TLONGLONG, "ZNAXIS2", &nrows, "original number of rows",
+ status);
+
+ /* save the original PCOUNT value */
+ fits_read_key(infptr, TLONG, "PCOUNT", &pcount, comm, status);
+ fits_write_key(outfptr, TLONG, "ZPCOUNT", &pcount, comm, status);
+ /* reset the PCOUNT keyword to zero */
+ pcount = 0;
+ fits_modify_key_lng(outfptr, "PCOUNT", pcount, NULL, status);
+
+ /* Modify the TFORMn keywords; all columns become variable-length arrays. */
+ /* Save the original TFORMn values in the corresponding ZFORMn keyword. */
+ outcolstart[0] = 0;
+ for (ii = 0; ii < ncols; ii++) {
+
+ /* get the column type, repeat count, and unit width */
+ fits_make_keyn("TFORM", ii+1, keyname, status);
+ fits_read_key(outfptr, TSTRING, keyname, tform, comm, status);
+
+ /* preserve the original TFORM value and comment string */
+ keyname[0] = 'Z';
+ fits_write_key(outfptr, TSTRING, keyname, tform, comm, status);
+ keyname[0] = 'T';
+
+ /* all columns are now VLAs */
+ fits_modify_key_str(outfptr, keyname, "1PB", "&", status);
+
+ fits_binary_tform(tform, &coltype, &repeat, &width, status);
+
+ cptr = tform;
+ while(isdigit(*cptr)) cptr++;
+ colcode[ii] = *cptr; /* save the column type code */
+
+ /* deal with special cases */
+ if (coltype == TBIT) {
+ repeat = (repeat + 7) / 8; /* convert from bits to bytes */
+ } else if (coltype == TSTRING) {
+ width = 1; /* ignore the optional 'w' in 'rAw' format */
+ } else if (coltype < 0) { /* pointer to variable length array */
+ repeat = 1;
+
+ if (colcode[ii] == 'Q')
+ width = 16; /* this is a 'Q' column */
+ else
+ width = 8; /* this is a 'P' column */
+ }
+
+ inrepeat[ii] = repeat;
+
+ /* width (in bytes) of each element and field in the INPUT row-major table */
+ incolwidth[ii] = repeat * width;
+
+ /* starting offset of each field in the OUTPUT column-major table */
+ outcolstart[ii + 1] = outcolstart[ii] + incolwidth[ii] * nrows;
+
+ /* length of each sequence of bytes, after sorting them in signicant order */
+ outbytespan[ii] = (incolwidth[ii] * nrows) / width;
+ }
+
+ /* the transformed table has only 1 row */
+ /* output table width 8 bytes per column */
+
+ fits_modify_key_lng(outfptr, "NAXIS2", 1, "&", status);
+ fits_modify_key_lng(outfptr, "NAXIS1", ncols * 8, "&", status);
+
+ /* move to the start of the input table */
+ fits_get_hduaddrll(infptr, &headstart, &datastart, &dataend, status);
+ ffmbyt(infptr, datastart, 0, status);
+
+ /* now transpose the rows and columns in the table into an array in memory */
+ for (jj = 0; jj < nrows; jj++) { /* loop over rows */
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ cptr = buffer + (outcolstart[ii] + (jj * incolwidth[ii])); /* output address */
+ startbyte = (infptr->Fptr)->bytepos; /* save the starting byte location */
+ ffgbyt(infptr, incolwidth[ii], cptr, status); /* copy the column element */
+
+ if (incolwidth[ii] >= MINDIRECT) { /* have to explicitly move to next byte */
+ ffmbyt(infptr, startbyte + incolwidth[ii], 0, status);
+ }
+ }
+ }
+
+ fits_set_hdustruc(outfptr, status); /* reinitialize internal pointers */
+
+ /* Now compress each column. Depending on the column data type, try */
+ /* all the various available compression algorithms, then choose the one */
+ /* that gives the most compression. */
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ datasize = (size_t) (outcolstart[ii + 1] - outcolstart[ii]);
+
+ /* allocate memory for the gzip compressed data */
+ gzip1_data = malloc(datasize);
+ if (!gzip1_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+ buffsize = datasize;
+
+ /* First, simply compress the bytes with gzip (GZIP_1 algorithm code). */
+ /* This algorithm can be applied to every type of column. */
+ compress2mem_from_mem(buffer + outcolstart[ii], datasize,
+ &gzip1_data, &buffsize, realloc, &gzip1_len, status);
+
+ /* depending on the data type, try other compression methods */
+ switch (colcode[ii]) {
+
+ case 'I': /* 2-byte Integer columns */
+
+ /************* first, try rice compression *****************/
+ rice_data = malloc(datasize * 2); /* memory for the compressed bytes */
+ if (!rice_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+
+#if BYTESWAPPED
+ /* have to swap the bytes on little endian machines */
+ ffswap2((short *) (buffer + outcolstart[ii]), datasize / 2);
+#endif
+ rice_len = fits_rcomp_short ((short *)(buffer + outcolstart[ii]), datasize / 2,
+ (unsigned char *) rice_data, datasize * 2, 32);
+
+#if BYTESWAPPED
+ /* un-swap the bytes, to restore the original order */
+ ffswap2((short *) (buffer + outcolstart[ii]), datasize / 2);
+#endif
+
+ /************* Second, try shuffled gzip compression *****************/
+ fits_shuffle_2bytes(buffer + outcolstart[ii], datasize / 2, status);
+
+ /* allocate memory for the shuffled gzip compressed data */
+ gzip2_data = malloc(datasize);
+ if (!gzip2_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+ buffsize = datasize;
+
+ compress2mem_from_mem(buffer + outcolstart[ii], datasize,
+ &gzip2_data, &buffsize, realloc, &gzip2_len, status);
+ break;
+
+ case 'J': /* 4-byte Integer columns */
+
+ /************* first, try rice compression *****************/
+ rice_data = malloc(datasize * 2); /* memory for the compressed bytes */
+ if (!rice_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+#if BYTESWAPPED
+ /* have to swap the bytes on little endian machines */
+ ffswap4((int *) (buffer + outcolstart[ii]), datasize / 4);
+#endif
+ rice_len = fits_rcomp ((int *)(buffer + outcolstart[ii]), datasize / 4,
+ (unsigned char *) rice_data, datasize * 2, 32);
+
+#if BYTESWAPPED
+ /* un-swap the bytes, to restore the original order */
+ ffswap4((int *) (buffer + outcolstart[ii]), datasize / 4);
+#endif
+
+ /************* Second, try shuffled gzip compression *****************/
+ fits_shuffle_4bytes(buffer + outcolstart[ii], datasize / 4, status);
+
+ /* allocate memory for the shuffled gzip compressed data */
+ gzip2_data = malloc(datasize);
+ if (!gzip2_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+ buffsize = datasize;
+
+ compress2mem_from_mem(buffer + outcolstart[ii], datasize,
+ &gzip2_data, &buffsize, realloc, &gzip2_len, status);
+ break;
+
+ case 'E': /* 4-byte floating-point */
+
+ /************* try shuffled gzip compression *****************/
+ fits_shuffle_4bytes(buffer + outcolstart[ii], datasize / 4, status);
+
+ /* allocate memory for the gzip compressed data */
+ gzip2_data = malloc(datasize);
+ if (!gzip2_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+ buffsize = datasize;
+
+ compress2mem_from_mem(buffer + outcolstart[ii], datasize,
+ &gzip2_data, &buffsize, realloc, &gzip2_len, status);
+
+ rice_len = 100 * datasize; /* rice is not applicable to R*4 data */
+
+ break;
+
+ case 'K':
+ case 'D': /* 8-byte floating-point or integers */
+
+ /************* try shuffled gzip compression *****************/
+ fits_shuffle_8bytes(buffer + outcolstart[ii], datasize / 8, status);
+
+ /* allocate memory for the gzip compressed data */
+ gzip2_data = malloc(datasize);
+ if (!gzip2_data) {
+ ffpmsg("data memory allocation error");
+ return(-1);
+ }
+ buffsize = datasize;
+
+ compress2mem_from_mem(buffer + outcolstart[ii], datasize,
+ &gzip2_data, &buffsize, realloc, &gzip2_len, status);
+
+ rice_len = 100 * datasize; /* rice is not applicable to R*8 or I*8 data */
+
+ break;
+
+ default: /* L, X, B, A, C, M, P, Q type columns: no other compression options */
+ rice_len = 100 * datasize; /* rice is not applicable */
+ gzip2_len = 100 * datasize; /* shuffled-gzip is not applicable */
+
+ } /* end of switch block */
+
+ /* now write the compressed bytes from the best algorithm */
+ fits_set_tscale(outfptr, ii + 1, 1.0, 0.0, status); /* turn off any data scaling, first */
+ if (gzip1_len <= gzip2_len && gzip1_len <= rice_len) {
+
+ fits_write_col(outfptr, TBYTE, ii + 1, 1, 1, gzip1_len, gzip1_data, status);
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "GZIP_1",
+ "compression algorithm for column", status);
+ } else if (gzip2_len <= gzip1_len && gzip2_len <= rice_len) {
+ fits_write_col(outfptr, TBYTE, ii + 1, 1, 1, gzip2_len, gzip2_data, status);
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "GZIP_2",
+ "compression algorithm for column", status);
+ } else {
+ fits_write_col(outfptr, TBYTE, ii + 1, 1, 1, rice_len, rice_data, status);
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ fits_write_key(outfptr, TSTRING, keyname, "RICE_1",
+ "compression algorithm for column", status);
+ }
+
+ /* free the temporary memory */
+ if (gzip1_data) free(gzip1_data);
+ if (gzip2_data) free(gzip2_data);
+ gzip1_data = 0;
+ gzip2_data = 0;
+ }
+
+ free(buffer);
+
+ /* shuffle and compress the input heap and append to the output file */
+
+ fits_gzip_heap(infptr, outfptr, status);
+ fits_set_hdustruc(outfptr, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_uncompress_table(fitsfile *infptr, fitsfile *outfptr, int *status)
+
+/*
+ Uncompress the table that was compressed with fits_compress_table_fast or
+ fits_compress_table_best.
+*/
+{
+ LONGLONG nrows, rmajor_colwidth[999], rmajor_colstart[1000], cmajor_colstart[1000];
+ LONGLONG cmajor_repeat[999], rmajor_repeat[999], cmajor_bytespan[999], kk;
+ LONGLONG headstart, datastart, dataend;
+ long repeat, width, vla_repeat;
+ int ncols, coltype, hdutype, anynull, tstatus, zctype[999];
+ char *buffer, *transbuffer, *cptr, keyname[9], tform[40], colcode[999];
+ long pcount, zheapptr, naxis1, naxis2, ii, jj;
+ char *ptr, comm[FLEN_COMMENT], zvalue[FLEN_VALUE];
+ size_t dlen, fullsize;
+
+ /**** do initial sanity checks *****/
+ if (*status > 0)
+ return(*status);
+
+ fits_get_hdu_type(infptr, &hdutype, status);
+ if (hdutype != BINARY_TBL) {
+ *status = NOT_BTABLE;
+ return(*status);
+ }
+
+ fits_get_num_rowsll(infptr, &nrows, status);
+ fits_get_num_cols(infptr, &ncols, status);
+
+ if (nrows != 1 || (ncols < 1)) {
+ /* just copy the HDU if the table does not have 1 row and
+ more than 0 columns */
+ if (infptr != outfptr) {
+ fits_copy_hdu (infptr, outfptr, 0, status);
+ }
+ return(*status);
+ }
+
+ /**** get size of the uncompressed table */
+ fits_read_key(infptr, TLONG, "ZNAXIS1", &naxis1, comm, status);
+ if (*status > 0) {
+ ffpmsg("Could not find the required ZNAXIS1 keyword");
+ *status = 1;
+ return(*status);
+ }
+
+ fits_read_key(infptr, TLONG, "ZNAXIS2", &naxis2, comm, status);
+ if (*status > 0) {
+ ffpmsg("Could not find the required ZNAXIS2 keyword");
+ *status = 1;
+ return(*status);
+ }
+
+ fits_read_key(infptr, TLONG, "ZPCOUNT", &pcount, comm, status);
+ if (*status > 0) {
+ ffpmsg("Could not find the required ZPCOUNT keyword");
+ *status = 1;
+ return(*status);
+ }
+
+ tstatus = 0;
+ fits_read_key(infptr, TLONG, "ZHEAPPTR", &zheapptr, comm, &tstatus);
+ if (tstatus > 0) {
+ zheapptr = 0; /* uncompressed table has no heap */
+ }
+
+ /**** recreate the uncompressed table header keywords ****/
+ fits_copy_header(infptr, outfptr, status);
+
+ /* reset the NAXISn keywords to what they were in the original uncompressed table */
+ fits_modify_key_lng(outfptr, "NAXIS1", naxis1, "&", status);
+ fits_modify_key_lng(outfptr, "NAXIS2", naxis2, "&", status);
+ fits_modify_key_lng(outfptr, "PCOUNT", pcount, "&", status);
+
+ fits_delete_key(outfptr, "ZTABLE", status);
+ fits_delete_key(outfptr, "ZNAXIS1", status);
+ fits_delete_key(outfptr, "ZNAXIS2", status);
+ fits_delete_key(outfptr, "ZPCOUNT", status);
+ fits_delete_key(outfptr, "ZTILELEN", status);
+ tstatus = 0;
+ fits_delete_key(outfptr, "ZHEAPPTR", &tstatus);
+
+ /**** get the compression method that was used for each column ****/
+ for (ii = 0; ii < ncols; ii++) {
+
+ /* construct the ZCTYPn keyword name then read the keyword */
+ fits_make_keyn("ZCTYP", ii+1, keyname, status);
+ tstatus = 0;
+ fits_read_key(infptr, TSTRING, keyname, zvalue, NULL, &tstatus);
+ if (tstatus) {
+ zctype[ii] = GZIP_2;
+ } else {
+ if (!strcmp(zvalue, "GZIP_2")) {
+ zctype[ii] = GZIP_2;
+ } else if (!strcmp(zvalue, "GZIP_1")) {
+ zctype[ii] = GZIP_1;
+ } else if (!strcmp(zvalue, "RICE_1")) {
+ zctype[ii] = RICE_1;
+ } else {
+ ffpmsg("Unrecognized ZCTYPn keyword compression code:");
+ ffpmsg(zvalue);
+ *status = DATA_DECOMPRESSION_ERR;
+ return(*status);
+ }
+
+ /* delete this keyword from the uncompressed header */
+ fits_delete_key(outfptr, keyname, status);
+ }
+ }
+
+ /**** allocate space for the full transposed and untransposed table ****/
+ fullsize = naxis1 * naxis2;
+ transbuffer = malloc(fullsize);
+ if (!transbuffer) {
+ ffpmsg("Could not allocate buffer for shuffled table");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ buffer = malloc(fullsize);
+ if (!buffer) {
+ ffpmsg("Could not allocate buffer for unshuffled table");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /*** loop over each column: read and uncompress the bytes ****/
+ rmajor_colstart[0] = 0;
+ cmajor_colstart[0] = 0;
+ for (ii = 0; ii < ncols; ii++) {
+
+ /* get the original column type, repeat count, and unit width */
+ fits_make_keyn("ZFORM", ii+1, keyname, status);
+ fits_read_key(infptr, TSTRING, keyname, tform, comm, status);
+
+ /* restore the original TFORM value and comment */
+ keyname[0] = 'T';
+ fits_modify_key_str(outfptr, keyname, tform, comm, status);
+
+ /* now delete the ZFORM keyword */
+ keyname[0] = 'Z';
+ fits_delete_key(outfptr, keyname, status);
+
+ cptr = tform;
+ while(isdigit(*cptr)) cptr++;
+ colcode[ii] = *cptr; /* save the column type code */
+
+ fits_binary_tform(tform, &coltype, &repeat, &width, status);
+
+ /* deal with special cases */
+ if (coltype == TBIT) {
+ repeat = (repeat + 7) / 8 ; /* convert from bits to bytes */
+ } else if (coltype == TSTRING) {
+ width = 1;
+ } else if (coltype < 0) { /* pointer to variable length array */
+ if (colcode[ii] == 'P')
+ width = 8; /* this is a 'P' column */
+ else
+ width = 16; /* this is a 'Q' not a 'P' column */
+ }
+
+ rmajor_repeat[ii] = repeat;
+ cmajor_repeat[ii] = repeat * naxis2;
+
+ /* width (in bytes) of each field in the row-major table */
+ rmajor_colwidth[ii] = rmajor_repeat[ii] * width;
+
+ /* starting offset of each field in the column-major table */
+ cmajor_colstart[ii + 1] = cmajor_colstart[ii] + rmajor_colwidth[ii] * naxis2;
+
+ /* length of each sequence of bytes, after sorting them in signicant order */
+ cmajor_bytespan[ii] = (rmajor_colwidth[ii] * naxis2) / width;
+
+ /* starting offset of each field in the row-major table */
+ rmajor_colstart[ii + 1] = rmajor_colstart[ii] + rmajor_colwidth[ii];
+
+ /* read compressed bytes from input table */
+ fits_read_descript(infptr, ii + 1, 1, &vla_repeat, NULL, status);
+
+ /* allocate memory and read in the compressed bytes */
+ ptr = malloc(vla_repeat);
+ if (!ptr) {
+ ffpmsg("Could not allocate buffer for compressed bytes");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ fits_set_tscale(infptr, ii + 1, 1.0, 0.0, status); /* turn off any data scaling, first */
+ fits_read_col_byt(infptr, ii + 1, 1, 1, vla_repeat, 0, (unsigned char *) ptr, &anynull, status);
+
+ cptr = transbuffer + cmajor_colstart[ii];
+
+ fullsize = (size_t) (cmajor_colstart[ii+1] - cmajor_colstart[ii]);
+
+ switch (colcode[ii]) {
+ /* separate the byte planes for the 2-byte, 4-byte, and 8-byte numeric columns */
+
+
+ case 'I':
+
+ if (zctype[ii] == RICE_1) {
+ dlen = fits_rdecomp_short((unsigned char *)ptr, vla_repeat, (unsigned short *)cptr,
+ fullsize / 2, 32);
+#if BYTESWAPPED
+ ffswap2((short *) cptr, fullsize / 2);
+#endif
+ } else { /* gunzip the data into the correct location */
+ uncompress2mem_from_mem(ptr, vla_repeat, &cptr, &fullsize, realloc, &dlen, status);
+ }
+ break;
+
+ case 'J':
+
+ if (zctype[ii] == RICE_1) {
+ dlen = fits_rdecomp ((unsigned char *) ptr, vla_repeat, (unsigned int *)cptr,
+ fullsize / 4, 32);
+#if BYTESWAPPED
+ ffswap4((int *) cptr, fullsize / 4);
+#endif
+ } else { /* gunzip the data into the correct location */
+ uncompress2mem_from_mem(ptr, vla_repeat, &cptr, &fullsize, realloc, &dlen, status);
+ }
+ break;
+
+ case 'B':
+
+ if (zctype[ii] == RICE_1) {
+ dlen = fits_rdecomp_byte ((unsigned char *) ptr, vla_repeat, (unsigned char *)cptr,
+ fullsize, 32);
+ } else { /* gunzip the data into the correct location */
+ uncompress2mem_from_mem(ptr, vla_repeat, &cptr, &fullsize, realloc, &dlen, status);
+ }
+ break;
+
+ default:
+ /* gunzip the data into the correct location in the full table buffer */
+ uncompress2mem_from_mem(ptr, vla_repeat,
+ &cptr, &fullsize, realloc, &dlen, status);
+
+ } /* end of switch block */
+
+ free(ptr);
+ }
+
+ /* now transpose the rows and columns (from transbuffer to buffer) */
+ ptr = transbuffer;
+ for (ii = 0; ii < ncols; ii++) { /* loop over columns */
+
+ if ((zctype[ii] == GZIP_2)) { /* need to unshuffle the bytes */
+
+ switch (colcode[ii]) {
+
+ /* recombine the byte planes for the 2-byte, 4-byte, and 8-byte numeric columns */
+
+ case 'I':
+ /* get the 1st byte of each I*2 value */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]));
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 2;
+ }
+ }
+
+ /* get the 2nd byte of each I*2 value */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 1);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 2;
+ }
+ }
+
+ break;
+
+ case 'J':
+ case 'E':
+
+ /* get the 1st byte of each 4-byte value */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]));
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 4;
+ }
+ }
+
+ /* get the 2nd byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 1);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 4;
+ }
+ }
+
+ /* get the 3rd byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 2);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 4;
+ }
+ }
+
+ /* get the 4th byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 3);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 4;
+ }
+ }
+
+ break;
+
+ case 'D':
+ case 'K':
+
+ /* get the 1st byte of each 8-byte value */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]));
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 8;
+ }
+ }
+
+ /* get the 2nd byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 1);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 8;
+ }
+ }
+
+ /* get the 3rd byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 2);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 8;
+ }
+ }
+
+ /* get the 4th byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 3);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 8;
+ }
+ }
+
+ /* get the 5th byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 4);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 8;
+ }
+ }
+
+ /* get the 6th byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 5);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 8;
+ }
+ }
+
+ /* get the 7th byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 6);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 8;
+ }
+ }
+
+ /* get the 8th byte */
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + (jj * rmajor_colstart[ncols]) + 7);
+ for (kk = 0; kk < rmajor_repeat[ii]; kk++) {
+ *cptr = *ptr; /* copy 1 byte */
+ ptr++;
+ cptr += 8;
+ }
+ }
+
+ break;
+ default: /* should never get here */
+ ffpmsg("Error: unexpected use of GZIP_2 to compress a column");
+ *status = DATA_DECOMPRESSION_ERR;
+ return(*status);
+
+ } /* end of switch */
+
+ } else { /* not GZIP_2, so just transpose the bytes */
+
+ for (jj = 0; jj < naxis2; jj++) { /* loop over number of rows in the output table */
+ cptr = buffer + (rmajor_colstart[ii] + jj * rmajor_colstart[ncols]); /* addr to copy to */
+ memcpy(cptr, ptr, (size_t) rmajor_colwidth[ii]);
+
+ ptr += (rmajor_colwidth[ii]);
+ }
+ }
+
+ } /* end of ncols loop */
+
+ /* copy the buffer of data to the output data unit */
+ fits_get_hduaddrll(outfptr, &headstart, &datastart, &dataend, status);
+ ffmbyt(outfptr, datastart, 1, status);
+ ffpbyt(outfptr, naxis1 * naxis2, buffer, status);
+ free(buffer);
+ free(transbuffer);
+
+ /* reset internal table structure parameters */
+ fits_set_hdustruc(outfptr, status);
+
+ /* unshuffle the heap, if it exists */
+ fits_gunzip_heap(infptr, outfptr, status);
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+int fits_gzip_datablocks(fitsfile *fptr, size_t *size, int *status)
+/*
+ GZIP compress all the data blocks in the binary table HDU.
+ Store the size of the compressed byte stream in the PCOUNT keyword.
+ Save the original PCOUNT value in the ZPCOUNT keyword.
+*/
+{
+ long headstart, datastart, dataend;
+ char *ptr, *cptr, *iptr;
+ size_t dlen, datasize, ii;
+
+ /* allocate memory for the data and the compressed data */
+ fits_get_hduaddr(fptr, &headstart, &datastart, &dataend, status);
+ datasize = dataend - datastart;
+ ptr = malloc(datasize);
+ cptr = malloc(datasize);
+ if (!ptr || !cptr) {
+ ffpmsg("data memory allocation error in fits_gzip_datablocks\n");
+ return(-1);
+ }
+
+ /* copy the data into memory */
+ ffmbyt(fptr,datastart, REPORT_EOF, status);
+ iptr = ptr;
+ for (ii = 0; ii < datasize; ii+= 2880) {
+ ffgbyt(fptr, 2880, iptr, status);
+ iptr += 2880;
+ }
+
+ /* gzip compress the data */
+ compress2mem_from_mem(ptr, datasize,
+ &cptr, &datasize, realloc,
+ &dlen, status);
+
+ *size = dlen;
+
+ free(cptr); /* don't need the compressed data any more */
+ free(ptr); /* don't need the original data any more */
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int fits_gzip_heap(fitsfile *infptr, fitsfile *outfptr, int *status)
+
+/*
+ Compress the binary table heap in the input file and write it to the output file.
+ First, shuffle the bytes for the numeric arrays in the heap, so that
+ the bytes are sorted in order of decreasing significance. Then gzip
+ the entire heap as a single block of data. Then append this compressed heap
+ to the end of any existing data in the output file heap.
+*/
+{
+ LONGLONG datastart, dataend, nrows, naxis1, heapsize, length, offset, pcount, jj;
+ int coltype, ncols, ii;
+ char *heap, *compheap, card[FLEN_CARD];
+ size_t theapsize, compsize;
+
+ if (*status > 0)
+ return(*status);
+
+ /* insert a set of COMMENT keyword to indicate that this is a compressed table */
+ fits_read_card(outfptr, "TFIELDS", card, status);
+ fits_insert_card(outfptr, "COMMENT [FPACK] This is a compressed binary table generated by fpack.", status);
+ fits_insert_card(outfptr, "COMMENT [FPACK] It can be uncompressed using funpack.", status);
+ fits_insert_card(outfptr, "COMMENT [FPACK] fpack and funpack are available from the HEASARC Web site.", status);
+
+ /* get the size of the heap (value of PCOUNT keyword) */
+ fits_read_key(infptr, TLONGLONG, "PCOUNT", &heapsize, NULL, status);
+
+ /* return if there is no heap */
+ if (*status != 0 || heapsize == 0)
+ return(*status);
+
+ /* allocate memory for the heap and compressed heap */
+
+ heap = malloc((size_t) heapsize);
+ if (!heap) {
+ ffpmsg("Could not allocate buffer for the heap (fits_gzip_heap");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ compheap = malloc((size_t) heapsize);
+ if (!compheap) {
+ ffpmsg("Could not allocate buffer for compressed heap (fits_gzip_heap");
+ free(heap);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ fits_get_hduaddrll(infptr, NULL, &datastart, NULL, status);
+ fits_get_num_rowsll(infptr, &nrows, status);
+ fits_get_num_cols(infptr, &ncols, status);
+ fits_read_key(infptr, TLONGLONG, "NAXIS1", &naxis1, NULL, status);
+
+ /* move to start of the heap and copy the heap into memory */
+ ffmbyt(infptr, datastart + (nrows * naxis1), REPORT_EOF, status);
+ ffgbyt(infptr, heapsize, heap, status);
+
+ /* shuffle the bytes for the numeric columns */
+ for (ii = 1; ii <= ncols; ii++) {
+
+ fits_get_coltype(infptr, ii, &coltype, NULL, NULL, status);
+
+ if (coltype >= 0) continue; /* only interested in variable length columns */
+
+ coltype = coltype * (-1);
+
+ switch (coltype) {
+ /* shuffle the bytes for the 2-byte, 4-byte, and 8-byte numeric columns */
+ case TSHORT:
+
+ for (jj = 1; jj <= nrows; jj++) {
+ fits_read_descriptll(infptr, ii, jj, &length, &offset, status);
+ fits_shuffle_2bytes(heap + offset, length, status);
+ }
+ break;
+
+ case TLONG:
+ case TFLOAT:
+ for (jj = 1; jj <= nrows; jj++) {
+ fits_read_descriptll(infptr, ii, jj, &length, &offset, status);
+ fits_shuffle_4bytes(heap + offset, length, status);
+ }
+ break;
+
+ case TDOUBLE:
+ case TLONGLONG:
+ for (jj = 1; jj <= nrows; jj++) {
+ fits_read_descriptll(infptr, ii, jj, &length, &offset, status);
+ fits_shuffle_8bytes(heap + offset, length, status);
+ }
+ break;
+
+ default: /* don't have to do anything for other column types */
+ break;
+
+ } /* end of switch block */
+ }
+
+ /* gzip compress the shuffled heap */
+ theapsize = (size_t) heapsize;
+ compress2mem_from_mem(heap, (size_t) heapsize, &compheap, &theapsize,
+ realloc, &compsize, status);
+ free(heap); /* don't need the uncompresse heap any more */
+
+ /* update the internal pointers */
+ fits_set_hdustruc(outfptr, status);
+
+ /* save offset to the start of the compressed heap, relative to the
+ start of the main data table in the ZHEAPPTR keyword, and
+ update PCOUNT to the new extended heap size */
+
+ fits_read_key(outfptr, TLONGLONG, "PCOUNT", &pcount, NULL, status);
+ fits_get_num_rowsll(outfptr, &nrows, status);
+ fits_read_key(outfptr, TLONGLONG, "NAXIS1", &naxis1, NULL, status);
+
+ fits_write_key_lng(outfptr, "ZHEAPPTR", (LONGLONG) ((nrows * naxis1) + pcount),
+ "byte offset to compressed heap", status);
+ fits_modify_key_lng(outfptr, "PCOUNT", pcount + compsize, NULL, status);
+
+ /* now append the compressed heap to the heap in the output file */
+ dataend = (outfptr->Fptr)->datastart + (outfptr->Fptr)->heapstart +
+ (outfptr->Fptr)->heapsize;
+
+ ffmbyt(outfptr, dataend, IGNORE_EOF, status);
+ ffpbyt(outfptr, compsize, compheap, status);
+ free(compheap);
+
+ /* also update the internal pointer to the heap size */
+ (outfptr->Fptr)->heapsize = (outfptr->Fptr)->heapsize + compsize;
+
+ /* update the internal pointers again */
+ fits_set_hdustruc(outfptr, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int fits_shuffle_2bytes(char *heap, LONGLONG length, int *status)
+
+/* shuffle the bytes in an array of 2-byte integers in the heap */
+
+{
+ LONGLONG ii;
+ char *ptr, *cptr, *heapptr;
+
+ ptr = malloc((size_t) (length * 2));
+ heapptr = heap;
+ cptr = ptr;
+
+ for (ii = 0; ii < length; ii++) {
+ *cptr = *heapptr;
+ heapptr++;
+ *(cptr + length) = *heapptr;
+ heapptr++;
+ cptr++;
+ }
+
+ memcpy(heap, ptr, (size_t) (length * 2));
+ free(ptr);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int fits_shuffle_4bytes(char *heap, LONGLONG length, int *status)
+
+/* shuffle the bytes in an array of 4-byte integers or floats */
+
+{
+ LONGLONG ii;
+ char *ptr, *cptr, *heapptr;
+
+ ptr = malloc((size_t) (length * 4));
+ if (!ptr) {
+ ffpmsg("malloc failed\n");
+ return(*status);
+ }
+
+ heapptr = heap;
+ cptr = ptr;
+
+ for (ii = 0; ii < length; ii++) {
+ *cptr = *heapptr;
+ heapptr++;
+ *(cptr + length) = *heapptr;
+ heapptr++;
+ *(cptr + (length * 2)) = *heapptr;
+ heapptr++;
+ *(cptr + (length * 3)) = *heapptr;
+ heapptr++;
+ cptr++;
+ }
+
+ memcpy(heap, ptr, (size_t) (length * 4));
+ free(ptr);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int fits_shuffle_8bytes(char *heap, LONGLONG length, int *status)
+
+/* shuffle the bytes in an array of 8-byte integers or doubles in the heap */
+
+{
+ LONGLONG ii;
+ char *ptr, *cptr, *heapptr;
+
+ ptr = calloc(1, (size_t) (length * 8));
+ heapptr = heap;
+
+/* for some bizarre reason this loop fails to compile under OpenSolaris using
+ the proprietary SunStudioExpress C compiler; use the following equivalent
+ loop instead.
+
+ cptr = ptr;
+
+ for (ii = 0; ii < length; ii++) {
+ *cptr = *heapptr;
+ heapptr++;
+ *(cptr + length) = *heapptr;
+ heapptr++;
+ *(cptr + (length * 2)) = *heapptr;
+ heapptr++;
+ *(cptr + (length * 3)) = *heapptr;
+ heapptr++;
+ *(cptr + (length * 4)) = *heapptr;
+ heapptr++;
+ *(cptr + (length * 5)) = *heapptr;
+ heapptr++;
+ *(cptr + (length * 6)) = *heapptr;
+ heapptr++;
+ *(cptr + (length * 7)) = *heapptr;
+ heapptr++;
+ cptr++;
+ }
+*/
+ for (ii = 0; ii < length; ii++) {
+ cptr = ptr + ii;
+
+ *cptr = *heapptr;
+
+ heapptr++;
+ cptr += length;
+ *cptr = *heapptr;
+
+ heapptr++;
+ cptr += length;
+ *cptr = *heapptr;
+
+ heapptr++;
+ cptr += length;
+ *cptr = *heapptr;
+
+ heapptr++;
+ cptr += length;
+ *cptr = *heapptr;
+
+ heapptr++;
+ cptr += length;
+ *cptr = *heapptr;
+
+ heapptr++;
+ cptr += length;
+ *cptr = *heapptr;
+
+ heapptr++;
+ cptr += length;
+ *cptr = *heapptr;
+
+ heapptr++;
+ }
+
+ memcpy(heap, ptr, (size_t) (length * 8));
+ free(ptr);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int fits_gunzip_heap(fitsfile *infptr, fitsfile *outfptr, int *status)
+
+/*
+ inverse of the fits_gzip_heap function: uncompress and unshuffle the heap
+ in the input file and write it to the output file
+*/
+{
+ LONGLONG datastart, nrows, naxis1, length, offset, pcount, jj;
+ LONGLONG zpcount, zheapptr, cheapsize;
+ int coltype, ncols, ii;
+ char *heap, *compheap;
+ size_t arraysize, theapsize;
+
+ if (*status > 0)
+ return(*status);
+
+ /* first, delete any COMMENT keywords written by fits_gzip_heap */
+ while (*status == 0) {
+ fits_delete_str(outfptr, "COMMENT [FPACK]", status);
+ }
+ if (*status == KEY_NO_EXIST) *status = 0;
+
+ /* ZPCOUNT = size of original uncompressed heap */
+ fits_read_key(infptr, TLONGLONG, "ZPCOUNT", &zpcount, NULL, status);
+
+ /* just return if there is no heap */
+ if (*status != 0 || zpcount == 0)
+ return(*status);
+
+ fits_get_num_rowsll(infptr, &nrows, status);
+ fits_read_key(infptr, TLONGLONG, "NAXIS1", &naxis1, NULL, status);
+
+ /* ZHEAPPTR = offset to the start of the compressed heap */
+ fits_read_key(infptr, TLONGLONG, "ZHEAPPTR", &zheapptr, NULL, status);
+
+ /* PCOUNT = total size of the compressed 2D table plus the compressed heap */
+ fits_read_key(infptr, TLONGLONG, "PCOUNT", &pcount, NULL, status);
+
+ /* size of the compressed heap */
+ cheapsize = pcount - (zheapptr - (naxis1 * nrows));
+
+ /* allocate memory for the heap and uncompressed heap */
+ arraysize = (size_t) zpcount;
+ heap = malloc(arraysize);
+ if (!heap) {
+ ffpmsg("Could not allocate buffer for the heap (fits_gunzip_heap");
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ compheap = malloc((size_t) cheapsize);
+ if (!compheap) {
+ ffpmsg("Could not allocate buffer for compressed heap (fits_gunzip_heap");
+ free(heap);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ fits_get_hduaddrll(infptr, NULL, &datastart, NULL, status);
+
+ /* read the compressed heap into memory */
+ ffmbyt(infptr, datastart + zheapptr, REPORT_EOF, status);
+ ffgbyt(infptr, cheapsize, compheap, status);
+
+ /* uncompress the heap */
+ theapsize = (size_t) zpcount;
+ uncompress2mem_from_mem(compheap, (size_t) cheapsize, &heap, &arraysize,
+ realloc, &theapsize, status);
+
+ free(compheap); /* don't need the compressed heap any more */
+
+ if (theapsize != zpcount) {
+ /* something is wrong */
+ ffpmsg("uncompressed heap size != to ZPCOUNT");
+ free(heap);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* get dimensions of the uncompressed table */
+ fits_get_num_rowsll(outfptr, &nrows, status);
+ fits_read_key(outfptr, TLONGLONG, "NAXIS1", &naxis1, NULL, status);
+ fits_get_num_cols(outfptr, &ncols, status);
+
+ for (ii = ncols; ii > 0; ii--) {
+
+ fits_get_coltype(outfptr, ii, &coltype, NULL, NULL, status);
+
+ if (coltype >= 0) continue; /* only interested in variable length columns */
+
+ coltype = coltype * (-1);
+
+ switch (coltype) {
+ /* recombine the byte planes for the 2-byte, 4-byte, and 8-byte numeric columns */
+ case TSHORT:
+
+ for (jj = nrows; jj > 0; jj--) {
+ fits_read_descriptll(outfptr, ii, jj, &length, &offset, status);
+ fits_unshuffle_2bytes(heap + offset, length, status);
+ }
+ break;
+
+ case TLONG:
+ case TFLOAT:
+ for (jj = nrows; jj > 0; jj--) {
+ fits_read_descriptll(outfptr, ii, jj, &length, &offset, status);
+ fits_unshuffle_4bytes(heap + offset, length, status);
+ }
+ break;
+
+ case TDOUBLE:
+ case TLONGLONG:
+ for (jj = nrows; jj > 0; jj--) {
+ fits_read_descriptll(outfptr, ii, jj, &length, &offset, status);
+ fits_unshuffle_8bytes(heap + offset, length, status);
+ }
+ break;
+
+ default: /* don't need to recombine bytes for other column types */
+ break;
+
+ } /* end of switch block */
+ }
+
+ /* copy the unshuffled heap back to the output file */
+ fits_get_hduaddrll(outfptr, NULL, &datastart, NULL, status);
+
+ ffmbyt(outfptr, datastart + (nrows * naxis1), IGNORE_EOF, status);
+ ffpbyt(outfptr, zpcount, heap, status);
+
+ free(heap);
+
+ /* also update the internal pointer to the heap size */
+ (outfptr->Fptr)->heapsize = zpcount;
+
+ /* update the internal pointers again */
+ fits_set_hdustruc(outfptr, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int fits_unshuffle_2bytes(char *heap, LONGLONG length, int *status)
+
+/* unshuffle the bytes in an array of 2-byte integers */
+
+{
+ LONGLONG ii;
+ char *ptr, *cptr, *heapptr;
+
+ ptr = malloc((size_t) (length * 2));
+ heapptr = heap + (2 * length) - 1;
+ cptr = ptr + (2 * length) - 1;
+
+ for (ii = 0; ii < length; ii++) {
+ *cptr = *heapptr;
+ cptr--;
+ *cptr = *(heapptr - length);
+ cptr--;
+ heapptr--;
+ }
+
+ memcpy(heap, ptr, (size_t) (length * 2));
+ free(ptr);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int fits_unshuffle_4bytes(char *heap, LONGLONG length, int *status)
+
+/* unshuffle the bytes in an array of 4-byte integers or floats */
+
+{
+ LONGLONG ii;
+ char *ptr, *cptr, *heapptr;
+
+ ptr = malloc((size_t) (length * 4));
+ heapptr = heap + (4 * length) -1;
+ cptr = ptr + (4 * length) -1;
+
+ for (ii = 0; ii < length; ii++) {
+ *cptr = *heapptr;
+ cptr--;
+ *cptr = *(heapptr - length);
+ cptr--;
+ *cptr = *(heapptr - (2 * length));
+ cptr--;
+ *cptr = *(heapptr - (3 * length));
+ cptr--;
+ heapptr--;
+ }
+
+ memcpy(heap, ptr, (size_t) (length * 4));
+ free(ptr);
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int fits_unshuffle_8bytes(char *heap, LONGLONG length, int *status)
+
+/* unshuffle the bytes in an array of 8-byte integers or doubles */
+
+{
+ LONGLONG ii;
+ char *ptr, *cptr, *heapptr;
+
+ ptr = malloc((size_t) (length * 8));
+ heapptr = heap + (8 * length) - 1;
+ cptr = ptr + (8 * length) -1;
+
+ for (ii = 0; ii < length; ii++) {
+ *cptr = *heapptr;
+ cptr--;
+ *cptr = *(heapptr - length);
+ cptr--;
+ *cptr = *(heapptr - (2 * length));
+ cptr--;
+ *cptr = *(heapptr - (3 * length));
+ cptr--;
+ *cptr = *(heapptr - (4 * length));
+ cptr--;
+ *cptr = *(heapptr - (5 * length));
+ cptr--;
+ *cptr = *(heapptr - (6 * length));
+ cptr--;
+ *cptr = *(heapptr - (7 * length));
+ cptr--;
+ heapptr--;
+ }
+
+ memcpy(heap, ptr, (size_t) (length * 8));
+ free(ptr);
+ return(*status);
+}
diff --git a/vendor/cfitsio/imcopy.c b/vendor/cfitsio/imcopy.c
new file mode 100644
index 00000000..253205d9
--- /dev/null
+++ b/vendor/cfitsio/imcopy.c
@@ -0,0 +1,233 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "fitsio.h"
+
+int main(int argc, char *argv[])
+{
+ fitsfile *infptr, *outfptr; /* FITS file pointers defined in fitsio.h */
+ int status = 0, tstatus, ii = 1, iteration = 0, single = 0, hdupos;
+ int hdutype, bitpix, bytepix, naxis = 0, nkeys, datatype = 0, anynul;
+ long naxes[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
+ long first, totpix = 0, npix;
+ double *array, bscale = 1.0, bzero = 0.0, nulval = 0.;
+ char card[81];
+
+ if (argc != 3)
+ {
+ printf("\n");
+ printf("Usage: imcopy inputImage outputImage[compress]\n");
+ printf("\n");
+ printf("Copy an input image to an output image, optionally compressing\n");
+ printf("or uncompressing the image in the process. If the [compress]\n");
+ printf("qualifier is appended to the output file name then the input image\n");
+ printf("will be compressed using the tile-compressed format. In this format,\n");
+ printf("the image is divided into rectangular tiles and each tile of pixels\n");
+ printf("is compressed and stored in a variable-length row of a binary table.\n");
+ printf("If the [compress] qualifier is omitted, and the input image is\n");
+ printf("in tile-compressed format, then the output image will be uncompressed.\n");
+ printf("\n");
+ printf("If an extension name or number is appended to the input file name, \n");
+ printf("enclosed in square brackets, then only that single extension will be\n");
+ printf("copied to the output file. Otherwise, every extension in the input file\n");
+ printf("will be processed in turn and copied to the output file.\n");
+ printf("\n");
+ printf("Examples:\n");
+ printf("\n");
+ printf("1) imcopy image.fit 'cimage.fit[compress]'\n");
+ printf("\n");
+ printf(" This compresses the input image using the default parameters, i.e.,\n");
+ printf(" using the Rice compression algorithm and using row by row tiles.\n");
+ printf("\n");
+ printf("2) imcopy cimage.fit image2.fit\n");
+ printf("\n");
+ printf(" This uncompresses the image created in the first example.\n");
+ printf(" image2.fit should be identical to image.fit if the image\n");
+ printf(" has an integer datatype. There will be small differences\n");
+ printf(" in the pixel values if it is a floating point image.\n");
+ printf("\n");
+ printf("3) imcopy image.fit 'cimage.fit[compress GZIP 100,100;q 16]'\n");
+ printf("\n");
+ printf(" This compresses the input image using the following parameters:\n");
+ printf(" GZIP compression algorithm;\n");
+ printf(" 100 X 100 pixel compression tiles;\n");
+ printf(" quantization level = 16 (only used with floating point images)\n");
+ printf("\n");
+ printf("The full syntax of the compression qualifier is:\n");
+ printf(" [compress ALGORITHM TDIM1,TDIM2,...; q QLEVEL s SCALE]\n");
+ printf("where the allowed ALGORITHM values are:\n");
+ printf(" Rice, HCOMPRESS, HSCOMPRESS, GZIP, or PLIO. \n");
+ printf(" (HSCOMPRESS is a variant of HCOMPRESS in which a small\n");
+ printf(" amount of smoothing is applied to the uncompressed image\n");
+ printf(" to help suppress blocky compression artifacts in the image\n");
+ printf(" when using large values for the 'scale' parameter).\n");
+ printf("TDIMn is the size of the compression tile in each dimension,\n");
+ printf("\n");
+ printf("QLEVEL specifies the quantization level when converting a floating\n");
+ printf("point image into integers, prior to compressing the image. The\n");
+ printf("default value = 16, which means the image will be quantized into\n");
+ printf("integer levels that are spaced at intervals of sigma/16., where \n");
+ printf("sigma is the estimated noise level in background areas of the image.\n");
+ printf("If QLEVEL is negative, this means use the absolute value for the\n");
+ printf("quantization spacing (e.g. 'q -0.005' means quantize the floating\n");
+ printf("point image such that the scaled integers represent steps of 0.005\n");
+ printf("in the original image).\n");
+ printf("\n");
+ printf("SCALE is the integer scale factor that only applies to the HCOMPRESS\n");
+ printf("algorithm. The default value SCALE = 0 forces the image to be\n");
+ printf("losslessly compressed; Greater amounts of lossy compression (resulting\n");
+ printf("in smaller compressed files) can be specified with larger SCALE values.\n");
+ printf("\n");
+ printf("\n");
+ printf("Note that it may be necessary to enclose the file names\n");
+ printf("in single quote characters on the Unix command line.\n");
+ return(0);
+ }
+
+ /* Open the input file and create output file */
+ fits_open_file(&infptr, argv[1], READONLY, &status);
+ fits_create_file(&outfptr, argv[2], &status);
+
+ if (status != 0) {
+ fits_report_error(stderr, status);
+ return(status);
+ }
+
+ fits_get_hdu_num(infptr, &hdupos); /* Get the current HDU position */
+
+ /* Copy only a single HDU if a specific extension was given */
+ if (hdupos != 1 || strchr(argv[1], '[')) single = 1;
+
+ for (; !status; hdupos++) /* Main loop through each extension */
+ {
+
+ fits_get_hdu_type(infptr, &hdutype, &status);
+
+ if (hdutype == IMAGE_HDU) {
+
+ /* get image dimensions and total number of pixels in image */
+ for (ii = 0; ii < 9; ii++)
+ naxes[ii] = 1;
+
+ fits_get_img_param(infptr, 9, &bitpix, &naxis, naxes, &status);
+
+ totpix = naxes[0] * naxes[1] * naxes[2] * naxes[3] * naxes[4]
+ * naxes[5] * naxes[6] * naxes[7] * naxes[8];
+ }
+
+ if (hdutype != IMAGE_HDU || naxis == 0 || totpix == 0) {
+
+ /* just copy tables and null images */
+ fits_copy_hdu(infptr, outfptr, 0, &status);
+
+ } else {
+
+ /* Explicitly create new image, to support compression */
+ fits_create_img(outfptr, bitpix, naxis, naxes, &status);
+ if (status) {
+ fits_report_error(stderr, status);
+ return(status);
+ }
+
+ if (fits_is_compressed_image(outfptr, &status)) {
+ /* write default EXTNAME keyword if it doesn't already exist */
+ tstatus = 0;
+ fits_read_card(infptr, "EXTNAME", card, &tstatus);
+ if (tstatus) {
+ strcpy(card, "EXTNAME = 'COMPRESSED_IMAGE' / name of this binary table extension");
+ fits_write_record(outfptr, card, &status);
+ }
+ }
+
+ /* copy all the user keywords (not the structural keywords) */
+ fits_get_hdrspace(infptr, &nkeys, NULL, &status);
+
+ for (ii = 1; ii <= nkeys; ii++) {
+ fits_read_record(infptr, ii, card, &status);
+ if (fits_get_keyclass(card) > TYP_CMPRS_KEY)
+ fits_write_record(outfptr, card, &status);
+ }
+
+ /* delete default EXTNAME keyword if it exists */
+/*
+ if (!fits_is_compressed_image(outfptr, &status)) {
+ tstatus = 0;
+ fits_read_key(outfptr, TSTRING, "EXTNAME", card, NULL, &tstatus);
+ if (!tstatus) {
+ if (strcmp(card, "COMPRESSED_IMAGE") == 0)
+ fits_delete_key(outfptr, "EXTNAME", &status);
+ }
+ }
+*/
+
+ switch(bitpix) {
+ case BYTE_IMG:
+ datatype = TBYTE;
+ break;
+ case SHORT_IMG:
+ datatype = TSHORT;
+ break;
+ case LONG_IMG:
+ datatype = TINT;
+ break;
+ case FLOAT_IMG:
+ datatype = TFLOAT;
+ break;
+ case DOUBLE_IMG:
+ datatype = TDOUBLE;
+ break;
+ }
+
+ bytepix = abs(bitpix) / 8;
+
+ npix = totpix;
+ iteration = 0;
+
+ /* try to allocate memory for the entire image */
+ /* use double type to force memory alignment */
+ array = (double *) calloc(npix, bytepix);
+
+ /* if allocation failed, divide size by 2 and try again */
+ while (!array && iteration < 10) {
+ iteration++;
+ npix = npix / 2;
+ array = (double *) calloc(npix, bytepix);
+ }
+
+ if (!array) {
+ printf("Memory allocation error\n");
+ return(0);
+ }
+
+ /* turn off any scaling so that we copy the raw pixel values */
+ fits_set_bscale(infptr, bscale, bzero, &status);
+ fits_set_bscale(outfptr, bscale, bzero, &status);
+
+ first = 1;
+ while (totpix > 0 && !status)
+ {
+ /* read all or part of image then write it back to the output file */
+ fits_read_img(infptr, datatype, first, npix,
+ &nulval, array, &anynul, &status);
+
+ fits_write_img(outfptr, datatype, first, npix, array, &status);
+ totpix = totpix - npix;
+ first = first + npix;
+ }
+ free(array);
+ }
+
+ if (single) break; /* quit if only copying a single HDU */
+ fits_movrel_hdu(infptr, 1, NULL, &status); /* try to move to next HDU */
+ }
+
+ if (status == END_OF_FILE) status = 0; /* Reset after normal error */
+
+ fits_close_file(outfptr, &status);
+ fits_close_file(infptr, &status);
+
+ /* if error occurred, print out error message */
+ if (status)
+ fits_report_error(stderr, status);
+ return(status);
+}
diff --git a/vendor/cfitsio/infback.c b/vendor/cfitsio/infback.c
new file mode 100644
index 00000000..af3a8c96
--- /dev/null
+++ b/vendor/cfitsio/infback.c
@@ -0,0 +1,632 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->dmax = 32768U;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->wnext = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code here; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.val < 16) {
+ NEEDBITS(here.bits);
+ DROPBITS(here.bits);
+ state->lens[state->have++] = here.val;
+ }
+ else {
+ if (here.val == 16) {
+ NEEDBITS(here.bits + 2);
+ DROPBITS(here.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (here.val == 17) {
+ NEEDBITS(here.bits + 3);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(here.bits + 7);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* check for end-of-block code (better have one) */
+ if (state->lens[256] == 0) {
+ strm->msg = (char *)"invalid code -- missing end-of-block";
+ state->mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftrees.h
+ concerning the ENOUGH constants, which depend on those values */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.op && (here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(here.bits);
+ state->length = (unsigned)here.val;
+
+ /* process literal */
+ if (here.op == 0) {
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (here.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(here.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ here = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(here.bits);
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)here.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(here.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/vendor/cfitsio/inffast.c b/vendor/cfitsio/inffast.c
new file mode 100644
index 00000000..2f1d60b4
--- /dev/null
+++ b/vendor/cfitsio/inffast.c
@@ -0,0 +1,340 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2008, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code here; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ wnext = state->wnext;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ PUP(out) = (unsigned char)(here.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ if (state->sane) {
+ strm->msg =
+ (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ if (len <= op - whave) {
+ do {
+ PUP(out) = 0;
+ } while (--len);
+ continue;
+ }
+ len -= op - whave;
+ do {
+ PUP(out) = 0;
+ } while (--op > whave);
+ if (op == 0) {
+ from = out - dist;
+ do {
+ PUP(out) = PUP(from);
+ } while (--len);
+ continue;
+ }
+#endif
+ }
+ from = window - OFF;
+ if (wnext == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (wnext < op) { /* wrap around window */
+ from += wsize + wnext - op;
+ op -= wnext;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (wnext < len) { /* some from start of window */
+ op = wnext;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += wnext - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ here = dcode[here.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ here = lcode[here.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and wnext == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/vendor/cfitsio/inffast.h b/vendor/cfitsio/inffast.h
new file mode 100644
index 00000000..e5c1aa4c
--- /dev/null
+++ b/vendor/cfitsio/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/vendor/cfitsio/inffixed.h b/vendor/cfitsio/inffixed.h
new file mode 100644
index 00000000..75ed4b59
--- /dev/null
+++ b/vendor/cfitsio/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/vendor/cfitsio/inflate.c b/vendor/cfitsio/inflate.c
new file mode 100644
index 00000000..a8431abe
--- /dev/null
+++ b/vendor/cfitsio/inflate.c
@@ -0,0 +1,1480 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->wnext = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ state->sane = 1;
+ state->back = -1;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+ int wrap;
+ struct inflate_state FAR *state;
+
+ /* get the state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* extract wrap request from windowBits parameter */
+ if (windowBits < 0) {
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48)
+ windowBits &= 15;
+#endif
+ }
+
+ /* set number of window bits, free window if different */
+ if (windowBits && (windowBits < 8 || windowBits > 15))
+ return Z_STREAM_ERROR;
+ if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+ ZFREE(strm, state->window);
+ state->window = Z_NULL;
+ }
+
+ /* update state and reset the rest of it */
+ state->wrap = wrap;
+ state->wbits = (unsigned)windowBits;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ int ret;
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->window = Z_NULL;
+ ret = inflateReset2(strm, windowBits);
+ if (ret != Z_OK) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ }
+ return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits < 0) {
+ state->hold = 0;
+ state->bits = 0;
+ return Z_OK;
+ }
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->wnext = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->wnext = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->wnext;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->wnext, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->wnext = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->wnext += dist;
+ if (state->wnext == state->wsize) state->wnext = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code here; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (state->wbits == 0)
+ state->wbits = len;
+ else if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN_; /* decode codes */
+ if (flush == Z_TREES) {
+ DROPBITS(2);
+ goto inf_leave;
+ }
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY_;
+ if (flush == Z_TREES) goto inf_leave;
+ case COPY_:
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.val < 16) {
+ NEEDBITS(here.bits);
+ DROPBITS(here.bits);
+ state->lens[state->have++] = here.val;
+ }
+ else {
+ if (here.val == 16) {
+ NEEDBITS(here.bits + 2);
+ DROPBITS(here.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (here.val == 17) {
+ NEEDBITS(here.bits + 3);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(here.bits + 7);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* check for end-of-block code (better have one) */
+ if (state->lens[256] == 0) {
+ strm->msg = (char *)"invalid code -- missing end-of-block";
+ state->mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftrees.h
+ concerning the ENOUGH constants, which depend on those values */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN_;
+ if (flush == Z_TREES) goto inf_leave;
+ case LEN_:
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ if (state->mode == TYPE)
+ state->back = -1;
+ break;
+ }
+ state->back = 0;
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.op && (here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ state->length = (unsigned)here.val;
+ if ((int)(here.op) == 0) {
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ state->mode = LIT;
+ break;
+ }
+ if (here.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->back = -1;
+ state->mode = TYPE;
+ break;
+ }
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->was = state->length;
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ here = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)here.val;
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->whave) {
+ if (state->sane) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ Trace((stderr, "inflate.c too far\n"));
+ copy -= state->whave;
+ if (copy > state->length) copy = state->length;
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = 0;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+#endif
+ }
+ if (copy > state->wnext) {
+ copy -= state->wnext;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->wnext - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0) +
+ (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ state->sane = !subvert;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ return Z_OK;
+#else
+ state->sane = 1;
+ return Z_DATA_ERROR;
+#endif
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
+ state = (struct inflate_state FAR *)strm->state;
+ return ((long)(state->back) << 16) +
+ (state->mode == COPY ? state->length :
+ (state->mode == MATCH ? state->was - state->length : 0));
+}
diff --git a/vendor/cfitsio/inflate.h b/vendor/cfitsio/inflate.h
new file mode 100644
index 00000000..95f4986d
--- /dev/null
+++ b/vendor/cfitsio/inflate.h
@@ -0,0 +1,122 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY_, /* i/o: same as COPY below, but only first time in */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN_, /* i: same as LEN below, but only first time in */
+ LEN, /* i: waiting for length/lit/eob code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib) or (raw)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+ HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ (raw) -> TYPEDO
+ Read deflate blocks:
+ TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+ STORED -> COPY_ -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN_
+ LEN_ -> LEN
+ Read deflate codes in fixed or dynamic block:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 10K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+ int sane; /* if false, allow invalid distance too far */
+ int back; /* bits back of last unprocessed length/lit */
+ unsigned was; /* initial length of match */
+};
diff --git a/vendor/cfitsio/inftrees.c b/vendor/cfitsio/inftrees.c
new file mode 100644
index 00000000..11e9c52a
--- /dev/null
+++ b/vendor/cfitsio/inftrees.c
@@ -0,0 +1,330 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.5 Copyright 1995-2010 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code here; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)1;
+ here.val = (unsigned short)0;
+ *(*table)++ = here; /* make a table to force an error */
+ *(*table)++ = here;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min < max; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked for LENS and DIST tables against
+ the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+ the initial root table size constants. See the comments in inftrees.h
+ for more information.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if ((type == LENS && used >= ENOUGH_LENS) ||
+ (type == DISTS && used >= ENOUGH_DISTS))
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ here.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ here.op = (unsigned char)0;
+ here.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ here.op = (unsigned char)(extra[work[sym]]);
+ here.val = base[work[sym]];
+ }
+ else {
+ here.op = (unsigned char)(32 + 64); /* end of block */
+ here.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = here;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if ((type == LENS && used >= ENOUGH_LENS) ||
+ (type == DISTS && used >= ENOUGH_DISTS))
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)(len - drop);
+ here.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ here.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = here;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/vendor/cfitsio/inftrees.h b/vendor/cfitsio/inftrees.h
new file mode 100644
index 00000000..baa53a0b
--- /dev/null
+++ b/vendor/cfitsio/inftrees.h
@@ -0,0 +1,62 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table. The maximum number of code structures is
+ 1444, which is the sum of 852 for literal/length codes and 592 for distance
+ codes. These values were found by exhaustive searches using the program
+ examples/enough.c found in the zlib distribtution. The arguments to that
+ program are the number of symbols, the initial root table size, and the
+ maximum bit length of a code. "enough 286 9 15" for literal/length codes
+ returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+ The initial root table size (9 or 6) is found in the fifth argument of the
+ inflate_table() calls in inflate.c and infback.c. If the root table size is
+ changed, then these maximum sizes would be need to be recalculated and
+ updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/vendor/cfitsio/iraffits.c b/vendor/cfitsio/iraffits.c
new file mode 100644
index 00000000..d8fc06b2
--- /dev/null
+++ b/vendor/cfitsio/iraffits.c
@@ -0,0 +1,2073 @@
+/*------------------------------------------------------------------------*/
+/* */
+/* 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);
+static int getirafpixname (char *hdrname, char *irafheader, char *pixfilename, int *status);
+int iraf2mem(char *filename, char **buffptr, size_t *buffsize,
+ size_t *filesize, int *status);
+
+void ffpmsg(const char *err_message);
+
+/*--------------------------------------------------------------------------*/
+int fits_delete_iraf_file(char *filename, /* name of input file */
+ int *status) /* IO - error status */
+
+/*
+ Delete the iraf .imh header file and the associated .pix data file
+*/
+{
+ char *irafheader;
+ int lenirafhead;
+
+ char pixfilename[SZ_IM2PIXFILE+1];
+
+ /* read IRAF header into dynamically created char array (free it later!) */
+ irafheader = irafrdhead(filename, &lenirafhead);
+
+ if (!irafheader)
+ {
+ return(*status = FILE_NOT_OPENED);
+ }
+
+ getirafpixname (filename, irafheader, pixfilename, status);
+
+ /* don't need the IRAF header any more */
+ free(irafheader);
+
+ if (*status > 0)
+ return(*status);
+
+ remove(filename);
+ remove(pixfilename);
+
+ return(*status);
+}
+
+/*--------------------------------------------------------------------------*/
+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 = 1, naxis1 = 1, naxis2 = 1, naxis3 = 1, naxis4 = 1, npaxis1 = 1, npaxis2;
+ int bitpix, bytepix, i;
+ char *fitsheader, *image;
+ int nbr, nbimage, nbaxis, nbl, nbdiff;
+ char *pixheader;
+ char *linebuff;
+ int imhver, lpixhead = 0;
+ char pixname[SZ_IM2PIXFILE+1];
+ char errmsg[81];
+ size_t newfilesize;
+
+ fitsheader = *buffptr; /* pointer to start of header */
+
+ /* 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;
+ fseek (fd, nbdiff, 1);
+ 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;
+/* int 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);
+ if (newpixname) {
+ free (pixname);
+ pixname = newpixname;
+ }
+ }
+ if (strchr (pixname, '/') == NULL && strchr (pixname, '$') == NULL) {
+ newpixname = same_path (pixname, hdrname);
+ if (newpixname) {
+ 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);
+}
+/*--------------------------------------------------------------------------*/
+
+/* get the IRAF pixel file name */
+
+static int getirafpixname (
+ char *hdrname, /* IRAF header file name (may be path) */
+ char *irafheader, /* IRAF image header */
+ char *pixfilename, /* IRAF pixel file name */
+ int *status)
+{
+ int imhver;
+ char *pixname, *newpixname, *bang;
+
+ /* 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);
+ }
+
+ /* get 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);
+ if (newpixname) {
+ free (pixname);
+ pixname = newpixname;
+ }
+ }
+
+ if (strchr (pixname, '/') == NULL && strchr (pixname, '$') == NULL) {
+ newpixname = same_path (pixname, hdrname);
+ if (newpixname) {
+ free (pixname);
+ pixname = newpixname;
+ }
+ }
+
+ if ((bang = strchr (pixname, '!')) != NULL )
+ strcpy(pixfilename,bang+1);
+ else
+ strcpy(pixfilename,pixname);
+
+ free (pixname);
+
+ 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;
+
+/* WDP - 10/16/2007 - increased allocation to avoid possible overflow */
+/* newpixname = (char *) calloc (SZ_IM2PIXFILE, sizeof (char)); */
+
+ newpixname = (char *) calloc (2*SZ_IM2PIXFILE+1, sizeof (char));
+ if (newpixname == NULL) {
+ ffpmsg("iraffits same_path: Cannot alloc memory for newpixname");
+ return (NULL);
+ }
+
+ /* 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/vendor/cfitsio/iter_a.c b/vendor/cfitsio/iter_a.c
new file mode 100644
index 00000000..19ea1d1c
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/iter_a.f b/vendor/cfitsio/iter_a.f
new file mode 100644
index 00000000..e6221897
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/iter_a.fit b/vendor/cfitsio/iter_a.fit
new file mode 100644
index 00000000..0f951cfd
--- /dev/null
+++ b/vendor/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= 30554.5 / 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/vendor/cfitsio/iter_b.c b/vendor/cfitsio/iter_b.c
new file mode 100644
index 00000000..296f4e16
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/iter_b.f b/vendor/cfitsio/iter_b.f
new file mode 100644
index 00000000..7a2a6e7d
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/iter_b.fit b/vendor/cfitsio/iter_b.fit
new file mode 100644
index 00000000..74dcd9d6
--- /dev/null
+++ b/vendor/cfitsio/iter_b.fit
Binary files differ
diff --git a/vendor/cfitsio/iter_c.c b/vendor/cfitsio/iter_c.c
new file mode 100644
index 00000000..bbf97742
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/iter_c.f b/vendor/cfitsio/iter_c.f
new file mode 100644
index 00000000..f9abeaa8
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/iter_c.fit b/vendor/cfitsio/iter_c.fit
new file mode 100644
index 00000000..f8576741
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/iter_image.c b/vendor/cfitsio/iter_image.c
new file mode 100644
index 00000000..43f263cb
--- /dev/null
+++ b/vendor/cfitsio/iter_image.c
@@ -0,0 +1,93 @@
+#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_image.fit' image file by setting
+ all the pixel values to zero (DESTROYING THE ORIGINAL IMAGE!!!)
+*/
+main()
+{
+ extern zero_image(); /* 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_image.fit"; /* name of rate FITS file */
+
+ status = 0;
+
+ fits_open_file(&fptr, filename, READWRITE, &status); /* open file */
+
+
+ n_cols = 1;
+
+ /* define input column structure members for the iterator function */
+ fits_iter_set_file(&cols[0], fptr);
+ fits_iter_set_iotype(&cols[0], InputOutputCol);
+ fits_iter_set_datatype(&cols[0], 0);
+
+ 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,
+ zero_image, 0L, &status);
+
+ fits_close_file(fptr, &status); /* all done */
+
+ if (status)
+ fits_report_error(stderr, status); /* print out error messages */
+
+ return(status);
+}
+/*--------------------------------------------------------------------------*/
+int zero_image(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 int *counts;
+
+ /*--------------------------------------------------------*/
+ /* Initialization procedures: execute on the first call */
+ /*--------------------------------------------------------*/
+ if (firstrow == 1)
+ {
+ if (ncols != 1)
+ return(-1); /* number of columns incorrect */
+
+ /* assign the input pointers to the appropriate arrays and null ptrs*/
+ counts = (int *) fits_iter_get_array(&cols[0]);
+ }
+
+ /*--------------------------------------------*/
+ /* 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++)
+ {
+ counts[ii] = 1.;
+ }
+ printf("firstrows, nrows = %d %d\n", firstrow, nrows);
+
+ return(0); /* return successful status */
+}
diff --git a/vendor/cfitsio/iter_var.c b/vendor/cfitsio/iter_var.c
new file mode 100644
index 00000000..50d01320
--- /dev/null
+++ b/vendor/cfitsio/iter_var.c
@@ -0,0 +1,100 @@
+#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[] = "vari.fits"; /* 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, "COMPRESSED_IMAGE", 0, &status) )
+ fits_report_error(stderr, status); /* print out error messages */
+
+ n_cols = 1; /* number of columns */
+
+ /* define input column structure members for the iterator function */
+ fits_iter_set_by_name(&cols[0], fptr, "COMPRESSED_DATA", 0, InputCol);
+
+ 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;
+ long repeat;
+
+ /* declare variables static to preserve their values between calls */
+ static unsigned char *counts;
+
+ /*--------------------------------------------------------*/
+ /* Initialization procedures: execute on the first call */
+ /*--------------------------------------------------------*/
+ if (firstrow == 1)
+ {
+
+printf("Datatype of column = %d\n",fits_iter_get_datatype(&cols[0]));
+
+ /* assign the input pointers to the appropriate arrays and null ptrs*/
+ counts = (long *) fits_iter_get_array(&cols[0]);
+
+ }
+
+ /*--------------------------------------------*/
+ /* 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++)
+ {
+ repeat = fits_iter_get_repeat(&cols[0]);
+ printf ("repeat = %d, %d\n",repeat, counts[1]);
+
+ }
+
+
+ return(0); /* return successful status */
+}
diff --git a/vendor/cfitsio/longnam.h b/vendor/cfitsio/longnam.h
new file mode 100644
index 00000000..cac8da4b
--- /dev/null
+++ b/vendor/cfitsio/longnam.h
@@ -0,0 +1,592 @@
+#ifndef _LONGNAME_H
+#define _LONGNAME_H
+
+#define fits_parse_input_url ffiurl
+#define fits_parse_input_filename ffifile
+#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_parse_rangell ffrwrgll
+#define fits_open_memfile ffomem
+
+/*
+ use the following special macro to test that the fitsio.h include
+ file that was used to build the CFITSIO library is the same version
+ as included when compiling the application program
+*/
+#define fits_open_file(A, B, C, D) ffopentest( CFITSIO_VERSION, A, B, C, D)
+
+#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_get_inttype ffinttyp
+#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_binary_tformll ffbnfmll
+#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_tdimll ffptdmll
+#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_imghdrll ffphpsll
+#define fits_write_grphdr ffphpr
+#define fits_write_grphdrll ffphprll
+#define fits_write_atblhdr ffphtb
+#define fits_write_btblhdr ffphbn
+#define fits_write_exthdr ffphext
+#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_str ffgstr
+#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_lnglng ffgkyjj
+#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_free_memory fffree
+#define fits_read_tdim ffgtdm
+#define fits_read_tdimll ffgtdmll
+#define fits_decode_tdim ffdtdm
+#define fits_decode_tdimll ffdtdmll
+#define fits_read_keys_str ffgkns
+#define fits_read_keys_log ffgknl
+#define fits_read_keys_lng ffgknj
+#define fits_read_keys_lnglng ffgknjj
+#define fits_read_keys_flt ffgkne
+#define fits_read_keys_dbl ffgknd
+#define fits_read_imghdr ffghpr
+#define fits_read_imghdrll ffghprll
+#define fits_read_atblhdr ffghtb
+#define fits_read_btblhdr ffghbn
+#define fits_read_atblhdrll ffghtbll
+#define fits_read_btblhdrll ffghbnll
+#define fits_hdr2str ffhdr2str
+#define fits_convert_hdr2str ffcnvthdr2str
+
+#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_str ffdstr
+#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_hduaddrll ffghadll
+#define fits_get_hduoff ffghof
+
+#define fits_get_img_param ffgipr
+#define fits_get_img_paramll ffgiprll
+
+#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_get_img_sizell ffgiszll
+
+#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_imgll ffcrimll
+#define fits_create_tbl ffcrtb
+#define fits_create_hdu ffcrhd
+#define fits_insert_img ffiimg
+#define fits_insert_imgll ffiimgll
+#define fits_insert_atbl ffitab
+#define fits_insert_btbl ffibin
+#define fits_resize_img ffrsim
+#define fits_resize_imgll ffrsimll
+
+#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_write_hdu ffwrhdu
+
+#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_coltypell ffgtclll
+#define fits_get_eqcoltype ffeqty
+#define fits_get_eqcoltypell ffeqtyll
+#define fits_get_num_rows ffgnrw
+#define fits_get_num_rowsll ffgnrwll
+#define fits_get_num_cols ffgncl
+#define fits_get_acolparms ffgacl
+#define fits_get_bcolparms ffgbcl
+#define fits_get_bcolparmsll ffgbclll
+
+#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_pixll ffgpxvll
+#define fits_read_pixnull ffgpxf
+#define fits_read_pixnullll ffgpxfll
+#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 ffcpimg fits_copy_image_section
+#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_descriptll ffgdesll
+#define fits_read_descripts ffgdess
+#define fits_read_descriptsll ffgdessll
+#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_pixll ffppxll
+#define fits_write_pixnull ffppxn
+#define fits_write_pixnullll ffppxnll
+#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_nulrows ffprwu
+#define fits_write_nullrows ffprwu
+
+#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_ext ffpextn
+#define fits_read_ext ffgextn
+
+#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_delete_rowlistll ffdrwsll
+#define fits_insert_col fficol
+#define fits_insert_cols fficls
+#define fits_delete_col ffdcol
+#define fits_copy_col ffcpcl
+#define fits_copy_rows ffcprw
+#define fits_modify_vector_len ffmvec
+
+#define fits_read_img_coord ffgics
+#define fits_read_img_coord_version ffgicsa
+#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/vendor/cfitsio/make_dfloat.com b/vendor/cfitsio/make_dfloat.com
new file mode 100644
index 00000000..1a7841f9
--- /dev/null
+++ b/vendor/cfitsio/make_dfloat.com
@@ -0,0 +1,90 @@
+$ ! 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 f77_wrap3.c
+$ cc/float=d_float f77_wrap4.c
+$ cc/float=d_float getcol.c
+$ cc/float=d_float getcolb.c
+$ cc/float=d_float getcolsb.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 putcolsb.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
+$ cc/float=d_float fits_hcompress.c
+$ cc/float=d_float fits_hdecompress.c
+$ lib/create cfitsio buffers,cfileio,checksum,compress,drvrfile,drvrmem
+$ lib/insert cfitsio editcol,edithdu,eval_f,eval_l,eval_y
+$ lib/insert cfitsio f77_wrap1,f77_wrap2,f77_wrap3,f77_wrap4
+$ lib/insert cfitsio fitscore,getcol,getcolb,getcoli,getcolj,getcolk,getcole
+$ lib/insert cfitsio getcold,getcoll,getcols,getcolui,getcoluj,getcoluk,getcolsb
+$ lib/insert cfitsio getkey,group,grparser,histo,iraffits,modkey,putcol,putcolb
+$ lib/insert cfitsio putcoli,putcolj,putcolk,putcole,putcold,putcolui,putcolsb
+$ lib/insert cfitsio putcoluj,putcoluk,putcols,putcoll,putcolu,putkey,region
+$ lib/insert cfitsio scalnull,swapproc,wcsutil,wcssub,imcompress
+$ lib/insert cfitsio quantize,ricecomp,pliocomp,fits_hcompress,fits_hdecompress
+$ !
+$ 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/vendor/cfitsio/make_gfloat.com b/vendor/cfitsio/make_gfloat.com
new file mode 100644
index 00000000..bfacd8b1
--- /dev/null
+++ b/vendor/cfitsio/make_gfloat.com
@@ -0,0 +1,88 @@
+$ ! 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 f77_wrap3.c
+$ cc f77_wrap4.c
+$ cc getcol.c
+$ cc getcolb.c
+$ cc getcolsb.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 putcolsb.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
+$ cc/float=d_float fits_hcompress.c
+$ cc/float=d_float fits_hdecompress.c
+$ lib/create cfitsio buffers,cfileio,checksum,compress,drvrfile,drvrmem
+$ lib/insert cfitsio editcol,edithdu,eval_f,eval_l,eval_y
+$ lib/insert cfitsio f77_wrap1,f77_wrap2,f77_wrap3,f77_wrap4
+$ lib/insert cfitsio fitscore,getcol,getcolb,getcoli,getcolj,getcolk,getcole
+$ lib/insert cfitsio getcold,getcoll,getcols,getcolui,getcoluj,getcoluk,getcolsb
+$ lib/insert cfitsio getkey,group,grparser,histo,iraffits,modkey,putcol,putcolb
+$ lib/insert cfitsio putcoli,putcolj,putcolk,putcole,putcold,putcolui,putcolsb
+$ lib/insert cfitsio putcoluj,putcoluk,putcols,putcoll,putcolu,putkey,region
+$ lib/insert cfitsio scalnull,swapproc,wcsutil,wcssub,imcompress
+$ lib/insert cfitsio quantize,ricecomp,pliocomp,fits_hcompress,fits_hdecompress
+$ !
+$ 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/vendor/cfitsio/make_ieee.com b/vendor/cfitsio/make_ieee.com
new file mode 100644
index 00000000..89ab4374
--- /dev/null
+++ b/vendor/cfitsio/make_ieee.com
@@ -0,0 +1,87 @@
+$ ! 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 f77_wrap3.c
+$ cc/float=ieee_float f77_wrap4.c
+$ cc/float=ieee_float getcol.c
+$ cc/float=ieee_float getcolb.c
+$ cc/float=ieee_float getcolsb.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 putcolsb.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
+$ cc/float=d_float fits_hcompress.c
+$ cc/float=d_float fits_hdecompress.c
+$ lib/create cfitsio buffers,cfileio,checksum,compress,drvrfile,drvrmem
+$ lib/insert cfitsio editcol,edithdu,eval_f,eval_l,eval_y
+$ lib/insert cfitsio f77_wrap1,f77_wrap2,f77_wrap3,f77_wrap4
+$ lib/insert cfitsio fitscore,getcol,getcolb,getcoli,getcolj,getcolk,getcole
+$ lib/insert cfitsio getcold,getcoll,getcols,getcolui,getcoluj,getcoluk,getcolsb
+$ lib/insert cfitsio getkey,group,grparser,histo,iraffits,modkey,putcol,putcolb
+$ lib/insert cfitsio putcoli,putcolj,putcolk,putcole,putcold,putcolui,putcolsb
+$ lib/insert cfitsio putcoluj,putcoluk,putcols,putcoll,putcolu,putkey,region
+$ lib/insert cfitsio scalnull,swapproc,wcsutil,wcssub,imcompress
+$ lib/insert cfitsio quantize,ricecomp,pliocomp,fits_hcompress,fits_hdecompress
+$ !
+$ 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/vendor/cfitsio/makefile.bc b/vendor/cfitsio/makefile.bc
new file mode 100644
index 00000000..8e8526ea
--- /dev/null
+++ b/vendor/cfitsio/makefile.bc
@@ -0,0 +1,588 @@
+#
+# 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\
+ checksum.obj\
+ cfileio.obj\
+ buffers.obj\
+ fits_hcompress.obj\
+ fits_hdecompress.obj\
+ zuncompress.obj\
+ zcompress.obj\
+ adler32.obj\
+ crc32.obj\
+ inffast.obj\
+ inftrees.obj\
+ trees.obj\
+ zutil.obj\
+ deflate.obj\
+ infback.obj\
+ inflate.obj\
+ uncompr.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+
+checksum.obj+
+cfileio.obj+
+buffers.obj+
+fits_hcompress.obj+
+fits_hdecompress.obj+
+zuncompress.obj+
+zcompress.obj+
+adler32.obj+
+crc32.obj+
+inffast.obj+
+inftrees.obj+
+trees.obj+
+zutil.obj+
+deflate.obj+
+infback.obj+
+inflate.obj+
+uncompr.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
+|
+
+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
+|
+
+fits_hcompress.obj : fits_hcompress.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ fits_hcompress.c
+|
+
+fits_hdecompress.obj : fits_hdecompress.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ fits_hdecompress.c
+|
+
+zuncompress.obj : zuncompress.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ zuncompress.c
+|
+
+zcompress.obj : zcompress.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ zcompress.c
+|
+
+adler32.obj : adler32.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ adler32.c
+|
+
+crc32.obj : crc32.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ crc32.c
+|
+
+inffast.obj : inffast.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ inffast.c
+|
+
+inftrees.obj : inftrees.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ inftrees.c
+|
+
+trees.obj : trees.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ trees.c
+|
+
+zutil.obj : zutil.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ zutil.c
+|
+
+deflate.obj : deflate.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ deflate.c
+|
+
+infback.obj : infback.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ infback.c
+|
+
+inflate.obj : inflate.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ inflate.c
+|
+
+uncompr.obj : uncompr.c
+ $(BCC32) -P- -c @&&|
+ $(CompOptsAt_cfitsiodlib) $(CompInheritOptsAt_cfitsiodlib) -o$@ uncompr.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/vendor/cfitsio/makefile.vcc b/vendor/cfitsio/makefile.vcc
new file mode 100644
index 00000000..e0e28b8b
--- /dev/null
+++ b/vendor/cfitsio/makefile.vcc
@@ -0,0 +1,793 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on cfitsio.dsp
+!IF "$(CFG)" == ""
+CFG=Win32 Release
+!MESSAGE No configuration specified. Defaulting to Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "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="Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "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)" == "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)\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)\wcssub.obj"
+ -@erase "$(INTDIR)\wcsutil.obj"
+ -@erase "$(INTDIR)\imcompress.obj"
+ -@erase "$(INTDIR)\ricecomp.obj"
+ -@erase "$(INTDIR)\quantize.obj"
+ -@erase "$(INTDIR)\pliocomp.obj"
+ -@erase "$(INTDIR)\fits_hcompress.obj"
+ -@erase "$(INTDIR)\fits_hdecompress.obj"
+ -@erase "$(INTDIR)\zuncompress.obj"
+ -@erase "$(INTDIR)\zcompress.obj"
+ -@erase "$(INTDIR)\adler32.obj"
+ -@erase "$(INTDIR)\crc32.obj"
+ -@erase "$(INTDIR)\inffast.obj"
+ -@erase "$(INTDIR)\inftrees.obj"
+ -@erase "$(INTDIR)\trees.obj"
+ -@erase "$(INTDIR)\zutil.obj"
+ -@erase "$(INTDIR)\deflate.obj"
+ -@erase "$(INTDIR)\infback.obj"
+ -@erase "$(INTDIR)\inflate.obj"
+ -@erase "$(INTDIR)\uncompr.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@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" /D "_CRT_SECURE_NO_DEPRECATE" /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)\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" \
+ "$(INTDIR)\fits_hcompress.obj" \
+ "$(INTDIR)\fits_hdecompress.obj" \
+ "$(INTDIR)\zuncompress.obj" \
+ "$(INTDIR)\zcompress.obj" \
+ "$(INTDIR)\adler32.obj" \
+ "$(INTDIR)\crc32.obj" \
+ "$(INTDIR)\inffast.obj" \
+ "$(INTDIR)\inftrees.obj" \
+ "$(INTDIR)\trees.obj" \
+ "$(INTDIR)\zutil.obj" \
+ "$(INTDIR)\deflate.obj" \
+ "$(INTDIR)\infback.obj" \
+ "$(INTDIR)\inflate.obj" \
+ "$(INTDIR)\uncompr.obj"
+
+"$(OUTDIR)\cfitsio.dll" : $(LINK32_OBJS) WINDUMP
+ windumpexts -o $(DEF_FILE) cfitsio.dll $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "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)\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 "$(INTDIR)\fits_hcompress.obj"
+ -@erase "$(INTDIR)\fits_hdecompress.obj"
+ -@erase "$(INTDIR)\zuncompress.obj"
+ -@erase "$(INTDIR)\zcompress.obj"
+ -@erase "$(INTDIR)\adler32.obj"
+ -@erase "$(INTDIR)\crc32.obj"
+ -@erase "$(INTDIR)\inffast.obj"
+ -@erase "$(INTDIR)\inftrees.obj"
+ -@erase "$(INTDIR)\trees.obj"
+ -@erase "$(INTDIR)\zutil.obj"
+ -@erase "$(INTDIR)\deflate.obj"
+ -@erase "$(INTDIR)\infback.obj"
+ -@erase "$(INTDIR)\inflate.obj"
+ -@erase "$(INTDIR)\uncompr.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 /MDd /W3 /Gm /GX /ZI /Od /D "__WIN32__" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CFITSIO_EXPORTS" /D "_CRT_SECURE_NO_DEPRECATE" /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)\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" \
+ "$(INTDIR)\fits_hcompress.obj" \
+ "$(INTDIR)\fits_hdecompress.obj" \
+ "$(INTDIR)\zuncompress.obj" \
+ "$(INTDIR)\zcompress.obj" \
+ "$(INTDIR)\adler32.obj" \
+ "$(INTDIR)\crc32.obj" \
+ "$(INTDIR)\inffast.obj" \
+ "$(INTDIR)\inftrees.obj" \
+ "$(INTDIR)\trees.obj" \
+ "$(INTDIR)\zutil.obj" \
+ "$(INTDIR)\deflate.obj" \
+ "$(INTDIR)\infback.obj" \
+ "$(INTDIR)\inflate.obj" \
+ "$(INTDIR)\uncompr.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)" == "Win32 Release" || "$(CFG)" == "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=.\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)"
+
+SOURCE=fits_hcompress.c
+
+"$(INTDIR)\fits_hcompress.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=fits_hdecompress.c
+
+"$(INTDIR)\fits_hdecompress.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=zuncompress.c
+
+"$(INTDIR)\zuncompress.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=zcompress.c
+
+"$(INTDIR)\zcompress.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=adler32.c
+
+"$(INTDIR)\adler32.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=crc32.c
+
+"$(INTDIR)\crc32.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=inffast.c
+
+"$(INTDIR)\inffast.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=inftrees.c
+
+"$(INTDIR)\inftrees.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=trees.c
+
+"$(INTDIR)\trees.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=zutil.c
+
+"$(INTDIR)\zutil.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=deflate.c
+
+"$(INTDIR)\deflate.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=infback.c
+
+"$(INTDIR)\infback.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=inflate.c
+
+"$(INTDIR)\inflate.obj" : $(SOURCE) "$(INTDIR)"
+
+SOURCE=uncompr.c
+
+"$(INTDIR)\uncompr.obj" : $(SOURCE) "$(INTDIR)"
+
+!ENDIF
+
+$(DEF_FILE):
+
+
+
+WINDUMP:
+ nmake -f winDumpExts.mak
diff --git a/vendor/cfitsio/makepc.bat b/vendor/cfitsio/makepc.bat
new file mode 100644
index 00000000..3079a296
--- /dev/null
+++ b/vendor/cfitsio/makepc.bat
@@ -0,0 +1,87 @@
+rem: this batch file builds the cfitsio library
+rem: using the Borland C++ v4.5 or new free v5.5 compiler
+rem:
+bcc32 -c buffers.c
+bcc32 -c cfileio.c
+bcc32 -c checksum.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 getcolsb.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 putcolsb.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
+bcc32 -c fits_hcompress.c
+bcc32 -c fits_hdecompress.c
+bcc32 -c zuncompress.c
+bcc32 -c zcompress.c
+bcc32 -c adler32.c
+bcc32 -c crc32.c
+bcc32 -c inffast.c
+bcc32 -c inftrees.c
+bcc32 -c trees.c
+bcc32 -c zutil.c
+bcc32 -c deflate.c
+bcc32 -c infback.c
+bcc32 -c inflate.c
+bcc32 -c uncompr.c
+del cfitsio.lib
+tlib cfitsio +buffers +cfileio +checksum +drvrfile +drvrmem
+tlib cfitsio +editcol +edithdu +eval_l +eval_y +eval_f +fitscore
+tlib cfitsio +getcol +getcolb +getcolsb +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 +putcolsb
+tlib cfitsio +imcompress +quantize +ricecomp +pliocomp
+tlib cfitsio +fits_hcompress +fits_hdecompress
+tlib cfitsio +zuncompress +zcompress +adler32 +crc32 +inffast
+tlib cfitsio +inftrees +trees +zutil +deflate +infback +inflate +uncompr
+bcc32 -f testprog.c cfitsio.lib
+bcc32 -f cookbook.c cfitsio.lib
+
diff --git a/vendor/cfitsio/mklibs b/vendor/cfitsio/mklibs
new file mode 100755
index 00000000..3b6f4dc5
--- /dev/null
+++ b/vendor/cfitsio/mklibs
@@ -0,0 +1,31 @@
+#!/bin/csh -f
+
+#set top = `(chdir .. ; pwd)`
+set top = `pwd`
+
+setenv CC "gcc"
+setenv CXX "g++"
+
+
+if ($?PLMACH) then
+ if ($PLMACH == "macosx") then
+ setenv CFLAGS "-mmacosx-version-min=10.5 -DDarwin"
+ endif
+endif
+
+echo " (Using toplevel directory '"$top"' ....)"
+
+# Global options.
+set gopts = "--prefix=$top --exec-prefix=$top --disable-shared"
+
+./configure $gopts >& _spool
+make clean >>& _spool
+make >>& _spool
+
+cp libcfitsio.a ../voclient/lib
+mv libcfitsio.a ../../lib
+cp fitsio*.h longnam.h ../../include
+
+make clean
+echo "done"
+
diff --git a/vendor/cfitsio/mkpkg b/vendor/cfitsio/mkpkg
new file mode 100644
index 00000000..e428f680
--- /dev/null
+++ b/vendor/cfitsio/mkpkg
@@ -0,0 +1,74 @@
+# CFITSIO -- Update the CFITSIO library.
+# copied from the fitsio mkpkg by jdd 12 sept 1996
+#
+# this is a sample IRAF mkfile which builds a local version of the CFITSIO lib.
+
+$call update
+$exit
+
+update:
+ $checkout libcfitsio.a ftoolsbin$
+ $update libcfitsio.a
+ $checkin libcfitsio.a ftoolsbin$
+ ;
+
+updateftools:
+ #Extra target for building fitsio inside the FTOOLS distribution
+ $checkout libcfitsio.a ftoolsbin$
+ $update libcfitsio.a
+ $checkin libcfitsio.a ftoolsbin$
+ ;
+
+cfitsio:
+ # Update fitsio subdirectory if new version of cfitsio.c installed.
+ $ifolder (splitc/cfileio.c, cfileio.c)
+ $echo "update cfitsio splitc subdirectory..."
+ $iffile(splitc/cfileio.c)
+ !\rm splitc/*
+ $delete splitc/mkpkg
+ $else
+ !mkdir splitc
+ !./configure
+ $endif
+ $copy buffers.c splitc/buffers.c
+ $copy cfileio.c splitc/cfileio.c
+ $copy checksum.c splitc/checksum.c
+ $copy compress.c splitc/compress.c
+ $copy f77_iter.c splitc/f77_iter.c
+ $copy f77_wrap.c splitc/f77_wrap.c
+ $copy drvrfile.c splitc/drvrfile.c
+ $copy fitscore.c splitc/fitscore.c
+ $copy editcol.c splitc/editcol.c
+ $copy edithdu.c splitc/edithdu.c
+ $copy getkey.c splitc/getkey.c
+ $copy modkey.c splitc/modkey.c
+ $copy putkey.c splitc/putkey.c
+ $copy scalnull.c splitc/scalnull.c
+ $copy swapproc.c splitc/swapproc.c
+ $copy wcsutil.c splitc/wcsutil.c
+ !cp getcol*.c splitc/
+ !cp putcol*.c splitc/
+ !cp *.h splitc/
+ !cp *.h ../include
+ !cd splitc
+ !echo '$checkout libcfitsio.a ../libcfitsio.a' > splitc/mkpkg
+ !echo '$update libcfitsio.a' >> splitc/mkpkg
+ !echo '$checkin libcfitsio.a ../libcfitsio.a' >> splitc/mkpkg
+ !echo ' ' >> splitc/mkpkg
+ !echo 'libcfitsio.a:' >> splitc/mkpkg
+ !cd splitc; ls -1 *.c | sed 's/^/ /' >> mkpkg
+ !echo ' ;' >> splitc/mkpkg
+ $endif
+ ;
+
+libcfitsio.a:
+ $ifeq (hostid, unix)
+ # cheat and use Makefile....
+ $call cfitsio
+ @splitc
+ $else
+ # simply compile the files on VMS systems.
+ !@makevms.com
+ $endif
+
+ ;
diff --git a/vendor/cfitsio/modkey.c b/vendor/cfitsio/modkey.c
new file mode 100644
index 00000000..e6fe03a6
--- /dev/null
+++ b/vendor/cfitsio/modkey.c
@@ -0,0 +1,1706 @@
+/* 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 */
+ const 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, (LONGLONG) *(unsigned char *) value, comm, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffukyj(fptr, keyname, (LONGLONG) *(signed char *) value, comm, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffukyj(fptr, keyname, (LONGLONG) *(unsigned short *) value, comm, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffukyj(fptr, keyname, (LONGLONG) *(short *) value, comm, status);
+ }
+ else if (datatype == TINT)
+ {
+ ffukyj(fptr, keyname, (LONGLONG) *(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, (LONGLONG) *(long *) value, comm, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffukyj(fptr, keyname, *(LONGLONG *) 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 */
+ const 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 */
+ const 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 */
+ const 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;
+ char junk[FLEN_ERRMSG];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ tstatus = *status;
+
+ if (ffmkls(fptr, keyname, value, comm, status) == KEY_NO_EXIST)
+ {
+ /* since the ffmkls call failed, it wrote a bogus error message */
+ fits_read_errmsg(junk); /* clear the error message */
+
+ *status = tstatus;
+ ffpkls(fptr, keyname, value, comm, status);
+ }
+ return(*status);
+}/*--------------------------------------------------------------------------*/
+int ffukyl(fitsfile *fptr, /* I - FITS file pointer */
+ const 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 */
+ const char *keyname, /* I - keyword name */
+ LONGLONG 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const char *keyname, /* I - keyword name */
+ char *card, /* I - card string value */
+ int *status) /* IO - error status */
+{
+ char tcard[FLEN_CARD], valstring[FLEN_CARD], comm[FLEN_CARD], value[FLEN_CARD];
+ int keypos, len;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgcrd(fptr, keyname, tcard, status) > 0)
+ return(*status);
+
+ ffmkey(fptr, card, status);
+
+ /* calc position of keyword in header */
+ keypos = (int) ((((fptr->Fptr)->nextkey) - ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu])) / 80) + 1;
+
+ ffpsvc(tcard, valstring, comm, status);
+
+ /* 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 ffmnam(fitsfile *fptr, /* I - FITS file pointer */
+ const char *oldname, /* I - existing keyword name */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 = (int) (((((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 */
+ const 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], tmpkeyname[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 {
+ /* copy the input comment string */
+ strncpy(comm, incomm, FLEN_COMMENT-1);
+ comm[FLEN_COMMENT-1] = '\0';
+ }
+
+ /* 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 */
+ }
+
+ strncpy(tmpkeyname, keyname, 80);
+ tmpkeyname[80] = '\0';
+
+ cptr = tmpkeyname;
+ 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 */
+ const 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 */
+ const char *keyname, /* I - keyword name */
+ LONGLONG 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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], tmpkeyname[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 */
+ }
+
+
+ strncpy(tmpkeyname, keyname, 80);
+ tmpkeyname[80] = '\0';
+
+ cptr = tmpkeyname;
+ 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 */
+ const 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 */
+ const char *keyname, /* I - keyword name */
+ LONGLONG 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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;
+ LONGLONG 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);
+ }
+
+ /* no. keywords to shift */
+ nshift= (int) (( (fptr->Fptr)->headend - (fptr->Fptr)->nextkey ) / 80);
+
+ strncpy(buff2, card, 80); /* copy card to output buffer */
+ buff2[80] = '\0';
+
+ len = strlen(buff2);
+
+ /* silently replace any illegal characters with a space */
+ for (ii=0; ii < len; ii++)
+ if (buff2[ii] < ' ' || buff2[ii] > 126) buff2[ii] = ' ';
+
+ 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 */
+
+/* no need to do this any more, since any illegal characters have been removed
+ 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 */
+ const 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 = (int) ((((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 ffdstr(fitsfile *fptr, /* I - FITS file pointer */
+ const char *string, /* I - keyword name */
+ int *status) /* IO - error status */
+/*
+ delete a specified header keyword containing the input string
+*/
+{
+ int keypos, len;
+ char valstring[FLEN_VALUE], comm[FLEN_COMMENT], value[FLEN_VALUE];
+ char card[FLEN_CARD], message[FLEN_ERRMSG];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (ffgstr(fptr, string, card, status) > 0) /* read keyword */
+ {
+ sprintf(message, "Could not find the %s keyword to delete (ffdkey)",
+ string);
+ ffpmsg(message);
+ return(*status);
+ }
+
+ /* calc position of keyword in header */
+ keypos = (int) ((((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 */
+ ffpsvc(card, valstring, comm, status);
+ 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;
+ LONGLONG 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=(int) (( (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/vendor/cfitsio/pliocomp.c b/vendor/cfitsio/pliocomp.c
new file mode 100644
index 00000000..682599f3
--- /dev/null
+++ b/vendor/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 */
+ 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 */
+ int data, sw0001, otop, i__, lllen, i1, i2, x1, x2, ip, xe, np,
+ op, pv, opcode, llfirt;
+ 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/vendor/cfitsio/putcol.c b/vendor/cfitsio/putcol.c
new file mode 100644
index 00000000..0bfc9278
--- /dev/null
+++ b/vendor/cfitsio/putcol.c
@@ -0,0 +1,1929 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+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) */
+ LONGLONG 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 to
+ large images with more than 2**31 pixels.
+*/
+{
+ int naxis, ii;
+ long group = 1;
+ LONGLONG firstelem, dimsize = 1, naxes[9];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgiszll(fptr, 9, naxes, status);
+
+ firstelem = 0;
+ for (ii=0; ii < naxis; ii++)
+ {
+ firstelem += ((firstpix[ii] - 1) * dimsize);
+ dimsize *= naxes[ii];
+ }
+ firstelem++;
+
+ 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 ffppxll( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ LONGLONG *firstpix, /* I - coord of first pixel to write(1 based) */
+ LONGLONG 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 to
+ large images with more than 2**31 pixels.
+*/
+{
+ int naxis, ii;
+ long group = 1;
+ LONGLONG firstelem, dimsize = 1, naxes[9];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgiszll(fptr, 9, naxes, status);
+
+ firstelem = 0;
+ for (ii=0; ii < naxis; ii++)
+ {
+ firstelem += ((firstpix[ii] - 1) * dimsize);
+ dimsize *= naxes[ii];
+ }
+ firstelem++;
+
+ 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) */
+ LONGLONG 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).
+
+ This routine supports writing to large images with
+ more than 2**31 pixels.
+*/
+{
+ int naxis, ii;
+ long group = 1;
+ LONGLONG firstelem, dimsize = 1, naxes[9];
+
+ 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);
+ ffgiszll(fptr, 9, naxes, status);
+
+ firstelem = 0;
+ for (ii=0; ii < naxis; ii++)
+ {
+ firstelem += ((firstpix[ii] - 1) * dimsize);
+ dimsize *= naxes[ii];
+ }
+ firstelem++;
+
+ 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 ffppxnll( fitsfile *fptr, /* I - FITS file pointer */
+ int datatype, /* I - datatype of the value */
+ LONGLONG *firstpix, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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).
+
+ This routine supports writing to large images with
+ more than 2**31 pixels.
+*/
+{
+ int naxis, ii;
+ long group = 1;
+ LONGLONG firstelem, dimsize = 1, naxes[9];
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (nulval == NULL) /* null value not defined? */
+ {
+ ffppxll(fptr, datatype, firstpix, nelem, array, status);
+ return(*status);
+ }
+
+ /* get the size of the image */
+ ffgidm(fptr, &naxis, status);
+ ffgiszll(fptr, 9, naxes, status);
+
+ firstelem = 0;
+ for (ii=0; ii < naxis; ii++)
+ {
+ firstelem += ((firstpix[ii] - 1) * dimsize);
+ dimsize *= naxes[ii];
+ }
+ firstelem++;
+
+ 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 */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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).
+
+ This routine supports writing to large images with
+ more than 2**31 pixels.
+*/
+{
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, (long) firstelem, (long) 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG longlongnull;
+ } 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 */
+ }
+
+ /*------------------------------------------------------------*/
+ /* 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 &&
+ type != TLONGLONG )
+ {
+ 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) /* operating on FITS images */
+ {
+ 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 /* operating on FITS tables */
+ {
+ 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);
+ }
+ }
+
+ /* check that the column number is valid */
+ 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);
+ }
+ } /* end of loop over all columns */
+
+ /*-----------------------------------------------------------------*/
+ /* 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);
+ }
+ }
+
+ /* divid n_optimum by the number of files that will be processed */
+ 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 */
+ /*--------------------------------------*/
+
+ col = calloc(n_cols, sizeof(colNulls) ); /* memory for the null values */
+ if (!col)
+ {
+ ffpmsg("ffiter failed to allocate memory for null values");
+ *status = MEMORY_ALLOCATION; /* memory allocation failed */
+ return(*status);
+ }
+
+ 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;
+ case LONGLONG_IMG:
+ typecode = TLONGLONG;
+ 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, (long) 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;
+
+ case TLONGLONG:
+ cols[jj].array = calloc(ntodo + 1, sizeof(LONGLONG));
+ col[jj].nullsize = sizeof(LONGLONG); /* number of bytes per value */
+
+ if (abs(typecode) == TBYTE || abs(typecode) == TSHORT || abs(typecode) == TLONG ||
+ abs(typecode) == TLONGLONG)
+ {
+ col[jj].null.longlongnull = tnull;
+ }
+ else
+ {
+ col[jj].null.longlongnull = LONGLONG_MIN; /* use minimum as null */
+ }
+ 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 */
+ }
+ }
+ if (cols[jj].array)
+ 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/vendor/cfitsio/putcolb.c b/vendor/cfitsio/putcolb.c
new file mode 100644
index 00000000..8b962025
--- /dev/null
+++ b/vendor/cfitsio/putcolb.c
@@ -0,0 +1,1013 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffpprb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ fits_write_compressed_pixels(fptr, TBYTE, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TBYTE, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ LONGLONG nfits, narray;
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, maxelem2, hdutype, writeraw;
+ long twidth, incre;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull, maxelem;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpclb).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpclb(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpclb(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpclb(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffpextn( fitsfile *fptr, /* I - FITS file pointer */
+ LONGLONG offset, /* I - byte offset from start of extension data */
+ LONGLONG nelem, /* I - number of elements to write */
+ void *buffer, /* I - stream of bytes to write */
+ int *status) /* IO - error status */
+/*
+ Write a stream of bytes to the current FITS HDU. This primative routine is mainly
+ for writing non-standard "conforming" extensions and should not be used
+ for standard IMAGE, TABLE or BINTABLE extensions.
+*/
+{
+ 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);
+
+ /* rescan header if data structure is undefined */
+ else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
+ if ( ffrdef(fptr, status) > 0)
+ return(*status);
+
+ /* move to write position */
+ ffmbyt(fptr, (fptr->Fptr)->datastart+ offset, IGNORE_EOF, status);
+
+ /* write the buffer */
+ ffpbyt(fptr, nelem, buffer, 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
+*/
+{
+ 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 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] = (float) (( ( (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;
+ char *cptr;
+
+ cptr = output;
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcold.c b/vendor/cfitsio/putcold.c
new file mode 100644
index 00000000..82913679
--- /dev/null
+++ b/vendor/cfitsio/putcold.c
@@ -0,0 +1,1060 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffpprd( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ fits_write_compressed_pixels(fptr, TDOUBLE, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TDOUBLE, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, maxelem2, hdutype, writeraw;
+ long twidth, incre;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull, maxelem;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpcld).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ if (abs(tcode) >= TCOMPLEX)
+ { /* treat complex columns as pairs of numbers */
+ repeat *= 2;
+ }
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpcld(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 */
+
+ /* call ffpcluc, not ffpclu, in case we are writing to a
+ complex ('C') binary table column */
+ if (ffpcluc(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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpcld(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpcld(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 */
+ ffpcluc(fptr, colnum, fstrow, fstelm, nbad, status);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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.
+*/
+{
+ 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);
+ }
+ }
+ }
+ 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] = (float) ((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;
+ char *cptr;
+
+ cptr = output;
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcole.c b/vendor/cfitsio/putcole.c
new file mode 100644
index 00000000..af9aa86d
--- /dev/null
+++ b/vendor/cfitsio/putcole.c
@@ -0,0 +1,1074 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffppre( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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).
+
+ This routine cannot be called directly by users to write to large
+ arrays with > 2**31 pixels (although CFITSIO can do so by passing
+ the firstelem thru a LONGLONG sized global variable)
+*/
+{
+ 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 */
+
+ fits_write_compressed_pixels(fptr, TFLOAT, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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.
+
+ This routine cannot be called directly by users to write to large
+ arrays with > 2**31 pixels (although CFITSIO can do so by passing
+ the firstelem thru a LONGLONG sized global variable)
+*/
+{
+ 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TFLOAT, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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).
+
+ This routine does not support writing to large images with
+ more than 2**31 pixels.
+*/
+{
+ /* 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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).
+
+ This routine does not support writing to large images with
+ more than 2**31 pixels.
+*/
+{
+ long tablerow, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, maxelem2, hdutype, writeraw;
+ long twidth, incre;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull, maxelem;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpcle).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ if (abs(tcode) >= TCOMPLEX)
+ { /* treat complex columns as pairs of numbers */
+ repeat *= 2;
+ }
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpcle(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 */
+
+ /* call ffpcluc, not ffpclu, in case we are writing to a
+ complex ('C') binary table column */
+ if (ffpcluc(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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpcle(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpcle(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 */
+ ffpcluc(fptr, colnum, fstrow, fstelm, 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.
+*/
+{
+ 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);
+ }
+ }
+ }
+ 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] = (float) ((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;
+ char *cptr;
+
+ cptr = output;
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcoli.c b/vendor/cfitsio/putcoli.c
new file mode 100644
index 00000000..9a623f93
--- /dev/null
+++ b/vendor/cfitsio/putcoli.c
@@ -0,0 +1,986 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffppri( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write (1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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 */
+
+
+ fits_write_compressed_pixels(fptr, TSHORT, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TSHORT, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, maxelem2, hdutype, writeraw;
+ long twidth, incre;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull, maxelem;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpcli).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpcli(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpcli(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpcli(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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] = (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 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
+*/
+{
+ 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 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] = (float) ((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;
+ char *cptr, *tptr;
+
+ cptr = output;
+ tptr = output;
+
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcolj.c b/vendor/cfitsio/putcolj.c
new file mode 100644
index 00000000..57b1777e
--- /dev/null
+++ b/vendor/cfitsio/putcolj.c
@@ -0,0 +1,1992 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffpprj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ fits_write_compressed_pixels(fptr, TLONG, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TLONG, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, maxelem2, hdutype, writeraw;
+ long twidth, incre;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull, maxelem;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpclj).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpclj(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpclj(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpclj(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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] = (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 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] = (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 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
+*/
+{
+ 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 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] = (float) ((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;
+ char *cptr;
+
+ cptr = output;
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG nelem, /* I - number of values to write */
+ LONGLONG *array, /* I - array of values that are written */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ LONGLONG nfits, narray;
+ /*
+ 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, maxelem2, hdutype, writeraw;
+ long twidth, incre;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull, maxelem;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpclj).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpcljj(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpcljj(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpcljj(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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] = (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 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] = (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 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] = (float) ((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;
+ char *cptr;
+
+ cptr = output;
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcolk.c b/vendor/cfitsio/putcolk.c
new file mode 100644
index 00000000..90360575
--- /dev/null
+++ b/vendor/cfitsio/putcolk.c
@@ -0,0 +1,1013 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffpprk( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ fits_write_compressed_pixels(fptr, TINT, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TINT, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, maxelem2, hdutype, writeraw;
+ long twidth, incre;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull, maxelem;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem2, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+ maxelem = maxelem2;
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpclk).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpclk(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpclk(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpclk(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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
+*/
+{
+ 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 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] = (float) ((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;
+ char *cptr;
+
+ cptr = output;
+
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcoll.c b/vendor/cfitsio/putcoll.c
new file mode 100644
index 00000000..b26e9115
--- /dev/null
+++ b/vendor/cfitsio/putcoll.c
@@ -0,0 +1,369 @@
+/* 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull;
+ 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 (ffgcprll( 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 %.0f of input array of logicals (ffpcll).",
+ (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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 ngood = 0, nbad = 0, ii;
+ LONGLONG repeat, first, fstelm, fstrow;
+ int tcode;
+
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* first write the whole input vector, then go back and fill in the nulls */
+ if (ffpcll(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0)
+ return(*status);
+
+ /* 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 */
+
+/* good values have already been written
+ 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 */
+
+/* these have already been written
+ 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) */
+ LONGLONG 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'.
+*/
+{
+ LONGLONG offset, bstart, repeat, rowlen, elemnum, rstart, estart, tnull;
+ long fbyte, lbyte, nbyte, bitloc, ndone;
+ long ii, twidth, incre;
+ 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; ffgcprll will increment the value if */
+ /* we are writing to a variable length column. */
+ offset = (fptr->Fptr)->heapsize;
+
+ /* call ffgcprll 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 (ffgcprll( 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: ffgcprll 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. */
+ /* ffgcprll 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: ffgcprll 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/vendor/cfitsio/putcols.c b/vendor/cfitsio/putcols.c
new file mode 100644
index 00000000..86d624e9
--- /dev/null
+++ b/vendor/cfitsio/putcols.c
@@ -0,0 +1,303 @@
+/* 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ long ii, jj, ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull;
+ 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 (ffgcprll( fptr, colnum, firstrow, 1, nchar, 1, &scale, &zero,
+ tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre,
+ &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
+ return(*status);
+
+ /* simply move to write position, then write the string */
+ ffmbyt(fptr, startpos, IGNORE_EOF, status);
+ ffpbyt(fptr, nchar, array[0], status);
+
+ if (*status > 0) /* test for error during previous write operation */
+ {
+ sprintf(message,
+ "Error writing to variable length string column (ffpcls).");
+ ffpmsg(message);
+ }
+
+ return(*status);
+ }
+ else if (tcode == TSTRING)
+ {
+ if (ffgcprll( 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 string length is greater than a FITS block (2880 char) then must */
+ /* only write 1 string at a time, to force writein by ffpbyt instead of */
+ /* ffpbytoff (ffpbytoff can't handle this case) */
+ if (twidth > IOBUFLEN) {
+ maxelem = 1;
+ incre = twidth;
+ repeat = 1;
+ }
+
+ 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + (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 %.0f thru %.0f of input data array (ffpcls).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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, ngood = 0, nbad = 0, ii;
+ LONGLONG first, 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/vendor/cfitsio/putcolsb.c b/vendor/cfitsio/putcolsb.c
new file mode 100644
index 00000000..25ee5d1f
--- /dev/null
+++ b/vendor/cfitsio/putcolsb.c
@@ -0,0 +1,974 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffpprsb( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ fits_write_compressed_pixels(fptr, TSBYTE, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TSBYTE, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( 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 == 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpclsb).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpclsb(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpclsb(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpclsb(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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
+*/
+{
+ 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 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] = (float) (( ( (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;
+ char *cptr;
+
+ cptr = output;
+
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcolu.c b/vendor/cfitsio/putcolu.c
new file mode 100644
index 00000000..15840d8b
--- /dev/null
+++ b/vendor/cfitsio/putcolu.c
@@ -0,0 +1,629 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffppru( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ long twidth, incre;
+ long ii;
+ LONGLONG largeelem, nelem, tnull, i8null;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, ntodo;
+ 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;
+
+ largeelem = 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 */
+ largeelem = (largeelem - 1) * 2 + 1;
+ nelem *= 2;
+ }
+
+ if (ffgcprll( fptr, colnum, firstrow, largeelem, 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 = (unsigned char) tnull;
+ else if (tcode == TSHORT)
+ {
+ i2null = (short) tnull;
+#if BYTESWAPPED
+ ffswap2(&i2null, 1); /* reverse order of bytes */
+#endif
+ }
+ else if (tcode == TLONG)
+ {
+ i4null = (INT32BIT) tnull;
+#if BYTESWAPPED
+ ffswap4(&i4null, 1); /* reverse order of bytes */
+#endif
+ }
+ else
+ {
+ i8null = 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 + ((LONGLONG)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 %.0f thru %.0f of null values (ffpclu).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ long twidth, incre;
+ long ii;
+ LONGLONG tnull, i8null;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, ntodo;
+ 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);
+
+ /*---------------------------------------------------*/
+ /* 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 (ffgcprll( fptr, colnum, firstrow, firstelem, 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 = (unsigned char) tnull;
+ else if (tcode == TSHORT)
+ {
+ i2null = (short) tnull;
+#if BYTESWAPPED
+ ffswap2(&i2null, 1); /* reverse order of bytes */
+#endif
+ }
+ else if (tcode == TLONG)
+ {
+ i4null = (INT32BIT) tnull;
+#if BYTESWAPPED
+ ffswap4(&i4null, 1); /* reverse order of bytes */
+#endif
+ }
+ else
+ {
+ i8null = tnull;
+#if BYTESWAPPED
+ ffswap4( (INT32BIT*) &i8null, 2); /* 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 + ((LONGLONG)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 %.0f thru %.0f of null values (ffpclu).",
+ (double) (next+1), (double) (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 ffprwu(fitsfile *fptr,
+ LONGLONG firstrow,
+ LONGLONG nrows,
+ int *status)
+
+/*
+ * fits_write_nullrows / ffprwu - write TNULLs to all columns in one or more rows
+ *
+ * fitsfile *fptr - pointer to FITS HDU opened for read/write
+ * long int firstrow - first table row to set to null. (firstrow >= 1)
+ * long int nrows - total number or rows to set to null. (nrows >= 1)
+ * int *status - upon return, *status contains CFITSIO status code
+ *
+ * RETURNS: CFITSIO status code
+ *
+ * written by Craig Markwardt, GSFC
+ */
+{
+ LONGLONG ntotrows;
+ int ncols, i;
+ int typecode = 0;
+ LONGLONG repeat = 0, width = 0;
+ int nullstatus;
+
+ if (*status > 0) return *status;
+
+ if ((firstrow <= 0) || (nrows <= 0)) return (*status = BAD_ROW_NUM);
+
+ fits_get_num_rowsll(fptr, &ntotrows, status);
+
+ if (firstrow + nrows - 1 > ntotrows) return (*status = BAD_ROW_NUM);
+
+ fits_get_num_cols(fptr, &ncols, status);
+ if (*status) return *status;
+
+
+ /* Loop through each column and write nulls */
+ for (i=1; i <= ncols; i++) {
+ repeat = 0; typecode = 0; width = 0;
+ fits_get_coltypell(fptr, i, &typecode, &repeat, &width, status);
+ if (*status) break;
+
+ /* NOTE: data of TSTRING type must not write the total repeat
+ count, since the repeat count is the *character* count, not the
+ nstring count. Divide by string width to get number of
+ strings. */
+
+ if (typecode == TSTRING) repeat /= width;
+
+ /* Write NULLs */
+ nullstatus = 0;
+ fits_write_col_null(fptr, i, firstrow, 1, repeat*nrows, &nullstatus);
+
+ /* ignore error if no null value is defined for the column */
+ if (nullstatus && nullstatus != NO_NULL) return (*status = nullstatus);
+
+ }
+
+ return *status;
+}
+
diff --git a/vendor/cfitsio/putcolui.c b/vendor/cfitsio/putcolui.c
new file mode 100644
index 00000000..e52b176a
--- /dev/null
+++ b/vendor/cfitsio/putcolui.c
@@ -0,0 +1,969 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffpprui(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write (1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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 */
+
+ fits_write_compressed_pixels(fptr, TUSHORT, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TUSHORT, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( 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 == 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpclui).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpclui(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpclui(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpclui(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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
+*/
+{
+ 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 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] = (float) (((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;
+ char *cptr;
+
+ cptr = output;
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcoluj.c b/vendor/cfitsio/putcoluj.c
new file mode 100644
index 00000000..9f89f108
--- /dev/null
+++ b/vendor/cfitsio/putcoluj.c
@@ -0,0 +1,977 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffppruj( fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ fits_write_compressed_pixels(fptr, TULONG, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TULONG, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( 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 == 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpcluj).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpcluj(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpcluj(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpcluj(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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] = (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 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] = (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 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
+*/
+{
+ 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 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] = (float) ((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;
+ char *cptr;
+
+ cptr = output;
+
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putcoluk.c b/vendor/cfitsio/putcoluk.c
new file mode 100644
index 00000000..dd92fe39
--- /dev/null
+++ b/vendor/cfitsio/putcoluk.c
@@ -0,0 +1,993 @@
+/* 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"
+
+/*--------------------------------------------------------------------------*/
+int ffppruk(fitsfile *fptr, /* I - FITS file pointer */
+ long group, /* I - group to write(1 = 1st group) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ fits_write_compressed_pixels(fptr, TUINT, firstelem, 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) */
+ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */
+ LONGLONG 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 */
+
+ nullvalue = nulval; /* set local variable */
+ fits_write_compressed_pixels(fptr, TUINT, firstelem, 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG 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) */
+ LONGLONG ncols, /* I - number of pixels in each row of array */
+ LONGLONG nrows, /* I - number of rows in each plane of array */
+ LONGLONG naxis1, /* I - FITS image NAXIS1 value */
+ LONGLONG naxis2, /* I - FITS image NAXIS2 value */
+ LONGLONG 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, ii, jj;
+ long fpixel[3]= {1,1,1}, lpixel[3];
+ LONGLONG nfits, narray;
+ /*
+ 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] = (long) ncols;
+ lpixel[1] = (long) nrows;
+ lpixel[2] = (long) 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;
+ LONGLONG fpix[7], dimen[7], astart, pstart;
+ LONGLONG off2, off3, off4, off5, off6, off7;
+ LONGLONG st10, st20, st30, st40, st50, st60, st70;
+ LONGLONG st1, st2, st3, st4, st5, st6, st7;
+ long ii, i1, i2, i3, i4, i5, i6, i7, irange[7];
+
+ 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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ long ntodo;
+ LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull;
+ 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;
+
+ /*---------------------------------------------------*/
+ /* Check input and get parameters about the column: */
+ /*---------------------------------------------------*/
+ if (ffgcprll( 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 == 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 = (long) minvalue(remain, maxelem);
+ ntodo = (long) minvalue(ntodo, (repeat - elemnum));
+
+ wrtptr = startpos + ((LONGLONG)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 %.0f thru %.0f of input data array (ffpcluk).",
+ (double) (next+1), (double) (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) */
+ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */
+ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */
+ LONGLONG 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;
+ LONGLONG repeat, first, fstelm, fstrow;
+ 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 */
+
+ tcode = colptr->tdatatype;
+
+ if (tcode > 0)
+ repeat = colptr->trepeat; /* repeat count for this column */
+ else
+ repeat = firstelem -1 + nelem; /* variable length arrays */
+
+ /* if variable length array, first write the whole input vector,
+ then go back and fill in the nulls */
+ if (tcode < 0) {
+ if (ffpcluk(fptr, colnum, firstrow, firstelem, nelem, array, status) > 0) {
+ if (*status == NUM_OVERFLOW)
+ {
+ /* ignore overflows, which are possibly the null pixel values */
+ /* overflow = 1; */
+ *status = 0;
+ } else {
+ return(*status);
+ }
+ }
+ }
+
+ /* 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 (tcode > 0) { /* variable length arrays have already been written */
+ if (ffpcluk(fptr, colnum, fstrow, fstelm, 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 */
+
+ if (tcode > 0) { /* variable length arrays have already been written */
+ ffpcluk(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);
+ }
+
+ if (*status <= 0) {
+ if (overflow) {
+ *status = NUM_OVERFLOW;
+ }
+ }
+
+ 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
+*/
+{
+ 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 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] = (float) ((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;
+ char *cptr;
+
+ cptr = output;
+
+ 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;
+ }
+ }
+
+ /* replace any commas with periods (e.g., in French locale) */
+ while ((cptr = strchr(cptr, ','))) *cptr = '.';
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/putkey.c b/vendor/cfitsio/putkey.c
new file mode 100644
index 00000000..2a88096b
--- /dev/null
+++ b/vendor/cfitsio/putkey.c
@@ -0,0 +1,3085 @@
+/* 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 ffcrimll(fitsfile *fptr, /* I - FITS file pointer */
+ int bitpix, /* I - bits per pixel */
+ int naxis, /* I - number of axes in the array */
+ LONGLONG *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 */
+ ffphprll(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 */
+ LONGLONG 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 */
+ const char *extnm, /* I - value of EXTNAME keyword, if any */
+ int *status) /* IO - error status */
+/*
+ Create a table extension in a FITS file.
+*/
+{
+ LONGLONG naxis1 = 0;
+ long *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 */
+ 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 */
+ const char *keyname, /* I - name of keyword to write */
+ void *value, /* I - keyword value */
+ const 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, (LONGLONG) *(unsigned char *) value, comm, status);
+ }
+ else if (datatype == TSBYTE)
+ {
+ ffpkyj(fptr, keyname, (LONGLONG) *(signed char *) value, comm, status);
+ }
+ else if (datatype == TUSHORT)
+ {
+ ffpkyj(fptr, keyname, (LONGLONG) *(unsigned short *) value, comm, status);
+ }
+ else if (datatype == TSHORT)
+ {
+ ffpkyj(fptr, keyname, (LONGLONG) *(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, (LONGLONG) *(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, (LONGLONG) *(long *) value, comm, status);
+ }
+ else if (datatype == TLONGLONG)
+ {
+ ffpkyj(fptr, keyname, *(LONGLONG *) 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);
+
+ /* silently replace any illegal characters with a space */
+ for (ii=0; ii < len; ii++)
+ if (tcard[ii] < ' ' || tcard[ii] > 126) tcard[ii] = ' ';
+
+ 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 */
+
+/* no need to do this any more, since any illegal characters have been removed
+ 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 */
+ const char *keyname, /* I - name of keyword to write */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ char *value, /* I - keyword value */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ const char *value, /* I - keyword value */
+ const 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], tmpkeyname[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 */
+ }
+
+ strncpy(tmpkeyname, keyname, 80);
+ tmpkeyname[80] = '\0';
+
+ cptr = tmpkeyname;
+ 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 */
+ const char *keyname, /* I - name of keyword to write */
+ int value, /* I - keyword value */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ LONGLONG value, /* I - keyword value */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ float value, /* I - keyword value */
+ int decim, /* I - number of decimal places to display */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ float value, /* I - keyword value */
+ int decim, /* I - number of decimal places to display */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ double value, /* I - keyword value */
+ int decim, /* I - number of decimal places to display */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ double value, /* I - keyword value */
+ int decim, /* I - number of decimal places to display */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ float *value, /* I - keyword value (real, imaginary) */
+ int decim, /* I - number of decimal places to display */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ double *value, /* I - keyword value (real, imaginary) */
+ int decim, /* I - number of decimal places to display */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ float *value, /* I - keyword value (real, imaginary) */
+ int decim, /* I - number of decimal places to display */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ double *value, /* I - keyword value (real, imaginary) */
+ int decim, /* I - number of decimal places to display */
+ const 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 */
+ const char *keyname, /* I - name of keyword to write */
+ long intval, /* I - integer part of value */
+ double fraction, /* I - fractional part of value */
+ const 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 ffverifydate(int year, /* I - year (0 - 9999) */
+ int month, /* I - month (1 - 12) */
+ int day, /* I - day (1 - 31) */
+ int *status) /* IO - error status */
+/*
+ Verify that the date is valid
+*/
+{
+ int ndays[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
+ char errmsg[81];
+
+
+ if (year < 0 || year > 9999)
+ {
+ sprintf(errmsg,
+ "input year value = %d is out of range 0 - 9999", year);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ else if (month < 1 || month > 12)
+ {
+ sprintf(errmsg,
+ "input month value = %d is out of range 1 - 12", month);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+
+ if (ndays[month] == 31) {
+ if (day < 1 || day > 31)
+ {
+ sprintf(errmsg,
+ "input day value = %d is out of range 1 - 31 for month %d", day, month);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ } else if (ndays[month] == 30) {
+ if (day < 1 || day > 30)
+ {
+ sprintf(errmsg,
+ "input day value = %d is out of range 1 - 30 for month %d", day, month);
+ ffpmsg(errmsg);
+ return(*status = BAD_DATE);
+ }
+ } else {
+ if (day < 1 || day > 28)
+ {
+ if (day == 29)
+ {
+ /* year is a leap year if it is divisible by 4 but not by 100,
+ except years divisible by 400 are leap years
+ */
+ if ((year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0)
+ return (*status);
+
+ sprintf(errmsg,
+ "input day value = %d is out of range 1 - 28 for February %d (not leap year)", day, year);
+ ffpmsg(errmsg);
+ } else {
+ sprintf(errmsg,
+ "input day value = %d is out of range 1 - 28 (or 29) for February", day);
+ ffpmsg(errmsg);
+ }
+
+ return(*status = BAD_DATE);
+ }
+ }
+ 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
+*/
+{
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ *datestr = '\0';
+
+ if (ffverifydate(year, month, day, status) > 0)
+ {
+ ffpmsg("invalid date (ffdt2s)");
+ return(*status);
+ }
+
+ 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 day values
+*/
+{
+ int slen, lyear, lmonth, lday;
+
+ if (*status > 0) /* inherit input status value if > 0 */
+ return(*status);
+
+ if (year)
+ *year = 0;
+ if (month)
+ *month = 0;
+ if (day)
+ *day = 0;
+
+ 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" */
+ lyear = atoi(&datestr[6]) + 1900;
+ lmonth = atoi(&datestr[3]);
+ lday = atoi(datestr);
+
+ if (year)
+ *year = lyear;
+ if (month)
+ *month = lmonth;
+ if (day)
+ *day = lday;
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format (ffs2dt):");
+ 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 (ffs2dt):");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+ /* this is a new format string: "yyyy-mm-dd" */
+ lyear = atoi(datestr);
+ lmonth = atoi(&datestr[5]);
+ lday = atoi(&datestr[8]);
+
+ if (year)
+ *year = lyear;
+ if (month)
+ *month = lmonth;
+ if (day)
+ *day = lday;
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format (ffs2dt):");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+ }
+ else
+ {
+ ffpmsg("input date string has illegal format (ffs2dt):");
+ ffpmsg(datestr);
+ return(*status = BAD_DATE);
+ }
+
+
+ if (ffverifydate(lyear, lmonth, lday, status) > 0)
+ {
+ ffpmsg("invalid date (ffs2dt)");
+ }
+
+ 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);
+
+ *datestr='\0';
+
+ if (year != 0 || month != 0 || day !=0)
+ {
+ if (ffverifydate(year, month, day, status) > 0)
+ {
+ ffpmsg("invalid date (fftm2s)");
+ return(*status);
+ }
+ }
+
+ 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 (year)
+ *year = 0;
+ if (month)
+ *month = 0;
+ if (day)
+ *day = 0;
+ if (hour)
+ *hour = 0;
+ if (minute)
+ *minute = 0;
+ if (second)
+ *second = 0.;
+
+ if (!datestr)
+ {
+ ffpmsg("error: null input date string (ffs2tm)");
+ return(*status = BAD_DATE); /* Null datestr pointer ??? */
+ }
+
+ 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 (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 */
+ const 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 */
+ const 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 */
+ const 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 ffpknjj( fitsfile *fptr, /* I - FITS file pointer */
+ const char *keyroot, /* I - root name of keywords to write */
+ int nstart, /* I - starting index number */
+ int nkey, /* I - number of keywords to write */
+ LONGLONG *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 */
+ const 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 */
+ const 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 */
+ const 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 */
+ const 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 ffptdmll( fitsfile *fptr, /* I - FITS file pointer */
+ int colnum, /* I - column number */
+ int naxis, /* I - number of axes in the data array */
+ LONGLONG 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;
+ LONGLONG 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);
+ }
+
+ /* cast to double because the 64-bit int conversion character in */
+ /* sprintf is platform dependent ( %lld, %ld, %I64d ) */
+
+ sprintf(value, "%.0f", (double) 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 ( 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 */
+ ffbnfmll(value, NULL, &repeat, NULL, status); /* parse the repeat count */
+
+ if (*status > 0 || repeat != totalpix)
+ {
+ sprintf(message,
+ "column vector length, %.0f, does not equal TDIMn array size, %.0f",
+ (double) (colptr->trepeat), (double) 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 ffphpsll( 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 */
+ LONGLONG 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 */
+ LONGLONG pcount = 0; /* number of group parameters (usually 0) */
+ LONGLONG gcount = 1; /* number of random groups (usually 1 or 0) */
+ int extend = 1; /* may FITS file have extensions? */
+
+ ffphprll(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 */
+ LONGLONG pcount, /* I - number of group parameters (usually 0) */
+ LONGLONG 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;
+ LONGLONG naxesll[20];
+
+ for (ii = 0; (ii < naxis) && (ii < 20); ii++)
+ naxesll[ii] = naxes[ii];
+
+ ffphprll(fptr, simple, bitpix, naxis, naxesll, pcount, gcount,
+ extend, status);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffphprll( 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 */
+ LONGLONG naxes[], /* I - length of each data axis */
+ LONGLONG pcount, /* I - number of group parameters (usually 0) */
+ LONGLONG 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, tnaxes[20];
+ 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 )
+ {
+
+ for (ii = 0; ii < naxis; ii++)
+ tnaxes[ii] = (long) naxes[ii];
+
+ /* write header for a compressed image */
+ imcomp_init_table(fptr, bitpix, naxis, tnaxes, 1, 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 3 special cases that represent unsigned integers */
+ if (longbitpix == USHORT_IMG)
+ longbitpix = SHORT_IMG;
+ else if (longbitpix == ULONG_IMG)
+ longbitpix = LONG_IMG;
+ else if (longbitpix == SBYTE_IMG)
+ longbitpix = BYTE_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 negative value for NAXIS%d keyword: %.0f", ii + 1, (double) (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", 0, comm, status);
+
+ strcpy(comm, "required keyword; must = 1");
+ ffpkyj(fptr, "GCOUNT", 1, 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);
+ }
+ else if (bitpix == SBYTE_IMG)
+ {
+ strcpy(comm, "offset data range to that of signed byte");
+ ffpkyg(fptr, "BZERO", -128., 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 */
+ LONGLONG naxis1, /* I - width of row in the table */
+ LONGLONG 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 */
+ const char *extnmx, /* 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; /* must be 'long' because it is passed to ffgabc */
+ char tfmt[30], name[FLEN_KEYWORD], comm[FLEN_COMMENT], extnm[FLEN_VALUE];
+
+ 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);
+
+ extnm[0] = '\0';
+ if (extnmx)
+ strncat(extnm, extnmx, FLEN_VALUE-1);
+
+ rowlen = (long) 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[ii] && *(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 */
+ LONGLONG 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 */
+ const char *extnmx, /* I - value of EXTNAME keyword, if any */
+ LONGLONG 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;
+ LONGLONG naxis1;
+
+ char tfmt[30], name[FLEN_KEYWORD], comm[FLEN_COMMENT], extnm[FLEN_VALUE];
+ 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);
+
+ extnm[0] = '\0';
+ if (extnmx)
+ strncat(extnm, extnmx, FLEN_VALUE-1);
+
+ 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 if (tform[ii][0] == 'P' || tform[ii][1] == 'P')
+ /* this is a 'P' variable length descriptor (neg. datatype) */
+ naxis1 += 8;
+ else
+ /* this is a 'Q' variable length descriptor (neg. datatype) */
+ naxis1 += 16;
+
+ 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[ii] && *(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 ffphext(fitsfile *fptr, /* I - FITS file pointer */
+ const char *xtensionx, /* I - value for the XTENSION keyword */
+ int bitpix, /* I - value for the BIXPIX keyword */
+ int naxis, /* I - value for the NAXIS keyword */
+ long naxes[], /* I - value for the NAXISn keywords */
+ LONGLONG pcount, /* I - value for the PCOUNT keyword */
+ LONGLONG gcount, /* I - value for the GCOUNT keyword */
+ int *status) /* IO - error status */
+/*
+ Put required Header keywords into a conforming extension:
+*/
+{
+ char message[FLEN_ERRMSG],comm[81], name[20], xtension[FLEN_VALUE];
+ int ii;
+
+ 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);
+
+ if (naxis < 0 || naxis > 999)
+ {
+ sprintf(message,
+ "Illegal value for NAXIS keyword: %d", naxis);
+ ffpmsg(message);
+ return(*status = BAD_NAXIS);
+ }
+
+ xtension[0] = '\0';
+ strncat(xtension, xtensionx, FLEN_VALUE-1);
+
+ ffpkys(fptr, "XTENSION", xtension, "extension type", status);
+ ffpkyj(fptr, "BITPIX", bitpix, "number of bits per data pixel", status);
+ ffpkyj(fptr, "NAXIS", naxis, "number of data axes", status);
+
+ strcpy(comm, "length of data axis ");
+ for (ii = 0; ii < naxis; ii++)
+ {
+ if (naxes[ii] < 0)
+ {
+ sprintf(message,
+ "Illegal negative value for NAXIS%d keyword: %.0f", ii + 1, (double) (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);
+ }
+
+
+ ffpkyj(fptr, "PCOUNT", pcount, " ", status);
+ ffpkyj(fptr, "GCOUNT", gcount, " ", status);
+
+ if (*status > 0)
+ ffpmsg("Failed to write extension header keywords (ffphext)");
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int ffi2c(LONGLONG 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 defined(_MSC_VER)
+ /* Microsoft Visual C++ 6.0 uses '%I64d' syntax for 8-byte integers */
+ if (sprintf(cval, "%I64d", ival) < 0)
+
+#elif (USE_LL_SUFFIX == 1)
+ if (sprintf(cval, "%lld", ival) < 0)
+#else
+ if (sprintf(cval, "%ld", ival) < 0)
+#endif
+ {
+ 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
+*/
+{
+ char *cptr;
+
+ 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;
+ }
+
+ /* replace comma with a period (e.g. in French locale) */
+ if ( (cptr = strchr(cval, ','))) *cptr = '.';
+
+ /* 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
+*/
+{
+ char *cptr;
+
+ 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)
+ {
+ /* replace comma with a period (e.g. in French locale) */
+ if ( (cptr = strchr(cval, ','))) *cptr = '.';
+
+ /* 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
+*/
+{
+ char *cptr;
+
+ 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;
+ }
+
+ /* replace comma with a period (e.g. in French locale) */
+ if ( (cptr = strchr(cval, ','))) *cptr = '.';
+
+ /* 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.
+*/
+{
+ char *cptr;
+
+ 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)
+ {
+ /* replace comma with a period (e.g. in French locale) */
+ if ( (cptr = strchr(cval, ','))) *cptr = '.';
+
+ /* 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/vendor/cfitsio/quantize.c b/vendor/cfitsio/quantize.c
new file mode 100644
index 00000000..8fe6acca
--- /dev/null
+++ b/vendor/cfitsio/quantize.c
@@ -0,0 +1,3888 @@
+/*
+ The following code is based on algorithms written by Richard White at STScI and made
+ available for use in CFITSIO in July 1999 and updated in January 2008.
+*/
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <math.h>
+# include <limits.h>
+# include <float.h>
+
+#include "fitsio2.h"
+
+/* nearest integer function */
+# define NINT(x) ((x >= 0.) ? (int) (x + 0.5) : (int) (x - 0.5))
+
+#define NULL_VALUE -2147483647 /* value used to represent undefined pixels */
+#define N_RESERVED_VALUES 10 /* 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 */
+ /* If lossy Hcompression is used, and the */
+ /* array contains null values, then it is also */
+ /* possible for the compressed values to slightly */
+ /* exceed the range of the actual (lossless) values */
+ /* so we must reserve a little more space */
+
+/* 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 int FnMeanSigma_short(short *array, long npix, int nullcheck,
+ short nullvalue, long *ngoodpix, double *mean, double *sigma, int *status);
+static int FnMeanSigma_int(int *array, long npix, int nullcheck,
+ int nullvalue, long *ngoodpix, double *mean, double *sigma, int *status);
+static int FnMeanSigma_float(float *array, long npix, int nullcheck,
+ float nullvalue, long *ngoodpix, double *mean, double *sigma, int *status);
+static int FnMeanSigma_double(double *array, long npix, int nullcheck,
+ double nullvalue, long *ngoodpix, double *mean, double *sigma, int *status);
+
+static int FnNoise5_short(short *array, long nx, long ny, int nullcheck,
+ short nullvalue, long *ngood, short *minval, short *maxval,
+ double *n2, double *n3, double *n5, int *status);
+static int FnNoise5_int(int *array, long nx, long ny, int nullcheck,
+ int nullvalue, long *ngood, int *minval, int *maxval,
+ double *n2, double *n3, double *n5, int *status);
+static int FnNoise5_float(float *array, long nx, long ny, int nullcheck,
+ float nullvalue, long *ngood, float *minval, float *maxval,
+ double *n2, double *n3, double *n5, int *status);
+static int FnNoise5_double(double *array, long nx, long ny, int nullcheck,
+ double nullvalue, long *ngood, double *minval, double *maxval,
+ double *n2, double *n3, double *n5, int *status);
+
+static int FnNoise3_short(short *array, long nx, long ny, int nullcheck,
+ short nullvalue, long *ngood, short *minval, short *maxval, double *noise, int *status);
+static int FnNoise3_int(int *array, long nx, long ny, int nullcheck,
+ int nullvalue, long *ngood, int *minval, int *maxval, double *noise, int *status);
+static int FnNoise3_float(float *array, long nx, long ny, int nullcheck,
+ float nullvalue, long *ngood, float *minval, float *maxval, double *noise, int *status);
+static int FnNoise3_double(double *array, long nx, long ny, int nullcheck,
+ double nullvalue, long *ngood, double *minval, double *maxval, double *noise, int *status);
+
+static int FnNoise1_short(short *array, long nx, long ny,
+ int nullcheck, short nullvalue, double *noise, int *status);
+static int FnNoise1_int(int *array, long nx, long ny,
+ int nullcheck, int nullvalue, double *noise, int *status);
+static int FnNoise1_float(float *array, long nx, long ny,
+ int nullcheck, float nullvalue, double *noise, int *status);
+static int FnNoise1_double(double *array, long nx, long ny,
+ int nullcheck, double nullvalue, double *noise, int *status);
+
+static int FnCompare_short (const void *, const void *);
+static int FnCompare_int (const void *, const void *);
+static int FnCompare_float (const void *, const void *);
+static int FnCompare_double (const void *, const void *);
+static float quick_select_float(float arr[], int n);
+static short quick_select_short(short arr[], int n);
+static int quick_select_int(int arr[], int n);
+static LONGLONG quick_select_longlong(LONGLONG arr[], int n);
+static double quick_select_double(double arr[], int n);
+
+/*---------------------------------------------------------------------------*/
+int fits_quantize_float (long row, float fdata[], long nxpix, long nypix, int nullcheck,
+ float in_null_value, float qlevel, int idata[], double *bscale,
+ double *bzero, int *iminval, int *imaxval) {
+
+/* arguments:
+long row i: if positive, tile number = row number in the binary table
+ (this is only used when dithering the quantized values)
+float fdata[] i: array of image pixels to be compressed
+long nxpix i: number of pixels in each row of fdata
+long nypix i: number of rows in fdata
+nullcheck i: check for nullvalues in fdata?
+float in_null_value i: value used to represent undefined pixels in fdata
+float qlevel i: quantization level
+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.
+*/
+
+ int status, anynulls = 0, iseed;
+ long i, nx, ngood = 0;
+ double stdev, noise2, noise3, noise5; /* MAD 2nd, 3rd, and 5th order noise values */
+ float minval = 0., maxval = 0.; /* min & max of fdata */
+ double delta; /* bscale, 1 in idata = delta in fdata */
+ double zeropt; /* bzero */
+ double temp;
+ int nextrand = 0;
+ extern float *fits_rand_value; /* this is defined in imcompress.c */
+ LONGLONG iqfactor;
+
+ nx = nxpix * nypix;
+ if (nx <= 1) {
+ *bscale = 1.;
+ *bzero = 0.;
+ return (0);
+ }
+
+ if (qlevel >= 0.) {
+
+ /* estimate background noise using MAD pixel differences */
+ FnNoise5_float(fdata, nxpix, nypix, nullcheck, in_null_value, &ngood,
+ &minval, &maxval, &noise2, &noise3, &noise5, &status);
+
+ if (nullcheck && ngood == 0) { /* special case of an image filled with Nulls */
+ /* set parameters to dummy values, which are not used */
+ minval = 0.;
+ maxval = 1.;
+ stdev = 1;
+ } else {
+
+ /* use the minimum of noise2, noise3, and noise5 as the best noise value */
+ stdev = noise3;
+ if (noise2 != 0. && noise2 < stdev) stdev = noise2;
+ if (noise5 != 0. && noise5 < stdev) stdev = noise5;
+ }
+
+ if (qlevel == 0.)
+ delta = stdev / 4.; /* default quantization */
+ else
+ delta = stdev / qlevel;
+
+ if (delta == 0.)
+ return (0); /* don't quantize */
+
+ } else {
+ /* negative value represents the absolute quantization level */
+ delta = -qlevel;
+
+ /* only nned to calculate the min and max values */
+ FnNoise3_float(fdata, nxpix, nypix, nullcheck, in_null_value, &ngood,
+ &minval, &maxval, 0, &status);
+ }
+
+ /* 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 (row > 0) { /* we need to dither the quantized values */
+ if (!fits_rand_value)
+ if (fits_init_randoms()) return(MEMORY_ALLOCATION);
+
+ /* initialize the index to the next random number in the list */
+ iseed = (int) ((row - 1) % N_RANDOM);
+ nextrand = (int) (fits_rand_value[iseed] * 500.);
+ }
+
+ if (ngood == nx) { /* 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;
+ /* fudge the zero point so it is an integer multiple of delta */
+ /* This helps to ensure the same scaling will be performed if the */
+ /* file undergoes multiple fpack/funpack cycles */
+ iqfactor = (LONGLONG) (zeropt/delta + 0.5);
+ zeropt = iqfactor * delta;
+ }
+ else
+ {
+ /* center the quantized levels around zero */
+ zeropt = (minval + maxval) / 2.;
+ }
+
+ if (row > 0) { /* dither the values when quantizing */
+ for (i = 0; i < nx; i++) {
+
+ idata[i] = NINT((((double) fdata[i] - zeropt) / delta) + fits_rand_value[nextrand] - 0.5);
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ } else { /* do not dither the values */
+
+ for (i = 0; i < nx; i++) {
+ idata[i] = NINT ((fdata[i] - zeropt) / delta);
+ }
+ }
+ }
+ 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);
+
+ if (row > 0) { /* dither the values */
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ idata[i] = NINT((((double) fdata[i] - zeropt) / delta) + fits_rand_value[nextrand] - 0.5);
+ } else {
+ idata[i] = NULL_VALUE;
+ }
+
+ /* increment the random number index, regardless */
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ if (iseed == N_RANDOM) iseed = 0;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ } else { /* do not dither the values */
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] != in_null_value)
+ idata[i] = NINT((fdata[i] - zeropt) / delta);
+ 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 (long row, double fdata[], long nxpix, long nypix, int nullcheck,
+ double in_null_value, float qlevel, int idata[], double *bscale,
+ double *bzero, int *iminval, int *imaxval) {
+
+/* arguments:
+long row i: tile number = row number in the binary table
+double fdata[] i: array of image pixels to be compressed
+long nxpix i: number of pixels in each row of fdata
+long nypix i: number of rows in fdata
+nullcheck i: check for nullvalues in fdata?
+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 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.
+*/
+
+ int status, anynulls = 0, iseed;
+ long i, nx, ngood = 0;
+ double stdev, noise2, noise3, noise5; /* MAD 2nd, 3rd, and 5th order noise values */
+ double minval = 0., maxval = 0.; /* min & max of fdata */
+ double delta; /* bscale, 1 in idata = delta in fdata */
+ double zeropt; /* bzero */
+ double temp;
+ int nextrand = 0;
+ extern float *fits_rand_value;
+ LONGLONG iqfactor;
+
+ nx = nxpix * nypix;
+ if (nx <= 1) {
+ *bscale = 1.;
+ *bzero = 0.;
+ return (0);
+ }
+
+ if (qlevel >= 0.) {
+
+ /* estimate background noise using MAD pixel differences */
+ FnNoise5_double(fdata, nxpix, nypix, nullcheck, in_null_value, &ngood,
+ &minval, &maxval, &noise2, &noise3, &noise5, &status);
+
+ if (nullcheck && ngood == 0) { /* special case of an image filled with Nulls */
+ /* set parameters to dummy values, which are not used */
+ minval = 0.;
+ maxval = 1.;
+ stdev = 1;
+ } else {
+
+ /* use the minimum of noise2, noise3, and noise5 as the best noise value */
+ stdev = noise3;
+ if (noise2 != 0. && noise2 < stdev) stdev = noise2;
+ if (noise5 != 0. && noise5 < stdev) stdev = noise5;
+ }
+
+ if (qlevel == 0.)
+ delta = stdev / 4.; /* default quantization */
+ else
+ delta = stdev / qlevel;
+
+ if (delta == 0.)
+ return (0); /* don't quantize */
+
+ } else {
+ /* negative value represents the absolute quantization level */
+ delta = -qlevel;
+
+ /* only nned to calculate the min and max values */
+ FnNoise3_double(fdata, nxpix, nypix, nullcheck, in_null_value, &ngood,
+ &minval, &maxval, 0, &status);
+ }
+
+ /* 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 (row > 0) { /* we need to dither the quantized values */
+ if (!fits_rand_value)
+ if (fits_init_randoms()) return(MEMORY_ALLOCATION);
+
+ /* initialize the index to the next random number in the list */
+ iseed = (int) ((row - 1) % N_RANDOM);
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+
+ if (ngood == nx) { /* 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;
+ /* fudge the zero point so it is an integer multiple of delta */
+ /* This helps to ensure the same scaling will be performed if the */
+ /* file undergoes multiple fpack/funpack cycles */
+ iqfactor = (LONGLONG) (zeropt/delta + 0.5);
+ zeropt = iqfactor * delta;
+ }
+ else
+ {
+ /* center the quantized levels around zero */
+ zeropt = (minval + maxval) / 2.;
+ }
+
+ if (row > 0) { /* dither the values when quantizing */
+ for (i = 0; i < nx; i++) {
+
+ idata[i] = NINT((((double) fdata[i] - zeropt) / delta) + fits_rand_value[nextrand] - 0.5);
+
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ } else { /* do not dither the values */
+
+ for (i = 0; i < nx; i++) {
+ idata[i] = NINT ((fdata[i] - zeropt) / delta);
+ }
+ }
+ }
+ 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);
+
+ if (row > 0) { /* dither the values */
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] != in_null_value) {
+ idata[i] = NINT((((double) fdata[i] - zeropt) / delta) + fits_rand_value[nextrand] - 0.5);
+ } else {
+ idata[i] = NULL_VALUE;
+ }
+
+ /* increment the random number index, regardless */
+ nextrand++;
+ if (nextrand == N_RANDOM) {
+ iseed++;
+ nextrand = (int) (fits_rand_value[iseed] * 500);
+ }
+ }
+ } else { /* do not dither the values */
+ for (i = 0; i < nx; i++) {
+ if (fdata[i] != in_null_value)
+ idata[i] = NINT((fdata[i] - zeropt) / delta);
+ 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_img_stats_short(short *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ /* (if this is a 3D image, then ny should be the */
+ /* product of the no. of rows times the no. of planes) */
+ int nullcheck, /* check for null values, if true */
+ short nullvalue, /* value of null pixels, if nullcheck is true */
+
+ /* returned parameters (if the pointer is not null) */
+ long *ngoodpix, /* number of non-null pixels in the image */
+ short *minvalue, /* returned minimum non-null value in the array */
+ short *maxvalue, /* returned maximum non-null value in the array */
+ double *mean, /* returned mean value of all non-null pixels */
+ double *sigma, /* returned R.M.S. value of all non-null pixels */
+ double *noise1, /* 1st order estimate of noise in image background level */
+ double *noise2, /* 2nd order estimate of noise in image background level */
+ double *noise3, /* 3rd order estimate of noise in image background level */
+ double *noise5, /* 5th order estimate of noise in image background level */
+ int *status) /* error status */
+
+/*
+ Compute statistics of the input short integer image.
+*/
+{
+ long ngood;
+ short minval, maxval;
+ double xmean = 0., xsigma = 0., xnoise = 0., xnoise2 = 0., xnoise3 = 0., xnoise5 = 0.;
+
+ /* need to calculate mean and/or sigma and/or limits? */
+ if (mean || sigma ) {
+ FnMeanSigma_short(array, nx * ny, nullcheck, nullvalue,
+ &ngood, &xmean, &xsigma, status);
+
+ if (ngoodpix) *ngoodpix = ngood;
+ if (mean) *mean = xmean;
+ if (sigma) *sigma = xsigma;
+ }
+
+ if (noise1) {
+ FnNoise1_short(array, nx, ny, nullcheck, nullvalue,
+ &xnoise, status);
+
+ *noise1 = xnoise;
+ }
+
+ if (minvalue || maxvalue || noise3) {
+ FnNoise5_short(array, nx, ny, nullcheck, nullvalue,
+ &ngood, &minval, &maxval, &xnoise2, &xnoise3, &xnoise5, status);
+
+ if (ngoodpix) *ngoodpix = ngood;
+ if (minvalue) *minvalue= minval;
+ if (maxvalue) *maxvalue = maxval;
+ if (noise2) *noise2 = xnoise2;
+ if (noise3) *noise3 = xnoise3;
+ if (noise5) *noise5 = xnoise5;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_img_stats_int(int *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ /* (if this is a 3D image, then ny should be the */
+ /* product of the no. of rows times the no. of planes) */
+ int nullcheck, /* check for null values, if true */
+ int nullvalue, /* value of null pixels, if nullcheck is true */
+
+ /* returned parameters (if the pointer is not null) */
+ long *ngoodpix, /* number of non-null pixels in the image */
+ int *minvalue, /* returned minimum non-null value in the array */
+ int *maxvalue, /* returned maximum non-null value in the array */
+ double *mean, /* returned mean value of all non-null pixels */
+ double *sigma, /* returned R.M.S. value of all non-null pixels */
+ double *noise1, /* 1st order estimate of noise in image background level */
+ double *noise2, /* 2nd order estimate of noise in image background level */
+ double *noise3, /* 3rd order estimate of noise in image background level */
+ double *noise5, /* 5th order estimate of noise in image background level */
+ int *status) /* error status */
+
+/*
+ Compute statistics of the input integer image.
+*/
+{
+ long ngood;
+ int minval, maxval;
+ double xmean = 0., xsigma = 0., xnoise = 0., xnoise2 = 0., xnoise3 = 0., xnoise5 = 0.;
+
+ /* need to calculate mean and/or sigma and/or limits? */
+ if (mean || sigma ) {
+ FnMeanSigma_int(array, nx * ny, nullcheck, nullvalue,
+ &ngood, &xmean, &xsigma, status);
+
+ if (ngoodpix) *ngoodpix = ngood;
+ if (mean) *mean = xmean;
+ if (sigma) *sigma = xsigma;
+ }
+
+ if (noise1) {
+ FnNoise1_int(array, nx, ny, nullcheck, nullvalue,
+ &xnoise, status);
+
+ *noise1 = xnoise;
+ }
+
+ if (minvalue || maxvalue || noise3) {
+ FnNoise5_int(array, nx, ny, nullcheck, nullvalue,
+ &ngood, &minval, &maxval, &xnoise2, &xnoise3, &xnoise5, status);
+
+ if (ngoodpix) *ngoodpix = ngood;
+ if (minvalue) *minvalue= minval;
+ if (maxvalue) *maxvalue = maxval;
+ if (noise2) *noise2 = xnoise2;
+ if (noise3) *noise3 = xnoise3;
+ if (noise5) *noise5 = xnoise5;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+int fits_img_stats_float(float *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ /* (if this is a 3D image, then ny should be the */
+ /* product of the no. of rows times the no. of planes) */
+ int nullcheck, /* check for null values, if true */
+ float nullvalue, /* value of null pixels, if nullcheck is true */
+
+ /* returned parameters (if the pointer is not null) */
+ long *ngoodpix, /* number of non-null pixels in the image */
+ float *minvalue, /* returned minimum non-null value in the array */
+ float *maxvalue, /* returned maximum non-null value in the array */
+ double *mean, /* returned mean value of all non-null pixels */
+ double *sigma, /* returned R.M.S. value of all non-null pixels */
+ double *noise1, /* 1st order estimate of noise in image background level */
+ double *noise2, /* 2nd order estimate of noise in image background level */
+ double *noise3, /* 3rd order estimate of noise in image background level */
+ double *noise5, /* 5th order estimate of noise in image background level */
+ int *status) /* error status */
+
+/*
+ Compute statistics of the input float image.
+*/
+{
+ long ngood;
+ float minval, maxval;
+ double xmean = 0., xsigma = 0., xnoise = 0., xnoise2 = 0., xnoise3 = 0., xnoise5 = 0.;
+
+ /* need to calculate mean and/or sigma and/or limits? */
+ if (mean || sigma ) {
+ FnMeanSigma_float(array, nx * ny, nullcheck, nullvalue,
+ &ngood, &xmean, &xsigma, status);
+
+ if (ngoodpix) *ngoodpix = ngood;
+ if (mean) *mean = xmean;
+ if (sigma) *sigma = xsigma;
+ }
+
+ if (noise1) {
+ FnNoise1_float(array, nx, ny, nullcheck, nullvalue,
+ &xnoise, status);
+
+ *noise1 = xnoise;
+ }
+
+ if (minvalue || maxvalue || noise3) {
+ FnNoise5_float(array, nx, ny, nullcheck, nullvalue,
+ &ngood, &minval, &maxval, &xnoise2, &xnoise3, &xnoise5, status);
+
+ if (ngoodpix) *ngoodpix = ngood;
+ if (minvalue) *minvalue= minval;
+ if (maxvalue) *maxvalue = maxval;
+ if (noise2) *noise2 = xnoise2;
+ if (noise3) *noise3 = xnoise3;
+ if (noise5) *noise5 = xnoise5;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnMeanSigma_short
+ (short *array, /* 2 dimensional array of image pixels */
+ long npix, /* number of pixels in the image */
+ int nullcheck, /* check for null values, if true */
+ short nullvalue, /* value of null pixels, if nullcheck is true */
+
+ /* returned parameters */
+
+ long *ngoodpix, /* number of non-null pixels in the image */
+ double *mean, /* returned mean value of all non-null pixels */
+ double *sigma, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Compute mean and RMS sigma of the non-null pixels in the input array.
+*/
+{
+ long ii, ngood = 0;
+ short *value;
+ double sum = 0., sum2 = 0., xtemp;
+
+ value = array;
+
+ if (nullcheck) {
+ for (ii = 0; ii < npix; ii++, value++) {
+ if (*value != nullvalue) {
+ ngood++;
+ xtemp = (double) *value;
+ sum += xtemp;
+ sum2 += (xtemp * xtemp);
+ }
+ }
+ } else {
+ ngood = npix;
+ for (ii = 0; ii < npix; ii++, value++) {
+ xtemp = (double) *value;
+ sum += xtemp;
+ sum2 += (xtemp * xtemp);
+ }
+ }
+
+ if (ngood > 1) {
+ if (ngoodpix) *ngoodpix = ngood;
+ xtemp = sum / ngood;
+ if (mean) *mean = xtemp;
+ if (sigma) *sigma = sqrt((sum2 / ngood) - (xtemp * xtemp));
+ } else if (ngood == 1){
+ if (ngoodpix) *ngoodpix = 1;
+ if (mean) *mean = sum;
+ if (sigma) *sigma = 0.0;
+ } else {
+ if (ngoodpix) *ngoodpix = 0;
+ if (mean) *mean = 0.;
+ if (sigma) *sigma = 0.;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnMeanSigma_int
+ (int *array, /* 2 dimensional array of image pixels */
+ long npix, /* number of pixels in the image */
+ int nullcheck, /* check for null values, if true */
+ int nullvalue, /* value of null pixels, if nullcheck is true */
+
+ /* returned parameters */
+
+ long *ngoodpix, /* number of non-null pixels in the image */
+ double *mean, /* returned mean value of all non-null pixels */
+ double *sigma, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Compute mean and RMS sigma of the non-null pixels in the input array.
+*/
+{
+ long ii, ngood = 0;
+ int *value;
+ double sum = 0., sum2 = 0., xtemp;
+
+ value = array;
+
+ if (nullcheck) {
+ for (ii = 0; ii < npix; ii++, value++) {
+ if (*value != nullvalue) {
+ ngood++;
+ xtemp = (double) *value;
+ sum += xtemp;
+ sum2 += (xtemp * xtemp);
+ }
+ }
+ } else {
+ ngood = npix;
+ for (ii = 0; ii < npix; ii++, value++) {
+ xtemp = (double) *value;
+ sum += xtemp;
+ sum2 += (xtemp * xtemp);
+ }
+ }
+
+ if (ngood > 1) {
+ if (ngoodpix) *ngoodpix = ngood;
+ xtemp = sum / ngood;
+ if (mean) *mean = xtemp;
+ if (sigma) *sigma = sqrt((sum2 / ngood) - (xtemp * xtemp));
+ } else if (ngood == 1){
+ if (ngoodpix) *ngoodpix = 1;
+ if (mean) *mean = sum;
+ if (sigma) *sigma = 0.0;
+ } else {
+ if (ngoodpix) *ngoodpix = 0;
+ if (mean) *mean = 0.;
+ if (sigma) *sigma = 0.;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnMeanSigma_float
+ (float *array, /* 2 dimensional array of image pixels */
+ long npix, /* number of pixels in the image */
+ int nullcheck, /* check for null values, if true */
+ float nullvalue, /* value of null pixels, if nullcheck is true */
+
+ /* returned parameters */
+
+ long *ngoodpix, /* number of non-null pixels in the image */
+ double *mean, /* returned mean value of all non-null pixels */
+ double *sigma, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Compute mean and RMS sigma of the non-null pixels in the input array.
+*/
+{
+ long ii, ngood = 0;
+ float *value;
+ double sum = 0., sum2 = 0., xtemp;
+
+ value = array;
+
+ if (nullcheck) {
+ for (ii = 0; ii < npix; ii++, value++) {
+ if (*value != nullvalue) {
+ ngood++;
+ xtemp = (double) *value;
+ sum += xtemp;
+ sum2 += (xtemp * xtemp);
+ }
+ }
+ } else {
+ ngood = npix;
+ for (ii = 0; ii < npix; ii++, value++) {
+ xtemp = (double) *value;
+ sum += xtemp;
+ sum2 += (xtemp * xtemp);
+ }
+ }
+
+ if (ngood > 1) {
+ if (ngoodpix) *ngoodpix = ngood;
+ xtemp = sum / ngood;
+ if (mean) *mean = xtemp;
+ if (sigma) *sigma = sqrt((sum2 / ngood) - (xtemp * xtemp));
+ } else if (ngood == 1){
+ if (ngoodpix) *ngoodpix = 1;
+ if (mean) *mean = sum;
+ if (sigma) *sigma = 0.0;
+ } else {
+ if (ngoodpix) *ngoodpix = 0;
+ if (mean) *mean = 0.;
+ if (sigma) *sigma = 0.;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnMeanSigma_double
+ (double *array, /* 2 dimensional array of image pixels */
+ long npix, /* number of pixels in the image */
+ int nullcheck, /* check for null values, if true */
+ double nullvalue, /* value of null pixels, if nullcheck is true */
+
+ /* returned parameters */
+
+ long *ngoodpix, /* number of non-null pixels in the image */
+ double *mean, /* returned mean value of all non-null pixels */
+ double *sigma, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Compute mean and RMS sigma of the non-null pixels in the input array.
+*/
+{
+ long ii, ngood = 0;
+ double *value;
+ double sum = 0., sum2 = 0., xtemp;
+
+ value = array;
+
+ if (nullcheck) {
+ for (ii = 0; ii < npix; ii++, value++) {
+ if (*value != nullvalue) {
+ ngood++;
+ xtemp = *value;
+ sum += xtemp;
+ sum2 += (xtemp * xtemp);
+ }
+ }
+ } else {
+ ngood = npix;
+ for (ii = 0; ii < npix; ii++, value++) {
+ xtemp = *value;
+ sum += xtemp;
+ sum2 += (xtemp * xtemp);
+ }
+ }
+
+ if (ngood > 1) {
+ if (ngoodpix) *ngoodpix = ngood;
+ xtemp = sum / ngood;
+ if (mean) *mean = xtemp;
+ if (sigma) *sigma = sqrt((sum2 / ngood) - (xtemp * xtemp));
+ } else if (ngood == 1){
+ if (ngoodpix) *ngoodpix = 1;
+ if (mean) *mean = sum;
+ if (sigma) *sigma = 0.0;
+ } else {
+ if (ngoodpix) *ngoodpix = 0;
+ if (mean) *mean = 0.;
+ if (sigma) *sigma = 0.;
+ }
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise5_short
+ (short *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ short nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ long *ngood, /* number of good, non-null pixels? */
+ short *minval, /* minimum non-null value */
+ short *maxval, /* maximum non-null value */
+ double *noise2, /* returned 2nd order MAD of all non-null pixels */
+ double *noise3, /* returned 3rd order MAD of all non-null pixels */
+ double *noise5, /* returned 5th order MAD of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Estimate the median and background noise in the input image using 2nd, 3rd and 5th
+order Median Absolute Differences.
+
+The noise in the background of the image is calculated using the MAD algorithms
+developed for deriving the signal to noise ratio in spectra
+(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/)
+
+3rd order: noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2)))
+
+The returned estimates are the median of the values that are computed for each
+row of the image.
+*/
+{
+ long ii, jj, nrows = 0, nrows2 = 0, nvals, nvals2, ngoodpix = 0;
+ int *differences2, *differences3, *differences5;
+ short *rowpix, v1, v2, v3, v4, v5, v6, v7, v8, v9;
+ short xminval = SHRT_MAX, xmaxval = SHRT_MIN;
+ int do_range = 0;
+ double *diffs2, *diffs3, *diffs5;
+ double xnoise2 = 0, xnoise3 = 0, xnoise5 = 0;
+
+ if (nx < 5) {
+ /* treat entire array as an image with a single row */
+ nx = nx * ny;
+ ny = 1;
+ }
+
+ /* rows must have at least 9 pixels */
+ if (nx < 9) {
+
+ for (ii = 0; ii < nx; ii++) {
+ if (nullcheck && array[ii] == nullvalue)
+ continue;
+ else {
+ if (array[ii] < xminval) xminval = array[ii];
+ if (array[ii] > xmaxval) xmaxval = array[ii];
+ ngoodpix++;
+ }
+ }
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (ngood) *ngood = ngoodpix;
+ if (noise2) *noise2 = 0.;
+ if (noise3) *noise3 = 0.;
+ if (noise5) *noise5 = 0.;
+ return(*status);
+ }
+
+ /* do we need to compute the min and max value? */
+ if (minval || maxval) do_range = 1;
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences2 = calloc(nx, sizeof(int));
+ if (!differences2) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ differences3 = calloc(nx, sizeof(int));
+ if (!differences3) {
+ free(differences2);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ differences5 = calloc(nx, sizeof(int));
+ if (!differences5) {
+ free(differences2);
+ free(differences3);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs2 = calloc(ny, sizeof(double));
+ if (!diffs2) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs3 = calloc(ny, sizeof(double));
+ if (!diffs3) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ free(diffs2);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs5 = calloc(ny, sizeof(double));
+ if (!diffs5) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ free(diffs2);
+ free(diffs3);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v1 < xminval) xminval = v1;
+ if (v1 > xmaxval) xmaxval = v1;
+ }
+
+ /***** find the 2nd valid pixel in row (which we will skip over) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v2 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v2 < xminval) xminval = v2;
+ if (v2 > xmaxval) xmaxval = v2;
+ }
+
+ /***** find the 3rd valid pixel in row */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v3 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v3 < xminval) xminval = v3;
+ if (v3 > xmaxval) xmaxval = v3;
+ }
+
+ /* find the 4nd valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v4 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v4 < xminval) xminval = v4;
+ if (v4 > xmaxval) xmaxval = v4;
+ }
+
+ /* find the 5th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v5 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v5 < xminval) xminval = v5;
+ if (v5 > xmaxval) xmaxval = v5;
+ }
+
+ /* find the 6th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v6 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v6 < xminval) xminval = v6;
+ if (v6 > xmaxval) xmaxval = v6;
+ }
+
+ /* find the 7th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v7 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v7 < xminval) xminval = v7;
+ if (v7 > xmaxval) xmaxval = v7;
+ }
+
+ /* find the 8th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v8 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v8 < xminval) xminval = v8;
+ if (v8 > xmaxval) xmaxval = v8;
+ }
+ /* now populate the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ nvals2 = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+ v9 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v9 < xminval) xminval = v9;
+ if (v9 > xmaxval) xmaxval = v9;
+ }
+
+ /* construct array of absolute differences */
+
+ if (!(v5 == v6 && v6 == v7) ) {
+ differences2[nvals2] = abs((int) v5 - (int) v7);
+ nvals2++;
+ }
+
+ if (!(v3 == v4 && v4 == v5 && v5 == v6 && v6 == v7) ) {
+ differences3[nvals] = abs((2 * (int) v5) - (int) v3 - (int) v7);
+ differences5[nvals] = abs((6 * (int) v5) - (4 * (int) v3) - (4 * (int) v7) + (int) v1 + (int) v9);
+ nvals++;
+ } else {
+ /* ignore constant background regions */
+ ngoodpix++;
+ }
+
+ /* shift over 1 pixel */
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = v5;
+ v5 = v6;
+ v6 = v7;
+ v7 = v8;
+ v8 = v9;
+ } /* end of loop over pixels in the row */
+
+ /* compute the median diffs */
+ /* Note that there are 8 more pixel values than there are diffs values. */
+ ngoodpix += (nvals + 8);
+
+ if (nvals == 0) {
+ continue; /* cannot compute medians on this row */
+ } else if (nvals == 1) {
+ if (nvals2 == 1) {
+ diffs2[nrows2] = differences2[0];
+ nrows2++;
+ }
+
+ diffs3[nrows] = differences3[0];
+ diffs5[nrows] = differences5[0];
+ } else {
+ /* quick_select returns the median MUCH faster than using qsort */
+ if (nvals2 > 1) {
+ diffs2[nrows2] = quick_select_int(differences2, nvals);
+ nrows2++;
+ }
+
+ diffs3[nrows] = quick_select_int(differences3, nvals);
+ diffs5[nrows] = quick_select_int(differences5, nvals);
+ }
+
+ nrows++;
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise3 = 0;
+ xnoise5 = 0;
+ } else if (nrows == 1) {
+ xnoise3 = diffs3[0];
+ xnoise5 = diffs5[0];
+ } else {
+ qsort(diffs3, nrows, sizeof(double), FnCompare_double);
+ qsort(diffs5, nrows, sizeof(double), FnCompare_double);
+ xnoise3 = (diffs3[(nrows - 1)/2] + diffs3[nrows/2]) / 2.;
+ xnoise5 = (diffs5[(nrows - 1)/2] + diffs5[nrows/2]) / 2.;
+ }
+
+ if (nrows2 == 0) {
+ xnoise2 = 0;
+ } else if (nrows2 == 1) {
+ xnoise2 = diffs2[0];
+ } else {
+ qsort(diffs2, nrows2, sizeof(double), FnCompare_double);
+ xnoise2 = (diffs2[(nrows2 - 1)/2] + diffs2[nrows2/2]) / 2.;
+ }
+
+ if (ngood) *ngood = ngoodpix;
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (noise2) *noise2 = 1.0483579 * xnoise2;
+ if (noise3) *noise3 = 0.6052697 * xnoise3;
+ if (noise5) *noise5 = 0.1772048 * xnoise5;
+
+ free(diffs5);
+ free(diffs3);
+ free(diffs2);
+ free(differences5);
+ free(differences3);
+ free(differences2);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise5_int
+ (int *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ int nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ long *ngood, /* number of good, non-null pixels? */
+ int *minval, /* minimum non-null value */
+ int *maxval, /* maximum non-null value */
+ double *noise2, /* returned 2nd order MAD of all non-null pixels */
+ double *noise3, /* returned 3rd order MAD of all non-null pixels */
+ double *noise5, /* returned 5th order MAD of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Estimate the median and background noise in the input image using 2nd, 3rd and 5th
+order Median Absolute Differences.
+
+The noise in the background of the image is calculated using the MAD algorithms
+developed for deriving the signal to noise ratio in spectra
+(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/)
+
+3rd order: noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2)))
+
+The returned estimates are the median of the values that are computed for each
+row of the image.
+*/
+{
+ long ii, jj, nrows = 0, nrows2 = 0, nvals, nvals2, ngoodpix = 0;
+ LONGLONG *differences2, *differences3, *differences5, tdiff;
+ int *rowpix, v1, v2, v3, v4, v5, v6, v7, v8, v9;
+ int xminval = INT_MAX, xmaxval = INT_MIN;
+ int do_range = 0;
+ double *diffs2, *diffs3, *diffs5;
+ double xnoise2 = 0, xnoise3 = 0, xnoise5 = 0;
+
+ if (nx < 5) {
+ /* treat entire array as an image with a single row */
+ nx = nx * ny;
+ ny = 1;
+ }
+
+ /* rows must have at least 9 pixels */
+ if (nx < 9) {
+
+ for (ii = 0; ii < nx; ii++) {
+ if (nullcheck && array[ii] == nullvalue)
+ continue;
+ else {
+ if (array[ii] < xminval) xminval = array[ii];
+ if (array[ii] > xmaxval) xmaxval = array[ii];
+ ngoodpix++;
+ }
+ }
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (ngood) *ngood = ngoodpix;
+ if (noise2) *noise2 = 0.;
+ if (noise3) *noise3 = 0.;
+ if (noise5) *noise5 = 0.;
+ return(*status);
+ }
+
+ /* do we need to compute the min and max value? */
+ if (minval || maxval) do_range = 1;
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences2 = calloc(nx, sizeof(LONGLONG));
+ if (!differences2) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ differences3 = calloc(nx, sizeof(LONGLONG));
+ if (!differences3) {
+ free(differences2);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ differences5 = calloc(nx, sizeof(LONGLONG));
+ if (!differences5) {
+ free(differences2);
+ free(differences3);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs2 = calloc(ny, sizeof(double));
+ if (!diffs2) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs3 = calloc(ny, sizeof(double));
+ if (!diffs3) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ free(diffs2);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs5 = calloc(ny, sizeof(double));
+ if (!diffs5) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ free(diffs2);
+ free(diffs3);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v1 < xminval) xminval = v1;
+ if (v1 > xmaxval) xmaxval = v1;
+ }
+
+ /***** find the 2nd valid pixel in row (which we will skip over) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v2 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v2 < xminval) xminval = v2;
+ if (v2 > xmaxval) xmaxval = v2;
+ }
+
+ /***** find the 3rd valid pixel in row */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v3 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v3 < xminval) xminval = v3;
+ if (v3 > xmaxval) xmaxval = v3;
+ }
+
+ /* find the 4nd valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v4 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v4 < xminval) xminval = v4;
+ if (v4 > xmaxval) xmaxval = v4;
+ }
+
+ /* find the 5th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v5 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v5 < xminval) xminval = v5;
+ if (v5 > xmaxval) xmaxval = v5;
+ }
+
+ /* find the 6th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v6 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v6 < xminval) xminval = v6;
+ if (v6 > xmaxval) xmaxval = v6;
+ }
+
+ /* find the 7th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v7 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v7 < xminval) xminval = v7;
+ if (v7 > xmaxval) xmaxval = v7;
+ }
+
+ /* find the 8th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v8 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v8 < xminval) xminval = v8;
+ if (v8 > xmaxval) xmaxval = v8;
+ }
+ /* now populate the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ nvals2 = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+ v9 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v9 < xminval) xminval = v9;
+ if (v9 > xmaxval) xmaxval = v9;
+ }
+
+ /* construct array of absolute differences */
+
+ if (!(v5 == v6 && v6 == v7) ) {
+ tdiff = (LONGLONG) v5 - (LONGLONG) v7;
+ if (tdiff < 0)
+ differences2[nvals2] = -1 * tdiff;
+ else
+ differences2[nvals2] = tdiff;
+
+ nvals2++;
+ }
+
+ if (!(v3 == v4 && v4 == v5 && v5 == v6 && v6 == v7) ) {
+ tdiff = (2 * (LONGLONG) v5) - (LONGLONG) v3 - (LONGLONG) v7;
+ if (tdiff < 0)
+ differences3[nvals] = -1 * tdiff;
+ else
+ differences3[nvals] = tdiff;
+
+ tdiff = (6 * (LONGLONG) v5) - (4 * (LONGLONG) v3) - (4 * (LONGLONG) v7) + (LONGLONG) v1 + (LONGLONG) v9;
+ if (tdiff < 0)
+ differences5[nvals] = -1 * tdiff;
+ else
+ differences5[nvals] = tdiff;
+
+ nvals++;
+ } else {
+ /* ignore constant background regions */
+ ngoodpix++;
+ }
+
+ /* shift over 1 pixel */
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = v5;
+ v5 = v6;
+ v6 = v7;
+ v7 = v8;
+ v8 = v9;
+ } /* end of loop over pixels in the row */
+
+ /* compute the median diffs */
+ /* Note that there are 8 more pixel values than there are diffs values. */
+ ngoodpix += (nvals + 8);
+
+ if (nvals == 0) {
+ continue; /* cannot compute medians on this row */
+ } else if (nvals == 1) {
+ if (nvals2 == 1) {
+ diffs2[nrows2] = (double) differences2[0];
+ nrows2++;
+ }
+
+ diffs3[nrows] = (double) differences3[0];
+ diffs5[nrows] = (double) differences5[0];
+ } else {
+ /* quick_select returns the median MUCH faster than using qsort */
+ if (nvals2 > 1) {
+ diffs2[nrows2] = (double) quick_select_longlong(differences2, nvals);
+ nrows2++;
+ }
+
+ diffs3[nrows] = (double) quick_select_longlong(differences3, nvals);
+ diffs5[nrows] = (double) quick_select_longlong(differences5, nvals);
+ }
+
+ nrows++;
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise3 = 0;
+ xnoise5 = 0;
+ } else if (nrows == 1) {
+ xnoise3 = diffs3[0];
+ xnoise5 = diffs5[0];
+ } else {
+ qsort(diffs3, nrows, sizeof(double), FnCompare_double);
+ qsort(diffs5, nrows, sizeof(double), FnCompare_double);
+ xnoise3 = (diffs3[(nrows - 1)/2] + diffs3[nrows/2]) / 2.;
+ xnoise5 = (diffs5[(nrows - 1)/2] + diffs5[nrows/2]) / 2.;
+ }
+
+ if (nrows2 == 0) {
+ xnoise2 = 0;
+ } else if (nrows2 == 1) {
+ xnoise2 = diffs2[0];
+ } else {
+ qsort(diffs2, nrows2, sizeof(double), FnCompare_double);
+ xnoise2 = (diffs2[(nrows2 - 1)/2] + diffs2[nrows2/2]) / 2.;
+ }
+
+ if (ngood) *ngood = ngoodpix;
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (noise2) *noise2 = 1.0483579 * xnoise2;
+ if (noise3) *noise3 = 0.6052697 * xnoise3;
+ if (noise5) *noise5 = 0.1772048 * xnoise5;
+
+ free(diffs5);
+ free(diffs3);
+ free(diffs2);
+ free(differences5);
+ free(differences3);
+ free(differences2);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise5_float
+ (float *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ float nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ long *ngood, /* number of good, non-null pixels? */
+ float *minval, /* minimum non-null value */
+ float *maxval, /* maximum non-null value */
+ double *noise2, /* returned 2nd order MAD of all non-null pixels */
+ double *noise3, /* returned 3rd order MAD of all non-null pixels */
+ double *noise5, /* returned 5th order MAD of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Estimate the median and background noise in the input image using 2nd, 3rd and 5th
+order Median Absolute Differences.
+
+The noise in the background of the image is calculated using the MAD algorithms
+developed for deriving the signal to noise ratio in spectra
+(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/)
+
+3rd order: noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2)))
+
+The returned estimates are the median of the values that are computed for each
+row of the image.
+*/
+{
+ long ii, jj, nrows = 0, nrows2 = 0, nvals, nvals2, ngoodpix = 0;
+ float *differences2, *differences3, *differences5;
+ float *rowpix, v1, v2, v3, v4, v5, v6, v7, v8, v9;
+ float xminval = FLT_MAX, xmaxval = -FLT_MAX;
+ int do_range = 0;
+ double *diffs2, *diffs3, *diffs5;
+ double xnoise2 = 0, xnoise3 = 0, xnoise5 = 0;
+
+ if (nx < 5) {
+ /* treat entire array as an image with a single row */
+ nx = nx * ny;
+ ny = 1;
+ }
+
+ /* rows must have at least 9 pixels */
+ if (nx < 9) {
+
+ for (ii = 0; ii < nx; ii++) {
+ if (nullcheck && array[ii] == nullvalue)
+ continue;
+ else {
+ if (array[ii] < xminval) xminval = array[ii];
+ if (array[ii] > xmaxval) xmaxval = array[ii];
+ ngoodpix++;
+ }
+ }
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (ngood) *ngood = ngoodpix;
+ if (noise2) *noise2 = 0.;
+ if (noise3) *noise3 = 0.;
+ if (noise5) *noise5 = 0.;
+ return(*status);
+ }
+
+ /* do we need to compute the min and max value? */
+ if (minval || maxval) do_range = 1;
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences2 = calloc(nx, sizeof(float));
+ if (!differences2) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ differences3 = calloc(nx, sizeof(float));
+ if (!differences3) {
+ free(differences2);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ differences5 = calloc(nx, sizeof(float));
+ if (!differences5) {
+ free(differences2);
+ free(differences3);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs2 = calloc(ny, sizeof(double));
+ if (!diffs2) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs3 = calloc(ny, sizeof(double));
+ if (!diffs3) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ free(diffs2);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs5 = calloc(ny, sizeof(double));
+ if (!diffs5) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ free(diffs2);
+ free(diffs3);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v1 < xminval) xminval = v1;
+ if (v1 > xmaxval) xmaxval = v1;
+ }
+
+ /***** find the 2nd valid pixel in row (which we will skip over) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v2 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v2 < xminval) xminval = v2;
+ if (v2 > xmaxval) xmaxval = v2;
+ }
+
+ /***** find the 3rd valid pixel in row */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v3 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v3 < xminval) xminval = v3;
+ if (v3 > xmaxval) xmaxval = v3;
+ }
+
+ /* find the 4nd valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v4 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v4 < xminval) xminval = v4;
+ if (v4 > xmaxval) xmaxval = v4;
+ }
+
+ /* find the 5th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v5 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v5 < xminval) xminval = v5;
+ if (v5 > xmaxval) xmaxval = v5;
+ }
+
+ /* find the 6th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v6 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v6 < xminval) xminval = v6;
+ if (v6 > xmaxval) xmaxval = v6;
+ }
+
+ /* find the 7th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v7 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v7 < xminval) xminval = v7;
+ if (v7 > xmaxval) xmaxval = v7;
+ }
+
+ /* find the 8th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v8 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v8 < xminval) xminval = v8;
+ if (v8 > xmaxval) xmaxval = v8;
+ }
+ /* now populate the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ nvals2 = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+ v9 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v9 < xminval) xminval = v9;
+ if (v9 > xmaxval) xmaxval = v9;
+ }
+
+ /* construct array of absolute differences */
+
+ if (!(v5 == v6 && v6 == v7) ) {
+ differences2[nvals2] = (float) fabs(v5 - v7);
+ nvals2++;
+ }
+
+ if (!(v3 == v4 && v4 == v5 && v5 == v6 && v6 == v7) ) {
+ differences3[nvals] = (float) fabs((2 * v5) - v3 - v7);
+ differences5[nvals] = (float) fabs((6 * v5) - (4 * v3) - (4 * v7) + v1 + v9);
+ nvals++;
+ } else {
+ /* ignore constant background regions */
+ ngoodpix++;
+ }
+
+ /* shift over 1 pixel */
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = v5;
+ v5 = v6;
+ v6 = v7;
+ v7 = v8;
+ v8 = v9;
+ } /* end of loop over pixels in the row */
+
+ /* compute the median diffs */
+ /* Note that there are 8 more pixel values than there are diffs values. */
+ ngoodpix += (nvals + 8);
+
+ if (nvals == 0) {
+ continue; /* cannot compute medians on this row */
+ } else if (nvals == 1) {
+ if (nvals2 == 1) {
+ diffs2[nrows2] = differences2[0];
+ nrows2++;
+ }
+
+ diffs3[nrows] = differences3[0];
+ diffs5[nrows] = differences5[0];
+ } else {
+ /* quick_select returns the median MUCH faster than using qsort */
+ if (nvals2 > 1) {
+ diffs2[nrows2] = quick_select_float(differences2, nvals);
+ nrows2++;
+ }
+
+ diffs3[nrows] = quick_select_float(differences3, nvals);
+ diffs5[nrows] = quick_select_float(differences5, nvals);
+ }
+
+ nrows++;
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise3 = 0;
+ xnoise5 = 0;
+ } else if (nrows == 1) {
+ xnoise3 = diffs3[0];
+ xnoise5 = diffs5[0];
+ } else {
+ qsort(diffs3, nrows, sizeof(double), FnCompare_double);
+ qsort(diffs5, nrows, sizeof(double), FnCompare_double);
+ xnoise3 = (diffs3[(nrows - 1)/2] + diffs3[nrows/2]) / 2.;
+ xnoise5 = (diffs5[(nrows - 1)/2] + diffs5[nrows/2]) / 2.;
+ }
+
+ if (nrows2 == 0) {
+ xnoise2 = 0;
+ } else if (nrows2 == 1) {
+ xnoise2 = diffs2[0];
+ } else {
+ qsort(diffs2, nrows2, sizeof(double), FnCompare_double);
+ xnoise2 = (diffs2[(nrows2 - 1)/2] + diffs2[nrows2/2]) / 2.;
+ }
+
+ if (ngood) *ngood = ngoodpix;
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (noise2) *noise2 = 1.0483579 * xnoise2;
+ if (noise3) *noise3 = 0.6052697 * xnoise3;
+ if (noise5) *noise5 = 0.1772048 * xnoise5;
+
+ free(diffs5);
+ free(diffs3);
+ free(diffs2);
+ free(differences5);
+ free(differences3);
+ free(differences2);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise5_double
+ (double *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ double nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ long *ngood, /* number of good, non-null pixels? */
+ double *minval, /* minimum non-null value */
+ double *maxval, /* maximum non-null value */
+ double *noise2, /* returned 2nd order MAD of all non-null pixels */
+ double *noise3, /* returned 3rd order MAD of all non-null pixels */
+ double *noise5, /* returned 5th order MAD of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Estimate the median and background noise in the input image using 2nd, 3rd and 5th
+order Median Absolute Differences.
+
+The noise in the background of the image is calculated using the MAD algorithms
+developed for deriving the signal to noise ratio in spectra
+(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/)
+
+3rd order: noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2)))
+
+The returned estimates are the median of the values that are computed for each
+row of the image.
+*/
+{
+ long ii, jj, nrows = 0, nrows2 = 0, nvals, nvals2, ngoodpix = 0;
+ double *differences2, *differences3, *differences5;
+ double *rowpix, v1, v2, v3, v4, v5, v6, v7, v8, v9;
+ double xminval = DBL_MAX, xmaxval = -DBL_MAX;
+ int do_range = 0;
+ double *diffs2, *diffs3, *diffs5;
+ double xnoise2 = 0, xnoise3 = 0, xnoise5 = 0;
+
+ if (nx < 5) {
+ /* treat entire array as an image with a single row */
+ nx = nx * ny;
+ ny = 1;
+ }
+
+ /* rows must have at least 9 pixels */
+ if (nx < 9) {
+
+ for (ii = 0; ii < nx; ii++) {
+ if (nullcheck && array[ii] == nullvalue)
+ continue;
+ else {
+ if (array[ii] < xminval) xminval = array[ii];
+ if (array[ii] > xmaxval) xmaxval = array[ii];
+ ngoodpix++;
+ }
+ }
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (ngood) *ngood = ngoodpix;
+ if (noise2) *noise2 = 0.;
+ if (noise3) *noise3 = 0.;
+ if (noise5) *noise5 = 0.;
+ return(*status);
+ }
+
+ /* do we need to compute the min and max value? */
+ if (minval || maxval) do_range = 1;
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences2 = calloc(nx, sizeof(double));
+ if (!differences2) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ differences3 = calloc(nx, sizeof(double));
+ if (!differences3) {
+ free(differences2);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ differences5 = calloc(nx, sizeof(double));
+ if (!differences5) {
+ free(differences2);
+ free(differences3);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs2 = calloc(ny, sizeof(double));
+ if (!diffs2) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs3 = calloc(ny, sizeof(double));
+ if (!diffs3) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ free(diffs2);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs5 = calloc(ny, sizeof(double));
+ if (!diffs5) {
+ free(differences2);
+ free(differences3);
+ free(differences5);
+ free(diffs2);
+ free(diffs3);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v1 < xminval) xminval = v1;
+ if (v1 > xmaxval) xmaxval = v1;
+ }
+
+ /***** find the 2nd valid pixel in row (which we will skip over) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v2 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v2 < xminval) xminval = v2;
+ if (v2 > xmaxval) xmaxval = v2;
+ }
+
+ /***** find the 3rd valid pixel in row */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v3 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v3 < xminval) xminval = v3;
+ if (v3 > xmaxval) xmaxval = v3;
+ }
+
+ /* find the 4nd valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v4 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v4 < xminval) xminval = v4;
+ if (v4 > xmaxval) xmaxval = v4;
+ }
+
+ /* find the 5th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v5 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v5 < xminval) xminval = v5;
+ if (v5 > xmaxval) xmaxval = v5;
+ }
+
+ /* find the 6th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v6 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v6 < xminval) xminval = v6;
+ if (v6 > xmaxval) xmaxval = v6;
+ }
+
+ /* find the 7th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v7 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v7 < xminval) xminval = v7;
+ if (v7 > xmaxval) xmaxval = v7;
+ }
+
+ /* find the 8th valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v8 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v8 < xminval) xminval = v8;
+ if (v8 > xmaxval) xmaxval = v8;
+ }
+ /* now populate the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ nvals2 = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+ v9 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v9 < xminval) xminval = v9;
+ if (v9 > xmaxval) xmaxval = v9;
+ }
+
+ /* construct array of absolute differences */
+
+ if (!(v5 == v6 && v6 == v7) ) {
+ differences2[nvals2] = fabs(v5 - v7);
+ nvals2++;
+ }
+
+ if (!(v3 == v4 && v4 == v5 && v5 == v6 && v6 == v7) ) {
+ differences3[nvals] = fabs((2 * v5) - v3 - v7);
+ differences5[nvals] = fabs((6 * v5) - (4 * v3) - (4 * v7) + v1 + v9);
+ nvals++;
+ } else {
+ /* ignore constant background regions */
+ ngoodpix++;
+ }
+
+ /* shift over 1 pixel */
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = v5;
+ v5 = v6;
+ v6 = v7;
+ v7 = v8;
+ v8 = v9;
+ } /* end of loop over pixels in the row */
+
+ /* compute the median diffs */
+ /* Note that there are 8 more pixel values than there are diffs values. */
+ ngoodpix += (nvals + 8);
+
+ if (nvals == 0) {
+ continue; /* cannot compute medians on this row */
+ } else if (nvals == 1) {
+ if (nvals2 == 1) {
+ diffs2[nrows2] = differences2[0];
+ nrows2++;
+ }
+
+ diffs3[nrows] = differences3[0];
+ diffs5[nrows] = differences5[0];
+ } else {
+ /* quick_select returns the median MUCH faster than using qsort */
+ if (nvals2 > 1) {
+ diffs2[nrows2] = quick_select_double(differences2, nvals);
+ nrows2++;
+ }
+
+ diffs3[nrows] = quick_select_double(differences3, nvals);
+ diffs5[nrows] = quick_select_double(differences5, nvals);
+ }
+
+ nrows++;
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise3 = 0;
+ xnoise5 = 0;
+ } else if (nrows == 1) {
+ xnoise3 = diffs3[0];
+ xnoise5 = diffs5[0];
+ } else {
+ qsort(diffs3, nrows, sizeof(double), FnCompare_double);
+ qsort(diffs5, nrows, sizeof(double), FnCompare_double);
+ xnoise3 = (diffs3[(nrows - 1)/2] + diffs3[nrows/2]) / 2.;
+ xnoise5 = (diffs5[(nrows - 1)/2] + diffs5[nrows/2]) / 2.;
+ }
+
+ if (nrows2 == 0) {
+ xnoise2 = 0;
+ } else if (nrows2 == 1) {
+ xnoise2 = diffs2[0];
+ } else {
+ qsort(diffs2, nrows2, sizeof(double), FnCompare_double);
+ xnoise2 = (diffs2[(nrows2 - 1)/2] + diffs2[nrows2/2]) / 2.;
+ }
+
+ if (ngood) *ngood = ngoodpix;
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (noise2) *noise2 = 1.0483579 * xnoise2;
+ if (noise3) *noise3 = 0.6052697 * xnoise3;
+ if (noise5) *noise5 = 0.1772048 * xnoise5;
+
+ free(diffs5);
+ free(diffs3);
+ free(diffs2);
+ free(differences5);
+ free(differences3);
+ free(differences2);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise3_short
+ (short *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ short nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ long *ngood, /* number of good, non-null pixels? */
+ short *minval, /* minimum non-null value */
+ short *maxval, /* maximum non-null value */
+ double *noise, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Estimate the median and background noise in the input image using 3rd order differences.
+
+The noise in the background of the image is calculated using the 3rd order algorithm
+developed for deriving the signal to noise ratio in spectra
+(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/)
+
+ noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2)))
+
+The returned estimates are the median of the values that are computed for each
+row of the image.
+*/
+{
+ long ii, jj, nrows = 0, nvals, ngoodpix = 0;
+ short *differences, *rowpix, v1, v2, v3, v4, v5;
+ short xminval = SHRT_MAX, xmaxval = SHRT_MIN, do_range = 0;
+ double *diffs, xnoise = 0, sigma;
+
+ if (nx < 5) {
+ /* treat entire array as an image with a single row */
+ nx = nx * ny;
+ ny = 1;
+ }
+
+ /* rows must have at least 5 pixels */
+ if (nx < 5) {
+
+ for (ii = 0; ii < nx; ii++) {
+ if (nullcheck && array[ii] == nullvalue)
+ continue;
+ else {
+ if (array[ii] < xminval) xminval = array[ii];
+ if (array[ii] > xmaxval) xmaxval = array[ii];
+ ngoodpix++;
+ }
+ }
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (ngood) *ngood = ngoodpix;
+ if (noise) *noise = 0.;
+ return(*status);
+ }
+
+ /* do we need to compute the min and max value? */
+ if (minval || maxval) do_range = 1;
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences = calloc(nx, sizeof(short));
+ if (!differences) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs = calloc(ny, sizeof(double));
+ if (!diffs) {
+ free(differences);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v1 < xminval) xminval = v1;
+ if (v1 > xmaxval) xmaxval = v1;
+ }
+
+ /***** find the 2nd valid pixel in row (which we will skip over) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v2 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v2 < xminval) xminval = v2;
+ if (v2 > xmaxval) xmaxval = v2;
+ }
+
+ /***** find the 3rd valid pixel in row */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v3 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v3 < xminval) xminval = v3;
+ if (v3 > xmaxval) xmaxval = v3;
+ }
+
+ /* find the 4nd valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v4 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v4 < xminval) xminval = v4;
+ if (v4 > xmaxval) xmaxval = v4;
+ }
+
+ /* now populate the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+ v5 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v5 < xminval) xminval = v5;
+ if (v5 > xmaxval) xmaxval = v5;
+ }
+
+ /* construct array of 3rd order absolute differences */
+ if (!(v1 == v2 && v2 == v3 && v3 == v4 && v4 == v5)) {
+ differences[nvals] = abs((2 * v3) - v1 - v5);
+ nvals++;
+ } else {
+ /* ignore constant background regions */
+ ngoodpix++;
+ }
+
+
+ /* shift over 1 pixel */
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = v5;
+ } /* end of loop over pixels in the row */
+
+ /* compute the 3rd order diffs */
+ /* Note that there are 4 more pixel values than there are diffs values. */
+ ngoodpix += (nvals + 4);
+
+ if (nvals == 0) {
+ continue; /* cannot compute medians on this row */
+ } else if (nvals == 1) {
+ diffs[nrows] = differences[0];
+ } else {
+ /* quick_select returns the median MUCH faster than using qsort */
+ diffs[nrows] = quick_select_short(differences, nvals);
+ }
+
+ nrows++;
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise = 0;
+ } else if (nrows == 1) {
+ xnoise = diffs[0];
+ } else {
+
+
+ qsort(diffs, nrows, sizeof(double), FnCompare_double);
+ xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.;
+
+ FnMeanSigma_double(diffs, nrows, 0, 0.0, 0, &xnoise, &sigma, status);
+
+ /* do a 4.5 sigma rejection of outliers */
+ jj = 0;
+ sigma = 4.5 * sigma;
+ for (ii = 0; ii < nrows; ii++) {
+ if ( fabs(diffs[ii] - xnoise) <= sigma) {
+ if (jj != ii)
+ diffs[jj] = diffs[ii];
+ jj++;
+ }
+ }
+ if (ii != jj)
+ FnMeanSigma_double(diffs, jj, 0, 0.0, 0, &xnoise, &sigma, status);
+ }
+
+ if (ngood) *ngood = ngoodpix;
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (noise) *noise = 0.6052697 * xnoise;
+
+ free(diffs);
+ free(differences);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise3_int
+ (int *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ int nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ long *ngood, /* number of good, non-null pixels? */
+ int *minval, /* minimum non-null value */
+ int *maxval, /* maximum non-null value */
+ double *noise, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Estimate the background noise in the input image using 3rd order differences.
+
+The noise in the background of the image is calculated using the 3rd order algorithm
+developed for deriving the signal to noise ratio in spectra
+(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/)
+
+ noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2)))
+
+The returned estimates are the median of the values that are computed for each
+row of the image.
+*/
+{
+ long ii, jj, nrows = 0, nvals, ngoodpix = 0;
+ int *differences, *rowpix, v1, v2, v3, v4, v5;
+ int xminval = INT_MAX, xmaxval = INT_MIN, do_range = 0;
+ double *diffs, xnoise = 0, sigma;
+
+ if (nx < 5) {
+ /* treat entire array as an image with a single row */
+ nx = nx * ny;
+ ny = 1;
+ }
+
+ /* rows must have at least 5 pixels */
+ if (nx < 5) {
+
+ for (ii = 0; ii < nx; ii++) {
+ if (nullcheck && array[ii] == nullvalue)
+ continue;
+ else {
+ if (array[ii] < xminval) xminval = array[ii];
+ if (array[ii] > xmaxval) xmaxval = array[ii];
+ ngoodpix++;
+ }
+ }
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (ngood) *ngood = ngoodpix;
+ if (noise) *noise = 0.;
+ return(*status);
+ }
+
+ /* do we need to compute the min and max value? */
+ if (minval || maxval) do_range = 1;
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences = calloc(nx, sizeof(int));
+ if (!differences) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs = calloc(ny, sizeof(double));
+ if (!diffs) {
+ free(differences);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v1 < xminval) xminval = v1;
+ if (v1 > xmaxval) xmaxval = v1;
+ }
+
+ /***** find the 2nd valid pixel in row (which we will skip over) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v2 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v2 < xminval) xminval = v2;
+ if (v2 > xmaxval) xmaxval = v2;
+ }
+
+ /***** find the 3rd valid pixel in row */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v3 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v3 < xminval) xminval = v3;
+ if (v3 > xmaxval) xmaxval = v3;
+ }
+
+ /* find the 4nd valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v4 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v4 < xminval) xminval = v4;
+ if (v4 > xmaxval) xmaxval = v4;
+ }
+
+ /* now populate the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+ v5 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v5 < xminval) xminval = v5;
+ if (v5 > xmaxval) xmaxval = v5;
+ }
+
+ /* construct array of 3rd order absolute differences */
+ if (!(v1 == v2 && v2 == v3 && v3 == v4 && v4 == v5)) {
+ differences[nvals] = abs((2 * v3) - v1 - v5);
+ nvals++;
+ } else {
+ /* ignore constant background regions */
+ ngoodpix++;
+ }
+
+ /* shift over 1 pixel */
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = v5;
+ } /* end of loop over pixels in the row */
+
+ /* compute the 3rd order diffs */
+ /* Note that there are 4 more pixel values than there are diffs values. */
+ ngoodpix += (nvals + 4);
+
+ if (nvals == 0) {
+ continue; /* cannot compute medians on this row */
+ } else if (nvals == 1) {
+ diffs[nrows] = differences[0];
+ } else {
+ /* quick_select returns the median MUCH faster than using qsort */
+ diffs[nrows] = quick_select_int(differences, nvals);
+ }
+
+ nrows++;
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise = 0;
+ } else if (nrows == 1) {
+ xnoise = diffs[0];
+ } else {
+
+ qsort(diffs, nrows, sizeof(double), FnCompare_double);
+ xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.;
+
+ FnMeanSigma_double(diffs, nrows, 0, 0.0, 0, &xnoise, &sigma, status);
+
+ /* do a 4.5 sigma rejection of outliers */
+ jj = 0;
+ sigma = 4.5 * sigma;
+ for (ii = 0; ii < nrows; ii++) {
+ if ( fabs(diffs[ii] - xnoise) <= sigma) {
+ if (jj != ii)
+ diffs[jj] = diffs[ii];
+ jj++;
+ }
+ }
+ if (ii != jj)
+ FnMeanSigma_double(diffs, jj, 0, 0.0, 0, &xnoise, &sigma, status);
+ }
+
+ if (ngood) *ngood = ngoodpix;
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (noise) *noise = 0.6052697 * xnoise;
+
+ free(diffs);
+ free(differences);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise3_float
+ (float *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ float nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ long *ngood, /* number of good, non-null pixels? */
+ float *minval, /* minimum non-null value */
+ float *maxval, /* maximum non-null value */
+ double *noise, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Estimate the median and background noise in the input image using 3rd order differences.
+
+The noise in the background of the image is calculated using the 3rd order algorithm
+developed for deriving the signal to noise ratio in spectra
+(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/)
+
+ noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2)))
+
+The returned estimates are the median of the values that are computed for each
+row of the image.
+*/
+{
+ long ii, jj, nrows = 0, nvals, ngoodpix = 0;
+ float *differences, *rowpix, v1, v2, v3, v4, v5;
+ float xminval = FLT_MAX, xmaxval = -FLT_MAX;
+ int do_range = 0;
+ double *diffs, xnoise = 0;
+
+ if (nx < 5) {
+ /* treat entire array as an image with a single row */
+ nx = nx * ny;
+ ny = 1;
+ }
+
+ /* rows must have at least 5 pixels to calc noise, so just calc min, max, ngood */
+ if (nx < 5) {
+
+ for (ii = 0; ii < nx; ii++) {
+ if (nullcheck && array[ii] == nullvalue)
+ continue;
+ else {
+ if (array[ii] < xminval) xminval = array[ii];
+ if (array[ii] > xmaxval) xmaxval = array[ii];
+ ngoodpix++;
+ }
+ }
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (ngood) *ngood = ngoodpix;
+ if (noise) *noise = 0.;
+ return(*status);
+ }
+
+ /* do we need to compute the min and max value? */
+ if (minval || maxval) do_range = 1;
+
+ /* allocate arrays used to compute the median and noise estimates */
+ if (noise) {
+ differences = calloc(nx, sizeof(float));
+ if (!differences) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs = calloc(ny, sizeof(double));
+ if (!diffs) {
+ free(differences);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v1 < xminval) xminval = v1;
+ if (v1 > xmaxval) xmaxval = v1;
+ }
+
+ /***** find the 2nd valid pixel in row (which we will skip over) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v2 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v2 < xminval) xminval = v2;
+ if (v2 > xmaxval) xmaxval = v2;
+ }
+
+ /***** find the 3rd valid pixel in row */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v3 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v3 < xminval) xminval = v3;
+ if (v3 > xmaxval) xmaxval = v3;
+ }
+
+ /* find the 4nd valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v4 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v4 < xminval) xminval = v4;
+ if (v4 > xmaxval) xmaxval = v4;
+ }
+
+ /* now populate the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) {
+ ii++;
+ }
+
+ if (ii == nx) break; /* hit end of row */
+ v5 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v5 < xminval) xminval = v5;
+ if (v5 > xmaxval) xmaxval = v5;
+ }
+
+ /* construct array of 3rd order absolute differences */
+ if (noise) {
+ if (!(v1 == v2 && v2 == v3 && v3 == v4 && v4 == v5)) {
+
+ differences[nvals] = (float) fabs((2. * v3) - v1 - v5);
+ nvals++;
+ } else {
+ /* ignore constant background regions */
+ ngoodpix++;
+ }
+ } else {
+ /* just increment the number of non-null pixels */
+ ngoodpix++;
+ }
+
+ /* shift over 1 pixel */
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = v5;
+ } /* end of loop over pixels in the row */
+
+ /* compute the 3rd order diffs */
+ /* Note that there are 4 more pixel values than there are diffs values. */
+ ngoodpix += (nvals + 4);
+
+ if (noise) {
+ if (nvals == 0) {
+ continue; /* cannot compute medians on this row */
+ } else if (nvals == 1) {
+ diffs[nrows] = differences[0];
+ } else {
+ /* quick_select returns the median MUCH faster than using qsort */
+ diffs[nrows] = quick_select_float(differences, nvals);
+ }
+ }
+ nrows++;
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (noise) {
+ if (nrows == 0) {
+ xnoise = 0;
+ } else if (nrows == 1) {
+ xnoise = diffs[0];
+ } else {
+ qsort(diffs, nrows, sizeof(double), FnCompare_double);
+ xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.;
+ }
+ }
+
+ if (ngood) *ngood = ngoodpix;
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (noise) {
+ *noise = 0.6052697 * xnoise;
+ free(diffs);
+ free(differences);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise3_double
+ (double *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ double nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ long *ngood, /* number of good, non-null pixels? */
+ double *minval, /* minimum non-null value */
+ double *maxval, /* maximum non-null value */
+ double *noise, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+
+/*
+Estimate the median and background noise in the input image using 3rd order differences.
+
+The noise in the background of the image is calculated using the 3rd order algorithm
+developed for deriving the signal to noise ratio in spectra
+(see issue #42 of the ST-ECF newsletter, http://www.stecf.org/documents/newsletter/)
+
+ noise = 1.482602 / sqrt(6) * median (abs(2*flux(i) - flux(i-2) - flux(i+2)))
+
+The returned estimates are the median of the values that are computed for each
+row of the image.
+*/
+{
+ long ii, jj, nrows = 0, nvals, ngoodpix = 0;
+ double *differences, *rowpix, v1, v2, v3, v4, v5;
+ double xminval = DBL_MAX, xmaxval = -DBL_MAX;
+ int do_range = 0;
+ double *diffs, xnoise = 0;
+
+ if (nx < 5) {
+ /* treat entire array as an image with a single row */
+ nx = nx * ny;
+ ny = 1;
+ }
+
+ /* rows must have at least 5 pixels */
+ if (nx < 5) {
+
+ for (ii = 0; ii < nx; ii++) {
+ if (nullcheck && array[ii] == nullvalue)
+ continue;
+ else {
+ if (array[ii] < xminval) xminval = array[ii];
+ if (array[ii] > xmaxval) xmaxval = array[ii];
+ ngoodpix++;
+ }
+ }
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (ngood) *ngood = ngoodpix;
+ if (noise) *noise = 0.;
+ return(*status);
+ }
+
+ /* do we need to compute the min and max value? */
+ if (minval || maxval) do_range = 1;
+
+ /* allocate arrays used to compute the median and noise estimates */
+ if (noise) {
+ differences = calloc(nx, sizeof(double));
+ if (!differences) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs = calloc(ny, sizeof(double));
+ if (!diffs) {
+ free(differences);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v1 < xminval) xminval = v1;
+ if (v1 > xmaxval) xmaxval = v1;
+ }
+
+ /***** find the 2nd valid pixel in row (which we will skip over) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v2 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v2 < xminval) xminval = v2;
+ if (v2 > xmaxval) xmaxval = v2;
+ }
+
+ /***** find the 3rd valid pixel in row */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v3 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v3 < xminval) xminval = v3;
+ if (v3 > xmaxval) xmaxval = v3;
+ }
+
+ /* find the 4nd valid pixel in row (to be skipped) */
+ ii++;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v4 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v4 < xminval) xminval = v4;
+ if (v4 > xmaxval) xmaxval = v4;
+ }
+
+ /* now populate the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+ v5 = rowpix[ii]; /* store the good pixel value */
+
+ if (do_range) {
+ if (v5 < xminval) xminval = v5;
+ if (v5 > xmaxval) xmaxval = v5;
+ }
+
+ /* construct array of 3rd order absolute differences */
+ if (noise) {
+ if (!(v1 == v2 && v2 == v3 && v3 == v4 && v4 == v5)) {
+
+ differences[nvals] = fabs((2. * v3) - v1 - v5);
+ nvals++;
+ } else {
+ /* ignore constant background regions */
+ ngoodpix++;
+ }
+ } else {
+ /* just increment the number of non-null pixels */
+ ngoodpix++;
+ }
+
+ /* shift over 1 pixel */
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = v5;
+ } /* end of loop over pixels in the row */
+
+ /* compute the 3rd order diffs */
+ /* Note that there are 4 more pixel values than there are diffs values. */
+ ngoodpix += (nvals + 4);
+
+ if (noise) {
+ if (nvals == 0) {
+ continue; /* cannot compute medians on this row */
+ } else if (nvals == 1) {
+ diffs[nrows] = differences[0];
+ } else {
+ /* quick_select returns the median MUCH faster than using qsort */
+ diffs[nrows] = quick_select_double(differences, nvals);
+ }
+ }
+ nrows++;
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (noise) {
+ if (nrows == 0) {
+ xnoise = 0;
+ } else if (nrows == 1) {
+ xnoise = diffs[0];
+ } else {
+ qsort(diffs, nrows, sizeof(double), FnCompare_double);
+ xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.;
+ }
+ }
+
+ if (ngood) *ngood = ngoodpix;
+ if (minval) *minval = xminval;
+ if (maxval) *maxval = xmaxval;
+ if (noise) {
+ *noise = 0.6052697 * xnoise;
+ free(diffs);
+ free(differences);
+ }
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise1_short
+ (short *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ short nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ double *noise, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+/*
+Estimate the background noise in the input image using sigma of 1st order differences.
+
+ noise = 1.0 / sqrt(2) * rms of (flux[i] - flux[i-1])
+
+The returned estimate is the median of the values that are computed for each
+row of the image.
+*/
+{
+ int iter;
+ long ii, jj, kk, nrows = 0, nvals;
+ short *differences, *rowpix, v1;
+ double *diffs, xnoise, mean, stdev;
+
+ /* rows must have at least 3 pixels to estimate noise */
+ if (nx < 3) {
+ *noise = 0;
+ return(*status);
+ }
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences = calloc(nx, sizeof(short));
+ if (!differences) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs = calloc(ny, sizeof(double));
+ if (!diffs) {
+ free(differences);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ /* now continue populating the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+
+ /* construct array of 1st order differences */
+ differences[nvals] = v1 - rowpix[ii];
+
+ nvals++;
+ /* shift over 1 pixel */
+ v1 = rowpix[ii];
+ } /* end of loop over pixels in the row */
+
+ if (nvals < 2)
+ continue;
+ else {
+
+ FnMeanSigma_short(differences, nvals, 0, 0, 0, &mean, &stdev, status);
+
+ if (stdev > 0.) {
+ for (iter = 0; iter < NITER; iter++) {
+ kk = 0;
+ for (ii = 0; ii < nvals; ii++) {
+ if (fabs (differences[ii] - mean) < SIGMA_CLIP * stdev) {
+ if (kk < ii)
+ differences[kk] = differences[ii];
+ kk++;
+ }
+ }
+ if (kk == nvals) break;
+
+ nvals = kk;
+ FnMeanSigma_short(differences, nvals, 0, 0, 0, &mean, &stdev, status);
+ }
+ }
+
+ diffs[nrows] = stdev;
+ nrows++;
+ }
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise = 0;
+ } else if (nrows == 1) {
+ xnoise = diffs[0];
+ } else {
+ qsort(diffs, nrows, sizeof(double), FnCompare_double);
+ xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.;
+ }
+
+ *noise = .70710678 * xnoise;
+
+ free(diffs);
+ free(differences);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise1_int
+ (int *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ int nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ double *noise, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+/*
+Estimate the background noise in the input image using sigma of 1st order differences.
+
+ noise = 1.0 / sqrt(2) * rms of (flux[i] - flux[i-1])
+
+The returned estimate is the median of the values that are computed for each
+row of the image.
+*/
+{
+ int iter;
+ long ii, jj, kk, nrows = 0, nvals;
+ int *differences, *rowpix, v1;
+ double *diffs, xnoise, mean, stdev;
+
+ /* rows must have at least 3 pixels to estimate noise */
+ if (nx < 3) {
+ *noise = 0;
+ return(*status);
+ }
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences = calloc(nx, sizeof(int));
+ if (!differences) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs = calloc(ny, sizeof(double));
+ if (!diffs) {
+ free(differences);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ /* now continue populating the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+
+ /* construct array of 1st order differences */
+ differences[nvals] = v1 - rowpix[ii];
+
+ nvals++;
+ /* shift over 1 pixel */
+ v1 = rowpix[ii];
+ } /* end of loop over pixels in the row */
+
+ if (nvals < 2)
+ continue;
+ else {
+
+ FnMeanSigma_int(differences, nvals, 0, 0, 0, &mean, &stdev, status);
+
+ if (stdev > 0.) {
+ for (iter = 0; iter < NITER; iter++) {
+ kk = 0;
+ for (ii = 0; ii < nvals; ii++) {
+ if (fabs (differences[ii] - mean) < SIGMA_CLIP * stdev) {
+ if (kk < ii)
+ differences[kk] = differences[ii];
+ kk++;
+ }
+ }
+ if (kk == nvals) break;
+
+ nvals = kk;
+ FnMeanSigma_int(differences, nvals, 0, 0, 0, &mean, &stdev, status);
+ }
+ }
+
+ diffs[nrows] = stdev;
+ nrows++;
+ }
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise = 0;
+ } else if (nrows == 1) {
+ xnoise = diffs[0];
+ } else {
+ qsort(diffs, nrows, sizeof(double), FnCompare_double);
+ xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.;
+ }
+
+ *noise = .70710678 * xnoise;
+
+ free(diffs);
+ free(differences);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise1_float
+ (float *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ float nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ double *noise, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+/*
+Estimate the background noise in the input image using sigma of 1st order differences.
+
+ noise = 1.0 / sqrt(2) * rms of (flux[i] - flux[i-1])
+
+The returned estimate is the median of the values that are computed for each
+row of the image.
+*/
+{
+ int iter;
+ long ii, jj, kk, nrows = 0, nvals;
+ float *differences, *rowpix, v1;
+ double *diffs, xnoise, mean, stdev;
+
+ /* rows must have at least 3 pixels to estimate noise */
+ if (nx < 3) {
+ *noise = 0;
+ return(*status);
+ }
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences = calloc(nx, sizeof(float));
+ if (!differences) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs = calloc(ny, sizeof(double));
+ if (!diffs) {
+ free(differences);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ /* now continue populating the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+
+ /* construct array of 1st order differences */
+ differences[nvals] = v1 - rowpix[ii];
+
+ nvals++;
+ /* shift over 1 pixel */
+ v1 = rowpix[ii];
+ } /* end of loop over pixels in the row */
+
+ if (nvals < 2)
+ continue;
+ else {
+
+ FnMeanSigma_float(differences, nvals, 0, 0, 0, &mean, &stdev, status);
+
+ if (stdev > 0.) {
+ for (iter = 0; iter < NITER; iter++) {
+ kk = 0;
+ for (ii = 0; ii < nvals; ii++) {
+ if (fabs (differences[ii] - mean) < SIGMA_CLIP * stdev) {
+ if (kk < ii)
+ differences[kk] = differences[ii];
+ kk++;
+ }
+ }
+ if (kk == nvals) break;
+
+ nvals = kk;
+ FnMeanSigma_float(differences, nvals, 0, 0, 0, &mean, &stdev, status);
+ }
+ }
+
+ diffs[nrows] = stdev;
+ nrows++;
+ }
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise = 0;
+ } else if (nrows == 1) {
+ xnoise = diffs[0];
+ } else {
+ qsort(diffs, nrows, sizeof(double), FnCompare_double);
+ xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.;
+ }
+
+ *noise = .70710678 * xnoise;
+
+ free(diffs);
+ free(differences);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnNoise1_double
+ (double *array, /* 2 dimensional array of image pixels */
+ long nx, /* number of pixels in each row of the image */
+ long ny, /* number of rows in the image */
+ int nullcheck, /* check for null values, if true */
+ double nullvalue, /* value of null pixels, if nullcheck is true */
+ /* returned parameters */
+ double *noise, /* returned R.M.S. value of all non-null pixels */
+ int *status) /* error status */
+/*
+Estimate the background noise in the input image using sigma of 1st order differences.
+
+ noise = 1.0 / sqrt(2) * rms of (flux[i] - flux[i-1])
+
+The returned estimate is the median of the values that are computed for each
+row of the image.
+*/
+{
+ int iter;
+ long ii, jj, kk, nrows = 0, nvals;
+ double *differences, *rowpix, v1;
+ double *diffs, xnoise, mean, stdev;
+
+ /* rows must have at least 3 pixels to estimate noise */
+ if (nx < 3) {
+ *noise = 0;
+ return(*status);
+ }
+
+ /* allocate arrays used to compute the median and noise estimates */
+ differences = calloc(nx, sizeof(double));
+ if (!differences) {
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ diffs = calloc(ny, sizeof(double));
+ if (!diffs) {
+ free(differences);
+ *status = MEMORY_ALLOCATION;
+ return(*status);
+ }
+
+ /* loop over each row of the image */
+ for (jj=0; jj < ny; jj++) {
+
+ rowpix = array + (jj * nx); /* point to first pixel in the row */
+
+ /***** find the first valid pixel in row */
+ ii = 0;
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) continue; /* hit end of row */
+ v1 = rowpix[ii]; /* store the good pixel value */
+
+ /* now continue populating the differences arrays */
+ /* for the remaining pixels in the row */
+ nvals = 0;
+ for (ii++; ii < nx; ii++) {
+
+ /* find the next valid pixel in row */
+ if (nullcheck)
+ while (ii < nx && rowpix[ii] == nullvalue) ii++;
+
+ if (ii == nx) break; /* hit end of row */
+
+ /* construct array of 1st order differences */
+ differences[nvals] = v1 - rowpix[ii];
+
+ nvals++;
+ /* shift over 1 pixel */
+ v1 = rowpix[ii];
+ } /* end of loop over pixels in the row */
+
+ if (nvals < 2)
+ continue;
+ else {
+
+ FnMeanSigma_double(differences, nvals, 0, 0, 0, &mean, &stdev, status);
+
+ if (stdev > 0.) {
+ for (iter = 0; iter < NITER; iter++) {
+ kk = 0;
+ for (ii = 0; ii < nvals; ii++) {
+ if (fabs (differences[ii] - mean) < SIGMA_CLIP * stdev) {
+ if (kk < ii)
+ differences[kk] = differences[ii];
+ kk++;
+ }
+ }
+ if (kk == nvals) break;
+
+ nvals = kk;
+ FnMeanSigma_double(differences, nvals, 0, 0, 0, &mean, &stdev, status);
+ }
+ }
+
+ diffs[nrows] = stdev;
+ nrows++;
+ }
+ } /* end of loop over rows */
+
+ /* compute median of the values for each row */
+ if (nrows == 0) {
+ xnoise = 0;
+ } else if (nrows == 1) {
+ xnoise = diffs[0];
+ } else {
+ qsort(diffs, nrows, sizeof(double), FnCompare_double);
+ xnoise = (diffs[(nrows - 1)/2] + diffs[nrows/2]) / 2.;
+ }
+
+ *noise = .70710678 * xnoise;
+
+ free(diffs);
+ free(differences);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+static int FnCompare_short(const void *v1, const void *v2)
+{
+ const short *i1 = v1;
+ const short *i2 = v2;
+
+ if (*i1 < *i2)
+ return(-1);
+ else if (*i1 > *i2)
+ return(1);
+ else
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+static int FnCompare_int(const void *v1, const void *v2)
+{
+ const int *i1 = v1;
+ const int *i2 = v2;
+
+ if (*i1 < *i2)
+ return(-1);
+ else if (*i1 > *i2)
+ return(1);
+ else
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+static int FnCompare_float(const void *v1, const void *v2)
+{
+ const float *i1 = v1;
+ const float *i2 = v2;
+
+ if (*i1 < *i2)
+ return(-1);
+ else if (*i1 > *i2)
+ return(1);
+ else
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+static int FnCompare_double(const void *v1, const void *v2)
+{
+ const double *i1 = v1;
+ const double *i2 = v2;
+
+ if (*i1 < *i2)
+ return(-1);
+ else if (*i1 > *i2)
+ return(1);
+ else
+ return(0);
+}
+/*--------------------------------------------------------------------------*/
+
+/*
+ * These Quickselect routines are 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.
+ */
+
+/*--------------------------------------------------------------------------*/
+
+#define ELEM_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; }
+
+static float quick_select_float(float 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 short t=(a);(a)=(b);(b)=t; }
+
+static short quick_select_short(short 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 int t=(a);(a)=(b);(b)=t; }
+
+static int quick_select_int(int 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 LONGLONG t=(a);(a)=(b);(b)=t; }
+
+static LONGLONG quick_select_longlong(LONGLONG 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; }
+
+static double quick_select_double(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
+
+
diff --git a/vendor/cfitsio/quick.pdf b/vendor/cfitsio/quick.pdf
new file mode 100644
index 00000000..487e1ece
--- /dev/null
+++ b/vendor/cfitsio/quick.pdf
Binary files differ
diff --git a/vendor/cfitsio/quick.ps b/vendor/cfitsio/quick.ps
new file mode 100644
index 00000000..7503d841
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/quick.tex b/vendor/cfitsio/quick.tex
new file mode 100644
index 00000000..109d04e1
--- /dev/null
+++ b/vendor/cfitsio/quick.tex
@@ -0,0 +1,2159 @@
+\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
+ TLONGLONG signed 8-byte integer
+ 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
+ TLONGLONG signed 8-byte integer
+ 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
+record, or the keyword value and comment string. In each case any
+non-significant trailing blank characters in the strings are truncated.
+
+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/vendor/cfitsio/quick.toc b/vendor/cfitsio/quick.toc
new file mode 100644
index 00000000..9d7c7da6
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/region.c b/vendor/cfitsio/region.c
new file mode 100644
index 00000000..3ec5bc28
--- /dev/null
+++ b/vendor/cfitsio/region.c
@@ -0,0 +1,1747 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include "fitsio2.h"
+#include "region.h"
+static int Pt_in_Poly( double x, double y, int nPts, double *Pts );
+
+/*---------------------------------------------------------------------------*/
+int fits_read_rgnfile( const char *filename,
+ WCSdata *wcs,
+ SAORegion **Rgn,
+ int *status )
+/* Read regions from either a FITS or ASCII 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. */
+/*---------------------------------------------------------------------------*/
+{
+ fitsfile *fptr;
+ int tstatus = 0;
+
+ if( *status ) return( *status );
+
+ /* try to open as a FITS file - if that doesn't work treat as an ASCII file */
+
+ fits_write_errmark();
+ if ( ffopen(&fptr, filename, READONLY, &tstatus) ) {
+ fits_clear_errmark();
+ fits_read_ascii_region(filename, wcs, Rgn, status);
+ } else {
+ fits_read_fits_region(fptr, wcs, Rgn, status);
+ }
+
+ return(*status);
+
+}
+/*---------------------------------------------------------------------------*/
+int fits_read_ascii_region( 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, X, Y, x, y, ss, div, 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( isspace(*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( isspace(*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++;
+ if ( paramPtr ) cFmt = hhmmss_fmt; /* set format if parameter has : */
+ break;
+ case 'd':
+ currLoc++;
+ if ( paramPtr ) cFmt = degree_fmt; /* set format if parameter has d */
+ 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( isspace(*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, "linear;", 7 ) ) {
+ namePtr += 7;
+ 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 5 cases support region files created by POW
+ (or ds9 Version 4.x) 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, "physical", 8 ) ) {
+ 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;
+ for (i=0; i<8; i++) newShape->param.gen.p[i] = 0.0;
+ newShape->param.gen.a = 0.0;
+ newShape->param.gen.b = 0.0;
+ newShape->param.gen.sinT = 0.0;
+ newShape->param.gen.cosT = 0.0;
+
+ while( isspace(*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( isspace(*namePtr) ) namePtr++;
+ if( *namePtr=='\0' ) {
+ ffpmsg( "Error reading Region file" );
+ *status = PARSE_SYNTAX_ERR;
+ goto error;
+ }
+ lineLen = strlen( namePtr ) - 1;
+ while( isspace(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" ) ) {
+ if( nParams < 4 || nParams > 8 ) {
+ *status = PARSE_SYNTAX_ERR;
+ } else if ( nParams < 6 ) {
+ newShape->shape = ellipse_rgn;
+ newShape->param.gen.p[4] = 0.0;
+ } else {
+ newShape->shape = elliptannulus_rgn;
+ newShape->param.gen.p[6] = 0.0;
+ newShape->param.gen.p[7] = 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" ) ) {
+ if( nParams < 4 || nParams > 8 ) {
+ *status = PARSE_SYNTAX_ERR;
+ } else if ( nParams < 6 ) {
+ newShape->shape = box_rgn;
+ newShape->param.gen.p[4] = 0.0;
+ } else {
+ newShape->shape = boxannulus_rgn;
+ newShape->param.gen.p[6] = 0.0;
+ newShape->param.gen.p[7] = 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 if( !strcasecmp( namePtr, "panda" ) ) {
+ newShape->shape = panda_rgn;
+ if( nParams != 8 )
+ *status = PARSE_SYNTAX_ERR;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "epanda" ) ) {
+ newShape->shape = epanda_rgn;
+ if( nParams < 10 || nParams > 11 )
+ *status = PARSE_SYNTAX_ERR;
+ newShape->param.gen.p[10] = 0.0;
+ nCoords = 2;
+ } else if( !strcasecmp( namePtr, "bpanda" ) ) {
+ newShape->shape = bpanda_rgn;
+ if( nParams < 10 || nParams > 11 )
+ *status = PARSE_SYNTAX_ERR;
+ newShape->param.gen.p[10] = 0.0;
+ nCoords = 2;
+ } 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( isspace(*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=='"' || *endp=='\'' || *endp=='d') ) {
+ div = 1.0;
+ if ( *endp=='"' ) div = 3600.0;
+ if ( *endp=='\'' ) div = 60.0;
+ /* 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]/div; /* don't exceed -90 */
+ else
+ Y = ysave - coords[i]/div; /* 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) );
+
+ }
+ }
+
+ /* special case for elliptannulus and boxannulus if only one angle
+ was given */
+
+ if ( (newShape->shape == elliptannulus_rgn ||
+ newShape->shape == boxannulus_rgn ) && nParams == 7 ) {
+ coords[7] = coords[6];
+ }
+
+ /* Also, correct the position angle for any WCS rotation: */
+ /* If regions are specified in WCS coordintes, then the angles */
+ /* are relative to the WCS system, not the pixel X,Y system */
+
+ if( cFmt!=pixel_fmt ) {
+ switch( newShape->shape ) {
+ case sector_rgn:
+ case panda_rgn:
+ coords[2] += (wcs->rot);
+ coords[3] += (wcs->rot);
+ break;
+ case box_rgn:
+ case rectangle_rgn:
+ case diamond_rgn:
+ case ellipse_rgn:
+ coords[4] += (wcs->rot);
+ break;
+ case boxannulus_rgn:
+ case elliptannulus_rgn:
+ coords[6] += (wcs->rot);
+ coords[7] += (wcs->rot);
+ break;
+ case epanda_rgn:
+ case bpanda_rgn:
+ coords[2] += (wcs->rot);
+ coords[3] += (wcs->rot);
+ coords[10] += (wcs->rot);
+ }
+ }
+
+ /* do some precalculations to speed up tests */
+
+ fits_setup_shape(newShape);
+
+ } /* 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) ) */
+
+ /* set up component numbers */
+
+ fits_set_region_components( aRgn );
+
+error:
+
+ if( *status ) {
+ fits_free_region( aRgn );
+ } else {
+ *Rgn = aRgn;
+ }
+
+ fclose( rgnFile );
+ free( currLine );
+
+ return( *status );
+}
+
+/*---------------------------------------------------------------------------*/
+int fits_in_region( 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, th;
+ RgnShape *Shapes;
+ int i, cur_comp;
+ int result, comp_result;
+
+ Shapes = Rgn->Shapes;
+
+ result = 0;
+ comp_result = 0;
+ cur_comp = Rgn->Shapes[0].comp;
+
+ for( i=0; i<Rgn->nShapes; i++, Shapes++ ) {
+
+ /* if this region has a different component number to the last one */
+ /* then replace the accumulated selection logical with the union of */
+ /* the current logical and the total logical. Reinitialize the */
+ /* temporary logical. */
+
+ if ( i==0 || Shapes->comp != cur_comp ) {
+ result = result || comp_result;
+ cur_comp = Shapes->comp;
+ /* if an excluded region is given first, then implicitly */
+ /* assume a previous shape that includes the entire image. */
+ comp_result = !Shapes->sign;
+ }
+
+ /* 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 ( (!comp_result && Shapes->sign) || (comp_result && !Shapes->sign) ) {
+
+ comp_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) )
+ comp_result = 0;
+ break;
+
+ case boxannulus_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[4];
+ dy = 0.5 * Shapes->param.gen.p[5];
+ if( (x < -dx) || (x > dx) || (y < -dy) || (y > dy) ) {
+ comp_result = 0;
+ } else {
+ /* Repeat test for inner box */
+ x = xprime * Shapes->param.gen.b + yprime * Shapes->param.gen.a;
+ y = -xprime * Shapes->param.gen.a + yprime * Shapes->param.gen.b;
+
+ 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) )
+ comp_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) )
+ comp_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 )
+ comp_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 )
+ comp_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 )
+ comp_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 ) * RadToDeg;
+ if( Shapes->param.gen.p[2] <= Shapes->param.gen.p[3] ) {
+ if( r < Shapes->param.gen.p[2] || r > Shapes->param.gen.p[3] )
+ comp_result = 0;
+ } else {
+ if( r < Shapes->param.gen.p[2] && r > Shapes->param.gen.p[3] )
+ comp_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 )
+ comp_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 )
+ comp_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 )
+ comp_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) )
+ comp_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) )
+ comp_result = 0;
+ break;
+
+ case poly_rgn:
+ if( X<Shapes->xmin || X>Shapes->xmax
+ || Y<Shapes->ymin || Y>Shapes->ymax )
+ comp_result = 0;
+ else
+ comp_result = Pt_in_Poly( X, Y, Shapes->param.poly.nPts,
+ Shapes->param.poly.Pts );
+ break;
+
+ case panda_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 ) {
+ comp_result = 0;
+ } else {
+ if( x || y ) {
+ th = atan2( y, x ) * RadToDeg;
+ if( Shapes->param.gen.p[2] <= Shapes->param.gen.p[3] ) {
+ if( th < Shapes->param.gen.p[2] || th > Shapes->param.gen.p[3] )
+ comp_result = 0;
+ } else {
+ if( th < Shapes->param.gen.p[2] && th > Shapes->param.gen.p[3] )
+ comp_result = 0;
+ }
+ }
+ }
+ break;
+
+ case epanda_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;
+ xprime = x;
+ yprime = y;
+
+ /* outer region test */
+ x = xprime/Shapes->param.gen.p[7];
+ y = yprime/Shapes->param.gen.p[8];
+ r = x*x + y*y;
+ if ( r>1.0 )
+ comp_result = 0;
+ else {
+ /* inner region test */
+ x = xprime/Shapes->param.gen.p[5];
+ y = yprime/Shapes->param.gen.p[6];
+ r = x*x + y*y;
+ if ( r<1.0 )
+ comp_result = 0;
+ else {
+ /* angle test */
+ if( xprime || yprime ) {
+ th = atan2( yprime, xprime ) * RadToDeg;
+ if( Shapes->param.gen.p[2] <= Shapes->param.gen.p[3] ) {
+ if( th < Shapes->param.gen.p[2] || th > Shapes->param.gen.p[3] )
+ comp_result = 0;
+ } else {
+ if( th < Shapes->param.gen.p[2] && th > Shapes->param.gen.p[3] )
+ comp_result = 0;
+ }
+ }
+ }
+ }
+ break;
+
+ case bpanda_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;
+
+ /* outer box test */
+ dx = 0.5 * Shapes->param.gen.p[7];
+ dy = 0.5 * Shapes->param.gen.p[8];
+ if( (x < -dx) || (x > dx) || (y < -dy) || (y > dy) )
+ comp_result = 0;
+ else {
+ /* inner box test */
+ dx = 0.5 * Shapes->param.gen.p[5];
+ dy = 0.5 * Shapes->param.gen.p[6];
+ if( (x >= -dx) && (x <= dx) && (y >= -dy) && (y <= dy) )
+ comp_result = 0;
+ else {
+ /* angle test */
+ if( x || y ) {
+ th = atan2( y, x ) * RadToDeg;
+ if( Shapes->param.gen.p[2] <= Shapes->param.gen.p[3] ) {
+ if( th < Shapes->param.gen.p[2] || th > Shapes->param.gen.p[3] )
+ comp_result = 0;
+ } else {
+ if( th < Shapes->param.gen.p[2] && th > Shapes->param.gen.p[3] )
+ comp_result = 0;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if( !Shapes->sign ) comp_result = !comp_result;
+
+ }
+
+ }
+
+ result = result || comp_result;
+
+ return( result );
+}
+
+/*---------------------------------------------------------------------------*/
+void fits_free_region( 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 );
+}
+/*---------------------------------------------------------------------------*/
+void fits_set_region_components ( SAORegion *aRgn )
+{
+/*
+ Internal routine to turn a collection of regions read from an ascii file into
+ the more complex structure that is allowed by the FITS REGION extension with
+ multiple components. Regions are anded within components and ored between them
+ ie for a pixel to be selected it must be selected by at least one component
+ and to be selected by a component it must be selected by all that component's
+ shapes.
+
+ The algorithm is to replicate every exclude region after every include
+ region before it in the list. eg reg1, reg2, -reg3, reg4, -reg5 becomes
+ (reg1, -reg3, -reg5), (reg2, -reg5, -reg3), (reg4, -reg5) where the
+ parentheses designate components.
+*/
+
+ int i, j, k, icomp;
+
+/* loop round shapes */
+
+ i = 0;
+ while ( i<aRgn->nShapes ) {
+
+ /* first do the case of an exclude region */
+
+ if ( !aRgn->Shapes[i].sign ) {
+
+ /* we need to run back through the list copying the current shape as
+ required. start by findin the first include shape before this exclude */
+
+ j = i-1;
+ while ( j > 0 && !aRgn->Shapes[j].sign ) j--;
+
+ /* then go back one more shape */
+
+ j--;
+
+ /* and loop back through the regions */
+
+ while ( j >= 0 ) {
+
+ /* if this is an include region then insert a copy of the exclude
+ region immediately after it */
+
+ if ( aRgn->Shapes[j].sign ) {
+
+ aRgn->Shapes = (RgnShape *) realloc (aRgn->Shapes,(1+aRgn->nShapes)*sizeof(RgnShape));
+ aRgn->nShapes++;
+ for (k=aRgn->nShapes-1; k>j+1; k--) aRgn->Shapes[k] = aRgn->Shapes[k-1];
+
+ i++;
+ aRgn->Shapes[j+1] = aRgn->Shapes[i];
+
+ }
+
+ j--;
+
+ }
+
+ }
+
+ i++;
+
+ }
+
+ /* now set the component numbers */
+
+ icomp = 0;
+ for ( i=0; i<aRgn->nShapes; i++ ) {
+ if ( aRgn->Shapes[i].sign ) icomp++;
+ aRgn->Shapes[i].comp = icomp;
+
+ /*
+ printf("i = %d, shape = %d, sign = %d, comp = %d\n", i, aRgn->Shapes[i].shape, aRgn->Shapes[i].sign, aRgn->Shapes[i].comp);
+ */
+
+ }
+
+ return;
+
+}
+
+/*---------------------------------------------------------------------------*/
+void fits_setup_shape ( RgnShape *newShape)
+{
+/* Perform some useful calculations now to speed up filter later */
+
+ double X, Y, R;
+ double *coords;
+ int i;
+
+ if ( newShape->shape == poly_rgn ) {
+ coords = newShape->param.poly.Pts;
+ } else {
+ coords = newShape->param.gen.p;
+ }
+
+ 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 boxannulus_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 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 panda_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;
+ newShape->param.gen.a = newShape->param.gen.p[5]*newShape->param.gen.p[5];
+ newShape->param.gen.b = newShape->param.gen.p[6]*newShape->param.gen.p[6];
+ break;
+ case epanda_rgn:
+ case bpanda_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;
+ newShape->param.gen.sinT = sin( myPI * (coords[10] / 180.0) );
+ newShape->param.gen.cosT = cos( myPI * (coords[10] / 180.0) );
+ break;
+ }
+
+ /* Set the xmin, xmax, ymin, ymax elements of the RgnShape structure */
+
+ /* For everything which has first two parameters as center position just */
+ /* find a circle that encompasses the region and use it to set the */
+ /* bounding box */
+
+ R = -1.0;
+
+ switch ( newShape->shape ) {
+
+ case circle_rgn:
+ R = coords[2];
+ break;
+
+ case annulus_rgn:
+ R = coords[3];
+ break;
+
+ case ellipse_rgn:
+ if ( coords[2] > coords[3] ) {
+ R = coords[2];
+ } else {
+ R = coords[3];
+ }
+ break;
+
+ case elliptannulus_rgn:
+ if ( coords[4] > coords[5] ) {
+ R = coords[4];
+ } else {
+ R = coords[5];
+ }
+ break;
+
+ case box_rgn:
+ R = sqrt(coords[2]*coords[2]+
+ coords[3]*coords[3])/2.0;
+ break;
+
+ case boxannulus_rgn:
+ R = sqrt(coords[4]*coords[5]+
+ coords[4]*coords[5])/2.0;
+ break;
+
+ case diamond_rgn:
+ if ( coords[2] > coords[3] ) {
+ R = coords[2]/2.0;
+ } else {
+ R = coords[3]/2.0;
+ }
+ break;
+
+ case point_rgn:
+ R = 1.0;
+ break;
+
+ case panda_rgn:
+ R = coords[6];
+ break;
+
+ case epanda_rgn:
+ if ( coords[7] > coords[8] ) {
+ R = coords[7];
+ } else {
+ R = coords[8];
+ }
+ break;
+
+ case bpanda_rgn:
+ R = sqrt(coords[7]*coords[8]+
+ coords[7]*coords[8])/2.0;
+ break;
+
+ }
+
+ if ( R > 0.0 ) {
+
+ newShape->xmin = coords[0] - R;
+ newShape->xmax = coords[0] + R;
+ newShape->ymin = coords[1] - R;
+ newShape->ymax = coords[1] + R;
+
+ return;
+
+ }
+
+ /* Now do the rest of the shapes that require individual methods */
+
+ switch ( newShape->shape ) {
+
+ case rectangle_rgn:
+ R = sqrt((coords[5]-coords[0])*(coords[5]-coords[0])+
+ (coords[6]-coords[1])*(coords[6]-coords[1]));
+ newShape->xmin = coords[5] - R;
+ newShape->xmax = coords[5] + R;
+ newShape->ymin = coords[6] - R;
+ newShape->ymax = coords[6] + R;
+ break;
+
+ case poly_rgn:
+ newShape->xmin = coords[0];
+ newShape->xmax = coords[0];
+ newShape->ymin = coords[1];
+ newShape->ymax = coords[1];
+ for( i=2; i < newShape->param.poly.nPts; ) {
+ if( newShape->xmin > coords[i] ) /* Min X */
+ newShape->xmin = coords[i];
+ if( newShape->xmax < coords[i] ) /* Max X */
+ newShape->xmax = coords[i];
+ i++;
+ if( newShape->ymin > coords[i] ) /* Min Y */
+ newShape->ymin = coords[i];
+ if( newShape->ymax < coords[i] ) /* Max Y */
+ newShape->ymax = coords[i];
+ i++;
+ }
+ break;
+
+ case line_rgn:
+ if ( coords[0] > coords[2] ) {
+ newShape->xmin = coords[2];
+ newShape->xmax = coords[0];
+ } else {
+ newShape->xmin = coords[0];
+ newShape->xmax = coords[2];
+ }
+ if ( coords[1] > coords[3] ) {
+ newShape->ymin = coords[3];
+ newShape->ymax = coords[1];
+ } else {
+ newShape->ymin = coords[1];
+ newShape->ymax = coords[3];
+ }
+
+ break;
+
+ /* sector doesn't have min and max so indicate by setting max < min */
+
+ case sector_rgn:
+ newShape->xmin = 1.0;
+ newShape->xmax = -1.0;
+ newShape->ymin = 1.0;
+ newShape->ymax = -1.0;
+ break;
+
+ }
+
+ return;
+
+}
+
+/*---------------------------------------------------------------------------*/
+int fits_read_fits_region ( fitsfile *fptr,
+ WCSdata *wcs,
+ SAORegion **Rgn,
+ int *status)
+/* Read regions from a FITS region extension 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. */
+/*---------------------------------------------------------------------------*/
+{
+
+ int i, j, icol[6], idum, anynul, npos;
+ int dotransform, got_component = 1, tstatus;
+ long icsize[6];
+ double X, Y, Theta, Xsave, Ysave, Xpos, Ypos;
+ double *coords;
+ char *cvalue, *cvalue2;
+ char comment[FLEN_COMMENT];
+ char colname[6][FLEN_VALUE] = {"X", "Y", "SHAPE", "R", "ROTANG", "COMPONENT"};
+ char shapename[17][FLEN_VALUE] = {"POINT","CIRCLE","ELLIPSE","ANNULUS",
+ "ELLIPTANNULUS","BOX","ROTBOX","BOXANNULUS",
+ "RECTANGLE","ROTRECTANGLE","POLYGON","PIE",
+ "SECTOR","DIAMOND","RHOMBUS","ROTDIAMOND",
+ "ROTRHOMBUS"};
+ int shapetype[17] = {point_rgn, circle_rgn, ellipse_rgn, annulus_rgn,
+ elliptannulus_rgn, box_rgn, box_rgn, boxannulus_rgn,
+ rectangle_rgn, rectangle_rgn, poly_rgn, sector_rgn,
+ sector_rgn, diamond_rgn, diamond_rgn, diamond_rgn,
+ diamond_rgn};
+ SAORegion *aRgn;
+ RgnShape *newShape;
+ WCSdata *regwcs;
+
+ 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;
+
+ /* See if we are already positioned to a region extension, else */
+ /* move to the REGION extension (file is already open). */
+
+ tstatus = 0;
+ for (i=0; i<5; i++) {
+ ffgcno(fptr, CASEINSEN, colname[i], &icol[i], &tstatus);
+ }
+
+ if (tstatus) {
+ /* couldn't find the required columns, so search for "REGION" extension */
+ if ( ffmnhd(fptr, BINARY_TBL, "REGION", 1, status) ) {
+ ffpmsg("Could not move to REGION extension.");
+ goto error;
+ }
+ }
+
+ /* get the number of shapes and allocate memory */
+
+ if ( ffgky(fptr, TINT, "NAXIS2", &aRgn->nShapes, comment, status) ) {
+ ffpmsg("Could not read NAXIS2 keyword.");
+ goto error;
+ }
+
+ aRgn->Shapes = (RgnShape *) malloc(aRgn->nShapes * sizeof(RgnShape));
+ if ( !aRgn->Shapes ) {
+ ffpmsg( "Failed to allocate memory for Region data");
+ *status = MEMORY_ALLOCATION;
+ goto error;
+ }
+
+ /* get the required column numbers */
+
+ for (i=0; i<5; i++) {
+ if ( ffgcno(fptr, CASEINSEN, colname[i], &icol[i], status) ) {
+ ffpmsg("Could not find column.");
+ goto error;
+ }
+ }
+
+ /* try to get the optional column numbers */
+
+ if ( ffgcno(fptr, CASEINSEN, colname[5], &icol[5], status) ) {
+ got_component = 0;
+ }
+
+ /* if there was input WCS then read the WCS info for the region in case they */
+ /* are different and we have to transform */
+
+ dotransform = 0;
+ if ( aRgn->wcs.exists ) {
+ regwcs = (WCSdata *) malloc ( sizeof(WCSdata) );
+ if ( !regwcs ) {
+ ffpmsg( "Failed to allocate memory for Region WCS data");
+ *status = MEMORY_ALLOCATION;
+ goto error;
+ }
+
+ regwcs->exists = 1;
+ if ( ffgtcs(fptr, icol[0], icol[1], &regwcs->xrefval, &regwcs->yrefval,
+ &regwcs->xrefpix, &regwcs->yrefpix, &regwcs->xinc, &regwcs->yinc,
+ &regwcs->rot, regwcs->type, status) ) {
+ regwcs->exists = 0;
+ *status = 0;
+ }
+
+ if ( regwcs->exists && wcs->exists ) {
+ if ( fabs(regwcs->xrefval-wcs->xrefval) > 1.0e-6 ||
+ fabs(regwcs->yrefval-wcs->yrefval) > 1.0e-6 ||
+ fabs(regwcs->xrefpix-wcs->xrefpix) > 1.0e-6 ||
+ fabs(regwcs->yrefpix-wcs->yrefpix) > 1.0e-6 ||
+ fabs(regwcs->xinc-wcs->xinc) > 1.0e-6 ||
+ fabs(regwcs->yinc-wcs->yinc) > 1.0e-6 ||
+ fabs(regwcs->rot-wcs->rot) > 1.0e-6 ||
+ !strcmp(regwcs->type,wcs->type) ) dotransform = 1;
+ }
+ }
+
+ /* get the sizes of the X, Y, R, and ROTANG vectors */
+
+ for (i=0; i<6; i++) {
+ if ( ffgtdm(fptr, icol[i], 1, &idum, &icsize[i], status) ) {
+ ffpmsg("Could not find vector size of column.");
+ goto error;
+ }
+ }
+
+ cvalue = (char *) malloc ((FLEN_VALUE+1)*sizeof(char));
+
+ /* loop over the shapes - note 1-based counting for rows in FITS files */
+
+ for (i=1; i<=aRgn->nShapes; i++) {
+
+ newShape = &aRgn->Shapes[i-1];
+ for (j=0; j<8; j++) newShape->param.gen.p[j] = 0.0;
+ newShape->param.gen.a = 0.0;
+ newShape->param.gen.b = 0.0;
+ newShape->param.gen.sinT = 0.0;
+ newShape->param.gen.cosT = 0.0;
+
+ /* get the shape */
+
+ if ( ffgcvs(fptr, icol[2], i, 1, 1, " ", &cvalue, &anynul, status) ) {
+ ffpmsg("Could not read shape.");
+ goto error;
+ }
+
+ /* set include or exclude */
+
+ newShape->sign = 1;
+ cvalue2 = cvalue;
+ if ( !strncmp(cvalue,"!",1) ) {
+ newShape->sign = 0;
+ cvalue2++;
+ }
+
+ /* set the shape type */
+
+ for (j=0; j<9; j++) {
+ if ( !strcmp(cvalue2, shapename[j]) ) newShape->shape = shapetype[j];
+ }
+
+ /* allocate memory for polygon case and set coords pointer */
+
+ if ( newShape->shape == poly_rgn ) {
+ newShape->param.poly.Pts = (double *) calloc (2*icsize[0], 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 = 2*icsize[0];
+ coords = newShape->param.poly.Pts;
+ } else {
+ coords = newShape->param.gen.p;
+ }
+
+
+ /* read X and Y. Polygon and Rectangle require special cases */
+
+ npos = 1;
+ if ( newShape->shape == poly_rgn ) npos = newShape->param.poly.nPts/2;
+ if ( newShape->shape == rectangle_rgn ) npos = 2;
+
+ for (j=0; j<npos; j++) {
+ if ( ffgcvd(fptr, icol[0], i, j+1, 1, DOUBLENULLVALUE, coords, &anynul, status) ) {
+ ffpmsg("Failed to read X column for polygon region");
+ goto error;
+ }
+ if (*coords == DOUBLENULLVALUE) { /* check for null value end of array marker */
+ npos = j;
+ newShape->param.poly.nPts = npos * 2;
+ break;
+ }
+ coords++;
+
+ if ( ffgcvd(fptr, icol[1], i, j+1, 1, DOUBLENULLVALUE, coords, &anynul, status) ) {
+ ffpmsg("Failed to read Y column for polygon region");
+ goto error;
+ }
+ if (*coords == DOUBLENULLVALUE) { /* check for null value end of array marker */
+ npos = j;
+ newShape->param.poly.nPts = npos * 2;
+ coords--;
+ break;
+ }
+ coords++;
+
+ if (j == 0) { /* save the first X and Y coordinate */
+ Xsave = *(coords - 2);
+ Ysave = *(coords - 1);
+ } else if ((Xsave == *(coords - 2)) && (Ysave == *(coords - 1)) ) {
+ /* if point has same coordinate as first point, this marks the end of the array */
+ npos = j + 1;
+ newShape->param.poly.nPts = npos * 2;
+ break;
+ }
+ }
+
+ /* transform positions if the region and input wcs differ */
+
+ if ( dotransform ) {
+
+ coords -= npos*2;
+ Xsave = coords[0];
+ Ysave = coords[1];
+ for (j=0; j<npos; j++) {
+ ffwldp(coords[2*j], coords[2*j+1], regwcs->xrefval, regwcs->yrefval, regwcs->xrefpix,
+ regwcs->yrefpix, regwcs->xinc, regwcs->yinc, regwcs->rot,
+ regwcs->type, &Xpos, &Ypos, status);
+ ffxypx(Xpos, Ypos, wcs->xrefval, wcs->yrefval, wcs->xrefpix,
+ wcs->yrefpix, wcs->xinc, wcs->yinc, wcs->rot,
+ wcs->type, &coords[2*j], &coords[2*j+1], status);
+ if ( *status ) {
+ ffpmsg("Failed to transform coordinates");
+ goto error;
+ }
+ }
+ coords += npos*2;
+ }
+
+ /* read R. Circle requires one number; Box, Diamond, Ellipse, Annulus, Sector
+ and Panda two; Boxannulus and Elliptannulus four; Point, Rectangle and
+ Polygon none. */
+
+ npos = 0;
+ switch ( newShape->shape ) {
+ case circle_rgn:
+ npos = 1;
+ break;
+ case box_rgn:
+ case diamond_rgn:
+ case ellipse_rgn:
+ case annulus_rgn:
+ case sector_rgn:
+ npos = 2;
+ break;
+ case boxannulus_rgn:
+ case elliptannulus_rgn:
+ npos = 4;
+ break;
+ }
+
+ if ( npos > 0 ) {
+ if ( ffgcvd(fptr, icol[3], i, 1, npos, 0.0, coords, &anynul, status) ) {
+ ffpmsg("Failed to read R column for region");
+ goto error;
+ }
+
+ /* transform lengths if the region and input wcs differ */
+
+ if ( dotransform ) {
+ for (j=0; j<npos; j++) {
+ Y = Ysave + (*coords);
+ X = Xsave;
+ ffwldp(X, Y, regwcs->xrefval, regwcs->yrefval, regwcs->xrefpix,
+ regwcs->yrefpix, regwcs->xinc, regwcs->yinc, regwcs->rot,
+ regwcs->type, &Xpos, &Ypos, status);
+ ffxypx(Xpos, Ypos, wcs->xrefval, wcs->yrefval, wcs->xrefpix,
+ wcs->yrefpix, wcs->xinc, wcs->yinc, wcs->rot,
+ wcs->type, &X, &Y, status);
+ if ( *status ) {
+ ffpmsg("Failed to transform coordinates");
+ goto error;
+ }
+ *(coords++) = sqrt(pow(X-newShape->param.gen.p[0],2)+pow(Y-newShape->param.gen.p[1],2));
+ }
+ } else {
+ coords += npos;
+ }
+ }
+
+ /* read ROTANG. Requires two values for Boxannulus, Elliptannulus, Sector,
+ Panda; one for Box, Diamond, Ellipse; and none for Circle, Point, Annulus,
+ Rectangle, Polygon */
+
+ npos = 0;
+ switch ( newShape->shape ) {
+ case box_rgn:
+ case diamond_rgn:
+ case ellipse_rgn:
+ npos = 1;
+ break;
+ case boxannulus_rgn:
+ case elliptannulus_rgn:
+ case sector_rgn:
+ npos = 2;
+ break;
+ }
+
+ if ( npos > 0 ) {
+ if ( ffgcvd(fptr, icol[4], i, 1, npos, 0.0, coords, &anynul, status) ) {
+ ffpmsg("Failed to read ROTANG column for region");
+ goto error;
+ }
+
+ /* transform angles if the region and input wcs differ */
+
+ if ( dotransform ) {
+ Theta = (wcs->rot) - (regwcs->rot);
+ for (j=0; j<npos; j++) *(coords++) += Theta;
+ } else {
+ coords += npos;
+ }
+ }
+
+ /* read the component number */
+
+ if (got_component) {
+ if ( ffgcv(fptr, TINT, icol[5], i, 1, 1, 0, &newShape->comp, &anynul, status) ) {
+ ffpmsg("Failed to read COMPONENT column for region");
+ goto error;
+ }
+ } else {
+ newShape->comp = 1;
+ }
+
+
+ /* do some precalculations to speed up tests */
+
+ fits_setup_shape(newShape);
+
+ /* end loop over shapes */
+
+ }
+
+error:
+
+ if( *status )
+ fits_free_region( aRgn );
+ else
+ *Rgn = aRgn;
+
+ ffclos(fptr, status);
+
+ return( *status );
+}
+
diff --git a/vendor/cfitsio/region.h b/vendor/cfitsio/region.h
new file mode 100644
index 00000000..516c4fdb
--- /dev/null
+++ b/vendor/cfitsio/region.h
@@ -0,0 +1,82 @@
+/***************************************************************/
+/* REGION STUFF */
+/***************************************************************/
+
+#include "fitsio.h"
+#define myPI 3.1415926535897932385
+#define RadToDeg 180.0/myPI
+
+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,
+ boxannulus_rgn,
+ rectangle_rgn,
+ diamond_rgn,
+ sector_rgn,
+ poly_rgn,
+ panda_rgn,
+ epanda_rgn,
+ bpanda_rgn
+} shapeType;
+
+typedef enum { pixel_fmt, degree_fmt, hhmmss_fmt } coordFmt;
+
+typedef struct {
+ char sign; /* Include or exclude? */
+ shapeType shape; /* Shape of this region */
+ int comp; /* Component number for this region */
+
+ double xmin,xmax; /* bounding box */
+ double ymin,ymax;
+
+ union { /* Parameters - In pixels */
+
+ /**** Generic Shape Data ****/
+
+ struct {
+ double p[11]; /* 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 */
+ } poly;
+
+ } param;
+
+} RgnShape;
+
+typedef struct {
+ int nShapes;
+ RgnShape *Shapes;
+ WCSdata wcs;
+} SAORegion;
+
+/* SAO region file routines */
+int fits_read_rgnfile( const char *filename, WCSdata *wcs, SAORegion **Rgn, int *status );
+int fits_in_region( double X, double Y, SAORegion *Rgn );
+void fits_free_region( SAORegion *Rgn );
+void fits_set_region_components ( SAORegion *Rgn );
+void fits_setup_shape ( RgnShape *shape);
+int fits_read_fits_region ( fitsfile *fptr, WCSdata * wcs, SAORegion **Rgn, int *status);
+int fits_read_ascii_region ( const char *filename, WCSdata * wcs, SAORegion **Rgn, int *status);
+
+
diff --git a/vendor/cfitsio/ricecomp.c b/vendor/cfitsio/ricecomp.c
new file mode 100644
index 00000000..d5a11a43
--- /dev/null
+++ b/vendor/cfitsio/ricecomp.c
@@ -0,0 +1,1382 @@
+/*
+ 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>
+
+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 putcbuf(c,mf) ((*(mf->current)++ = c), 0)
+
+#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; */
+int 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; now an input parameter*/
+ /*
+ * 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);
+ }
+*/
+
+ /* move out of switch block, to tweak performance */
+ fsbits = 5;
+ fsmax = 25;
+ 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;
+ putcbuf(lbitbuffer & 0xff,buffer);
+
+ for (top -= lbits_to_go; top>=8; top -= 8) {
+ putcbuf(0, buffer);
+ }
+ 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) {
+ putcbuf((lbitbuffer>>(-lbits_to_go)) & 0xff,buffer);
+ lbits_to_go += 8;
+ }
+ }
+ }
+
+ /* check if overflowed output buffer */
+ if (buffer->current > buffer->end) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ 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);
+}
+/*---------------------------------------------------------------------------*/
+
+int fits_rcomp_short(
+ short 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; */
+int i, j, thisblock;
+
+/*
+NOTE: in principle, the following 2 variable could be declared as 'short'
+but in fact the code runs faster (on 32-bit Linux at least) as 'int'
+*/
+int lastpix, nextpix;
+/* int pdiff; */
+short pdiff;
+int v, fs, fsmask, top, fsmax, fsbits, bbits;
+int lbitbuffer, lbits_to_go;
+/* unsigned int psum; */
+unsigned short 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 = 2; */
+
+/* nblock = 32; now an input parameter */
+ /*
+ * 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);
+ }
+*/
+
+ /* move these out of switch block to further tweak performance */
+ fsbits = 4;
+ fsmax = 14;
+
+ 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 short value to the first 2 bytes of the buffer */
+ if (output_nbits(buffer, a[0], 16) == 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; */
+ psum = ((unsigned short) 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;
+ putcbuf(lbitbuffer & 0xff,buffer);
+ for (top -= lbits_to_go; top>=8; top -= 8) {
+ putcbuf(0, buffer);
+ }
+ 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) {
+ putcbuf((lbitbuffer>>(-lbits_to_go)) & 0xff,buffer);
+ lbits_to_go += 8;
+ }
+ }
+ }
+ /* check if overflowed output buffer */
+ if (buffer->current > buffer->end) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ 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);
+}
+/*---------------------------------------------------------------------------*/
+
+int fits_rcomp_byte(
+ signed char 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; */
+int i, j, thisblock;
+
+/*
+NOTE: in principle, the following 2 variable could be declared as 'short'
+but in fact the code runs faster (on 32-bit Linux at least) as 'int'
+*/
+int lastpix, nextpix;
+/* int pdiff; */
+signed char pdiff;
+int v, fs, fsmask, top, fsmax, fsbits, bbits;
+int lbitbuffer, lbits_to_go;
+/* unsigned int psum; */
+unsigned char 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 = 1; */
+
+/* nblock = 32; now an input parameter */
+ /*
+ * 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);
+ }
+*/
+
+ /* move these out of switch block to further tweak performance */
+ fsbits = 3;
+ fsmax = 6;
+ 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 byte value to the first byte of the buffer */
+ if (output_nbits(buffer, a[0], 8) == 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; */
+ psum = ((unsigned char) 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;
+ putcbuf(lbitbuffer & 0xff,buffer);
+ for (top -= lbits_to_go; top>=8; top -= 8) {
+ putcbuf(0, buffer);
+ }
+ 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) {
+ putcbuf((lbitbuffer>>(-lbits_to_go)) & 0xff,buffer);
+ lbits_to_go += 8;
+ }
+ }
+ }
+ /* check if overflowed output buffer */
+ if (buffer->current > buffer->end) {
+ ffpmsg("rice_encode: end of buffer");
+ free(diff);
+ return(-1);
+ }
+ 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;
+ /* AND mask for the right-most n bits */
+ static unsigned int mask[33] =
+ {0,
+ 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff,
+ 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff,
+ 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
+ 0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
+
+ /*
+ * 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); */
+ lbitbuffer |= (bits>>(n-lbits_to_go)) & *(mask+lbits_to_go);
+ putcbuf(lbitbuffer & 0xff,buffer);
+ n -= lbits_to_go;
+ lbits_to_go = 8;
+ }
+ lbitbuffer <<= n;
+/* lbitbuffer |= ( bits & ((1<<n)-1) ); */
+ lbitbuffer |= ( bits & *(mask+n) );
+ lbits_to_go -= n;
+ while (lbits_to_go <= 0) {
+ /*
+ * bitbuffer full, put out top 8 bits
+ */
+ putcbuf((lbitbuffer>>(-lbits_to_go)) & 0xff,buffer);
+ 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) {
+ putcbuf(buffer->bitbuffer<<buffer->bits_to_go,buffer);
+
+/* 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; */
+int 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; now an input parameter */
+ /*
+ * 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;
+ }
+*/
+
+ /* move out of switch block, to tweak performance */
+ fsbits = 5;
+ fsmax = 25;
+
+ bbits = 1<<fsbits;
+
+ FFLOCK;
+ 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");
+ FFUNLOCK;
+ return 1;
+ }
+ nzero = 8;
+ k = 128;
+ for (i=255; i>=0; ) {
+ for ( ; i>=k; i--) nonzero_count[i] = nzero;
+ k = k/2;
+ nzero--;
+ }
+ }
+ FFUNLOCK;
+
+ /*
+ * 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;
+}
+/*---------------------------------------------------------------------------*/
+/* this routine used to be called 'rdecomp' (WDP) */
+
+int fits_rdecomp_short (unsigned char *c, /* input buffer */
+ int clen, /* length of input */
+ unsigned short array[], /* output array */
+ int nx, /* number of output pixels */
+ int nblock) /* coding block size */
+{
+int i, imax;
+/* int bsize; */
+int k;
+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 = 2; */
+
+/* nblock = 32; now an input parameter */
+ /*
+ * 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;
+ }
+*/
+
+ /* move out of switch block, to tweak performance */
+ fsbits = 4;
+ fsmax = 14;
+
+ bbits = 1<<fsbits;
+
+ FFLOCK;
+ 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");
+ FFUNLOCK;
+ return 1;
+ }
+ nzero = 8;
+ k = 128;
+ for (i=255; i>=0; ) {
+ for ( ; i>=k; i--) nonzero_count[i] = nzero;
+ k = k/2;
+ nzero--;
+ }
+ }
+ FFUNLOCK;
+ /*
+ * Decode in blocks of nblock pixels
+ */
+
+ /* first 2 bytes of input buffer contain the value of the first */
+ /* 2 byte integer value, without any encoding */
+
+ lastpix = 0;
+ bytevalue = c[0];
+ lastpix = lastpix | (bytevalue<<8);
+ bytevalue = c[1];
+ lastpix = lastpix | bytevalue;
+
+ c += 2;
+ cend = c + clen - 2;
+
+ 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;
+}
+/*---------------------------------------------------------------------------*/
+/* this routine used to be called 'rdecomp' (WDP) */
+
+int fits_rdecomp_byte (unsigned char *c, /* input buffer */
+ int clen, /* length of input */
+ unsigned char array[], /* output array */
+ int nx, /* number of output pixels */
+ int nblock) /* coding block size */
+{
+int i, imax;
+/* int bsize; */
+int k;
+int nbits, nzero, fs;
+unsigned char *cend;
+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 = 1; */
+
+/* nblock = 32; now an input parameter */
+ /*
+ * 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;
+ }
+*/
+
+ /* move out of switch block, to tweak performance */
+ fsbits = 3;
+ fsmax = 6;
+
+ bbits = 1<<fsbits;
+
+ FFLOCK;
+ 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");
+ FFUNLOCK;
+ return 1;
+ }
+ nzero = 8;
+ k = 128;
+ for (i=255; i>=0; ) {
+ for ( ; i>=k; i--) nonzero_count[i] = nzero;
+ k = k/2;
+ nzero--;
+ }
+ }
+ FFUNLOCK;
+ /*
+ * Decode in blocks of nblock pixels
+ */
+
+ /* first byte of input buffer contain the value of the first */
+ /* byte integer value, without any encoding */
+
+ lastpix = c[0];
+ c += 1;
+ cend = c + clen - 1;
+
+ 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/vendor/cfitsio/sample.tpl b/vendor/cfitsio/sample.tpl
new file mode 100644
index 00000000..8cfca14e
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/scalnull.c b/vendor/cfitsio/scalnull.c
new file mode 100644
index 00000000..d2f2924e
--- /dev/null
+++ b/vendor/cfitsio/scalnull.c
@@ -0,0 +1,229 @@
+/* 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 */
+ LONGLONG 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 */
+ LONGLONG 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/vendor/cfitsio/smem.c b/vendor/cfitsio/smem.c
new file mode 100644
index 00000000..bf823701
--- /dev/null
+++ b/vendor/cfitsio/smem.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <memory.h>
+#include <string.h>
+#ifdef __APPLE__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+#include "fitsio.h" /* needed to define LONGLONG */
+#include "drvrsmem.h" /* uses LONGLONG */
+
+int main(int argc, char **argv)
+{ int cmdok, listmode, longlistmode, recovermode, deletemode, id;
+int status;
+char *address;
+
+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);
+
+for (id = 0; id <16; id++) {
+ status = shared_getaddr(id, &address);
+ if (!status)printf("id, status, address %d %d %ld %.30s\n", id, status, address, address);
+}
+return(0);
+}
diff --git a/vendor/cfitsio/speed.c b/vendor/cfitsio/speed.c
new file mode 100644
index 00000000..75fbf05d
--- /dev/null
+++ b/vendor/cfitsio/speed.c
@@ -0,0 +1,511 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/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;
+long startsec; /* start of elapsed time interval */
+int startmilli; /* start of elapsed time interval */
+
+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);
+int main(void);
+
+int 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 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 %4ld 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 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 %4ld 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;
+ struct timeval tv;
+ struct timezone tz;
+
+ 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.;
+
+ scpu = clock();
+ start = time(0);
+/*
+ while (telapse == 0.)
+ {
+ scpu = clock();
+ start = time(0);
+ telapse = difftime( start, temp );
+ }
+*/
+ gettimeofday (&tv, &tz);
+
+ startsec = tv.tv_sec;
+ startmilli = tv.tv_usec/1000;
+
+ return( *status );
+}
+/*--------------------------------------------------------------------------*/
+int gettime(double *elapse, float *elapscpu, int *status)
+{
+ struct timeval tv;
+ struct timezone tz;
+ int stopmilli;
+ long stopsec;
+
+
+ gettimeofday (&tv, &tz);
+ ecpu = clock();
+ finish = time(0);
+
+ stopmilli = tv.tv_usec/1000;
+ stopsec = tv.tv_sec;
+
+
+ *elapse = (stopsec - startsec) + (stopmilli - startmilli)/1000.;
+
+/* *elapse = difftime(finish, start) + 0.5; */
+ *elapscpu = (ecpu - scpu) * 1.0 / CLOCKTICKS;
+
+ return( *status );
+}
diff --git a/vendor/cfitsio/swapproc.c b/vendor/cfitsio/swapproc.c
new file mode 100644
index 00000000..cc69d6e6
--- /dev/null
+++ b/vendor/cfitsio/swapproc.c
@@ -0,0 +1,247 @@
+/* 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. */
+
+/* The fast SSE2 and SSSE3 functions were provided by Julian Taylor, ESO */
+
+#include <string.h>
+#include <stdlib.h>
+#include "fitsio2.h"
+
+/* bswap builtin is available since GCC 4.3 */
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+#define HAVE_BSWAP
+#endif
+
+#ifdef __SSSE3__
+#include <tmmintrin.h>
+/* swap 16 bytes according to mask, values must be 16 byte aligned */
+static inline void swap_ssse3(char * values, __m128i mask)
+{
+ __m128i v = _mm_load_si128((__m128i *)values);
+ __m128i s = _mm_shuffle_epi8(v, mask);
+ _mm_store_si128((__m128i*)values, s);
+}
+#endif
+#ifdef __SSE2__
+#include <emmintrin.h>
+/* swap 8 shorts, values must be 16 byte aligned
+ * faster than ssse3 variant for shorts */
+static inline void swap2_sse2(char * values)
+{
+ __m128i r1 = _mm_load_si128((__m128i *)values);
+ __m128i r2 = r1;
+ r1 = _mm_srli_epi16(r1, 8);
+ r2 = _mm_slli_epi16(r2, 8);
+ r1 = _mm_or_si128(r1, r2);
+ _mm_store_si128((__m128i*)values, r1);
+}
+/* the three shuffles required for 4 and 8 byte variants make
+ * SSE2 slower than bswap */
+
+
+/* get number of elements to peel to reach alignment */
+static inline size_t get_peel(void * addr, size_t esize, size_t nvals,
+ size_t alignment)
+{
+ const size_t offset = (size_t)addr % alignment;
+ size_t peel = offset ? (alignment - offset) / esize : 0;
+ peel = nvals < peel ? nvals : peel;
+ return peel;
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+static void ffswap2_slow(short *svalues, long nvals)
+{
+ register long ii;
+ unsigned short * usvalues;
+
+ usvalues = (unsigned short *) svalues;
+
+ for (ii = 0; ii < nvals; ii++)
+ {
+ usvalues[ii] = (usvalues[ii]>>8) | (usvalues[ii]<<8);
+ }
+}
+/*--------------------------------------------------------------------------*/
+#if __SSE2__
+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 )
+*/
+{
+ if ((long)svalues % 2 != 0) { /* should not happen */
+ ffswap2_slow(svalues, nvals);
+ return;
+ }
+
+ long ii;
+ size_t peel = get_peel((void*)&svalues[0], sizeof(svalues[0]), nvals, 16);
+
+ ffswap2_slow(svalues, peel);
+ for (ii = peel; ii < (nvals - peel - (nvals - peel) % 8); ii+=8) {
+ swap2_sse2((char*)&svalues[ii]);
+ }
+ ffswap2_slow(&svalues[ii], nvals - ii);
+}
+#else
+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 4-byte integer: ( 0 1 2 3 -> 3 2 1 0 )
+*/
+{
+ ffswap2_slow(svalues, nvals);
+}
+#endif
+/*--------------------------------------------------------------------------*/
+static void ffswap4_slow(INT32BIT *ivalues, long nvals)
+{
+ register long ii;
+
+#if defined(HAVE_BSWAP)
+ for (ii = 0; ii < nvals; ii++)
+ {
+ ivalues[ii] = __builtin_bswap32(ivalues[ii]);
+ }
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+ /* intrinsic byte swapping function in Microsoft Visual C++ 8.0 and later */
+ unsigned int* uivalues = (unsigned int *) ivalues;
+
+ /* intrinsic byte swapping function in Microsoft Visual C++ */
+ for (ii = 0; ii < nvals; ii++)
+ {
+ uivalues[ii] = _byteswap_ulong(uivalues[ii]);
+ }
+#else
+ char *cvalues, tmp;
+
+ for (ii = 0; ii < nvals; ii++)
+ {
+ cvalues = (char *)&ivalues[ii];
+ tmp = cvalues[0];
+ cvalues[0] = cvalues[3];
+ cvalues[3] = tmp;
+ tmp = cvalues[1];
+ cvalues[1] = cvalues[2];
+ cvalues[2] = tmp;
+ }
+#endif
+}
+/*--------------------------------------------------------------------------*/
+#ifdef __SSSE3__
+void ffswap4(INT32BIT *ivalues, /* IO - pointer to INT*4 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 )
+*/
+{
+ if ((long)ivalues % 4 != 0) { /* should not happen */
+ ffswap4_slow(ivalues, nvals);
+ return;
+ }
+
+ long ii;
+ const __m128i cmask4 = _mm_set_epi8(12, 13, 14, 15,
+ 8, 9, 10, 11,
+ 4, 5, 6, 7,
+ 0, 1, 2 ,3);
+ size_t peel = get_peel((void*)&ivalues[0], sizeof(ivalues[0]), nvals, 16);
+ ffswap4_slow(ivalues, peel);
+ for (ii = peel; ii < (nvals - peel - (nvals - peel) % 4); ii+=4) {
+ swap_ssse3((char*)&ivalues[ii], cmask4);
+ }
+ ffswap4_slow(&ivalues[ii], nvals - ii);
+}
+#else
+void ffswap4(INT32BIT *ivalues, /* IO - pointer to INT*4 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 )
+*/
+{
+ ffswap4_slow(ivalues, nvals);
+}
+#endif
+/*--------------------------------------------------------------------------*/
+static void ffswap8_slow(double *dvalues, long nvals)
+{
+ register long ii;
+#ifdef HAVE_BSWAP
+ LONGLONG * llvalues = (LONGLONG*)dvalues;
+
+ for (ii = 0; ii < nvals; ii++) {
+ llvalues[ii] = __builtin_bswap64(llvalues[ii]);
+ }
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+ /* intrinsic byte swapping function in Microsoft Visual C++ 8.0 and later */
+ unsigned __int64 * llvalues = (unsigned __int64 *) dvalues;
+
+ for (ii = 0; ii < nvals; ii++)
+ {
+ llvalues[ii] = _byteswap_uint64(llvalues[ii]);
+ }
+#else
+ register char *cvalues;
+ 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;
+ }
+#endif
+}
+/*--------------------------------------------------------------------------*/
+#ifdef __SSSE3__
+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 )
+*/
+{
+ if ((long)dvalues % 8 != 0) { /* should not happen on amd64 */
+ ffswap8_slow(dvalues, nvals);
+ return;
+ }
+
+ long ii;
+ const __m128i cmask8 = _mm_set_epi8(8, 9, 10, 11, 12, 13, 14, 15,
+ 0, 1, 2 ,3, 4, 5, 6, 7);
+ size_t peel = get_peel((void*)&dvalues[0], sizeof(dvalues[0]), nvals, 16);
+ ffswap8_slow(dvalues, peel);
+ for (ii = peel; ii < (nvals - peel - (nvals - peel) % 2); ii+=2) {
+ swap_ssse3((char*)&dvalues[ii], cmask8);
+ }
+ ffswap8_slow(&dvalues[ii], nvals - ii);
+}
+#else
+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 )
+*/
+{
+ ffswap8_slow(dvalues, nvals);
+}
+#endif
diff --git a/vendor/cfitsio/testf77.f b/vendor/cfitsio/testf77.f
new file mode 100644
index 00000000..ac3bc217
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/testf77.out b/vendor/cfitsio/testf77.out
new file mode 100644
index 00000000..14a0e7e5
--- /dev/null
+++ b/vendor/cfitsio/testf77.out
@@ -0,0 +1,746 @@
+ FITSIO TESTPROG, v 3.310
+
+ 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 98 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 98 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 98 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 98 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 99 99
+ F 0 0 -16
+ T 0 99 99
+ T 0 0 -18
+ T 0 99 99
+ T 0 0 -20
+ F 0 99 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/vendor/cfitsio/testf77.std b/vendor/cfitsio/testf77.std
new file mode 100644
index 00000000..24975a43
--- /dev/null
+++ b/vendor/cfitsio/testf77.std
Binary files differ
diff --git a/vendor/cfitsio/testprog.c b/vendor/cfitsio/testprog.c
new file mode 100644
index 00000000..5596f251
--- /dev/null
+++ b/vendor/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, cvalstr[2];
+ 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");
+ fits_open_file(&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 */
+ fits_free_memory(lsptr, &status);
+
+ /* 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], cvalstr, &repeat, &scale,
+ &zero, &jnulval, tdisp, &status);
+ printf(" %s, %s, %c, %ld, %f, %f, %ld, %s.\n",
+ ttype[0], tunit[0], cvalstr[0], 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/vendor/cfitsio/testprog.out b/vendor/cfitsio/testprog.out
new file mode 100644
index 00000000..3d6093fb
--- /dev/null
+++ b/vendor/cfitsio/testprog.out
@@ -0,0 +1,797 @@
+CFITSIO TESTPROG, v3.310
+
+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 98 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 98 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 98 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 98 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 99 99
+ 0 0 0 -16
+ 1 0 99 99
+ 1 0 0 -18
+ 1 0 99 99
+ 1 0 0 -20
+ 0 0 99 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/vendor/cfitsio/testprog.std b/vendor/cfitsio/testprog.std
new file mode 100644
index 00000000..c1a2db5f
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/testprog.tpt b/vendor/cfitsio/testprog.tpt
new file mode 100644
index 00000000..def9dcb2
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/trees.c b/vendor/cfitsio/trees.c
new file mode 100644
index 00000000..84361268
--- /dev/null
+++ b/vendor/cfitsio/trees.c
@@ -0,0 +1,1242 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2010 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local int detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (ush)val << s->bi_valid;\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (ush)(value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header,
+ "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (s->strm->data_type == Z_UNKNOWN)
+ s->strm->data_type = detect_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+last, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+last, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (last) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ * a) There are no non-portable control characters belonging to the
+ * "black list" (0..6, 14..25, 28..31).
+ * b) There is at least one printable character belonging to the
+ * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ * "gray list" that is ignored in this detection algorithm:
+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+ deflate_state *s;
+{
+ /* black_mask is the bit mask of black-listed bytes
+ * set bits 0..6, 14..25, and 28..31
+ * 0xf3ffc07f = binary 11110011111111111100000001111111
+ */
+ unsigned long black_mask = 0xf3ffc07fUL;
+ int n;
+
+ /* Check for non-textual ("black-listed") bytes. */
+ for (n = 0; n <= 31; n++, black_mask >>= 1)
+ if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+ return Z_BINARY;
+
+ /* Check for textual ("white-listed") bytes. */
+ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+ || s->dyn_ltree[13].Freq != 0)
+ return Z_TEXT;
+ for (n = 32; n < LITERALS; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ return Z_TEXT;
+
+ /* There are no "black-listed" or "white-listed" bytes:
+ * this stream either is empty or has tolerated ("gray-listed") bytes only.
+ */
+ return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/vendor/cfitsio/trees.h b/vendor/cfitsio/trees.h
new file mode 100644
index 00000000..d35639d8
--- /dev/null
+++ b/vendor/cfitsio/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/vendor/cfitsio/uncompr.c b/vendor/cfitsio/uncompr.c
new file mode 100644
index 00000000..769f83ee
--- /dev/null
+++ b/vendor/cfitsio/uncompr.c
@@ -0,0 +1,57 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/vendor/cfitsio/vmsieee.c b/vendor/cfitsio/vmsieee.c
new file mode 100644
index 00000000..5ddc7486
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/vmsieeed.mar b/vendor/cfitsio/vmsieeed.mar
new file mode 100644
index 00000000..f9928dda
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/vmsieeer.mar b/vendor/cfitsio/vmsieeer.mar
new file mode 100644
index 00000000..f3105880
--- /dev/null
+++ b/vendor/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/vendor/cfitsio/wcssub.c b/vendor/cfitsio/wcssub.c
new file mode 100644
index 00000000..afb8e5c6
--- /dev/null
+++ b/vendor/cfitsio/wcssub.c
@@ -0,0 +1,1043 @@
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "fitsio2.h"
+
+/*--------------------------------------------------------------------------*/
+int fits_read_wcstab(
+ fitsfile *fptr, /* I - FITS file pointer */
+ int nwtb, /* Number of arrays to be read from the binary table(s) */
+ wtbarr *wtb, /* Address of the first element of an array of wtbarr
+ typedefs. This wtbarr typedef is defined below to
+ match the wtbarr struct defined in WCSLIB. An array
+ of such structs returned by the WCSLIB function
+ wcstab(). */
+ int *status)
+
+/*
+* Author: Mark Calabretta, Australia Telescope National Facility
+* http://www.atnf.csiro.au/~mcalabre/index.html
+*
+* fits_read_wcstab() extracts arrays from a binary table required in
+* constructing -TAB coordinates. This helper routine is intended for
+* use by routines in the WCSLIB library when dealing with the -TAB table
+* look up WCS convention.
+*/
+
+{
+ int anynul, colnum, hdunum, iwtb, m, naxis, nostat;
+ long *naxes = 0, nelem;
+ wtbarr *wtbp;
+
+
+ if (*status) return *status;
+
+ if (fptr == 0) {
+ return (*status = NULL_INPUT_PTR);
+ }
+
+ if (nwtb == 0) return 0;
+
+ /* Zero the array pointers. */
+ wtbp = wtb;
+ for (iwtb = 0; iwtb < nwtb; iwtb++, wtbp++) {
+ *wtbp->arrayp = 0x0;
+ }
+
+ /* Save HDU number so that we can move back to it later. */
+ fits_get_hdu_num(fptr, &hdunum);
+
+ wtbp = wtb;
+ for (iwtb = 0; iwtb < nwtb; iwtb++, wtbp++) {
+ /* Move to the required binary table extension. */
+ if (fits_movnam_hdu(fptr, BINARY_TBL, (char *)(wtbp->extnam),
+ wtbp->extver, status)) {
+ goto cleanup;
+ }
+
+ /* Locate the table column. */
+ if (fits_get_colnum(fptr, CASEINSEN, (char *)(wtbp->ttype), &colnum,
+ status)) {
+ goto cleanup;
+ }
+
+ /* Get the array dimensions and check for consistency. */
+ if (wtbp->ndim < 1) {
+ *status = NEG_AXIS;
+ goto cleanup;
+ }
+
+ if (!(naxes = calloc(wtbp->ndim, sizeof(long)))) {
+ *status = MEMORY_ALLOCATION;
+ goto cleanup;
+ }
+
+ if (fits_read_tdim(fptr, colnum, wtbp->ndim, &naxis, naxes, status)) {
+ goto cleanup;
+ }
+
+ if (naxis != wtbp->ndim) {
+ if (wtbp->kind == 'c' && wtbp->ndim == 2) {
+ /* Allow TDIMn to be omitted for degenerate coordinate arrays. */
+ naxis = 2;
+ naxes[1] = naxes[0];
+ naxes[0] = 1;
+ } else {
+ *status = BAD_TDIM;
+ goto cleanup;
+ }
+ }
+
+ if (wtbp->kind == 'c') {
+ /* Coordinate array; calculate the array size. */
+ nelem = naxes[0];
+ for (m = 0; m < naxis-1; m++) {
+ *(wtbp->dimlen + m) = naxes[m+1];
+ nelem *= naxes[m+1];
+ }
+ } else {
+ /* Index vector; check length. */
+ if ((nelem = naxes[0]) != *(wtbp->dimlen)) {
+ /* N.B. coordinate array precedes the index vectors. */
+ *status = BAD_TDIM;
+ goto cleanup;
+ }
+ }
+
+ free(naxes);
+ naxes = 0;
+
+ /* Allocate memory for the array. */
+ if (!(*wtbp->arrayp = calloc((size_t)nelem, sizeof(double)))) {
+ *status = MEMORY_ALLOCATION;
+ goto cleanup;
+ }
+
+ /* Read the array from the table. */
+ if (fits_read_col_dbl(fptr, colnum, wtbp->row, 1L, nelem, 0.0,
+ *wtbp->arrayp, &anynul, status)) {
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ /* Move back to the starting HDU. */
+ nostat = 0;
+ fits_movabs_hdu(fptr, hdunum, 0, &nostat);
+
+ /* Release allocated memory. */
+ if (naxes) free(naxes);
+ if (*status) {
+ wtbp = wtb;
+ for (iwtb = 0; iwtb < nwtb; iwtb++, wtbp++) {
+ if (*wtbp->arrayp) free(*wtbp->arrayp);
+ }
+ }
+
+ return *status;
+}
+/*--------------------------------------------------------------------------*/
+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.
+
+ THIS ROUTINE IS DEPRECATED. USE fits_hdr2str INSTEAD
+*/
+{
+ 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 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 ffgicsa(fitsfile *fptr, /* I - FITS file pointer */
+ char version, /* I - character code of desired version *(/
+ /* A - Z or blank */
+ 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], keyname[FLEN_VALUE], alt[2];
+ 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);
+
+ if (version == ' ') {
+ ffgics(fptr, xrval, yrval, xrpix, yrpix, xinc, yinc, rot, type, status);
+ return (*status);
+ }
+
+ if (version > 'Z' || version < 'A') {
+ ffpmsg("ffgicsa: illegal WCS version code (must be A - Z or blank)");
+ return(*status = WCS_ERROR);
+ }
+
+ alt[0] = version;
+ alt[1] = '\0';
+
+ tstat = 0;
+ strcpy(keyname, "CRVAL1");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, xrval, NULL, &tstat))
+ *xrval = 0.;
+
+ tstat = 0;
+ strcpy(keyname, "CRVAL2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, yrval, NULL, &tstat))
+ *yrval = 0.;
+
+ tstat = 0;
+ strcpy(keyname, "CRPIX1");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, xrpix, NULL, &tstat))
+ *xrpix = 0.;
+
+ tstat = 0;
+ strcpy(keyname, "CRPIX2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, yrpix, NULL, &tstat))
+ *yrpix = 0.;
+
+ /* look for CDELTn first, then CDi_j keywords */
+ tstat = 0;
+ strcpy(keyname, "CDELT1");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, xinc, NULL, &tstat))
+ {
+ /* CASE 1: no CDELTn keyword, so look for the CD matrix */
+ tstat = 0;
+ strcpy(keyname, "CD1_1");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, &cd11, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ cd_exists = 1; /* found at least 1 CD_ keyword */
+
+ strcpy(keyname, "CD2_1");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, &cd21, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ cd_exists = 1; /* found at least 1 CD_ keyword */
+
+ strcpy(keyname, "CD1_2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, &cd12, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ cd_exists = 1; /* found at least 1 CD_ keyword */
+
+ strcpy(keyname, "CD2_2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, &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;
+ strcpy(keyname, "CDELT2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, yinc, NULL, &tstat))
+ *yinc = 1.;
+
+ tstat = 0;
+ strcpy(keyname, "CROTA2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, rot, NULL, &tstat))
+ *rot=0.;
+ }
+ }
+ else /* Case 2: CDELTn + optional PC matrix */
+ {
+ strcpy(keyname, "CDELT2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, yinc, NULL, &tstat))
+ *yinc = 1.;
+
+ tstat = 0;
+ strcpy(keyname, "CROTA2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, rot, NULL, &tstat))
+ {
+ *rot=0.;
+
+ /* no CROTA2 keyword, so look for the PC matrix */
+ tstat = 0;
+ strcpy(keyname, "PC1_1");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, &pc11, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ pc_exists = 1; /* found at least 1 PC_ keyword */
+
+ strcpy(keyname, "PC2_1");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, &pc21, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ pc_exists = 1; /* found at least 1 PC_ keyword */
+
+ strcpy(keyname, "PC1_2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, &pc12, NULL, &tstat))
+ tstat = 0; /* reset keyword not found error */
+ else
+ pc_exists = 1; /* found at least 1 PC_ keyword */
+
+ strcpy(keyname, "PC2_2");
+ strcat(keyname, alt);
+ if (ffgkyd(fptr, keyname, &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;
+ strcpy(keyname, "CTYPE1");
+ strcat(keyname, alt);
+ if (ffgkys(fptr, keyname, 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 */
+
+ *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. Do this by converting the
+ table to a temporary FITS image, then reading the keywords
+ from the image file.
+ These values may be used as input to the subroutines that
+ calculate celestial coordinates. (ffxypx, ffwldp)
+*/
+{
+ int colnum[2];
+ long naxes[2];
+ fitsfile *tptr;
+
+ if (*status > 0)
+ return(*status);
+
+ colnum[0] = xcol;
+ colnum[1] = ycol;
+ naxes[0] = 10;
+ naxes[1] = 10;
+
+ /* create temporary FITS file, in memory */
+ ffinit(&tptr, "mem://", status);
+
+ /* create a temporary image; the datatype and size are not important */
+ ffcrim(tptr, 32, 2, naxes, status);
+
+ /* now copy the relevant keywords from the table to the image */
+ fits_copy_pixlist2image(fptr, tptr, 9, 2, colnum, status);
+
+ /* write default WCS keywords, if they are not present */
+ fits_write_keys_histo(fptr, tptr, 2, colnum, status);
+
+ if (*status > 0)
+ return(*status);
+
+ /* read the WCS keyword values from the temporary image */
+ ffgics(tptr, xrval, yrval, xrpix, yrpix, xinc, yinc, rot, type, status);
+
+ if (*status > 0)
+ {
+ ffpmsg
+ ("ffgtcs could not find all the celestial coordinate keywords");
+ return(*status = NO_WCS_KEY);
+ }
+
+ /* delete the temporary file */
+ fits_delete_file(tptr, 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.
+
+ THIS ROUTINE IS DEPRECATED. USE fits_hdr2str INSTEAD
+*/
+{
+ 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/vendor/cfitsio/wcsutil.c b/vendor/cfitsio/wcsutil.c
new file mode 100644
index 00000000..394a0f04
--- /dev/null
+++ b/vendor/cfitsio/wcsutil.c
@@ -0,0 +1,503 @@
+#include <math.h>
+#include "fitsio2.h"
+#define D2R 0.01745329252
+#define TWOPI 6.28318530717959
+
+/*--------------------------------------------------------------------------*/
+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)
+
+/* This routine is based on the classic AIPS WCS routine.
+
+ It converts from pixel location to RA,Dec for 9 projective geometries:
+ "-CAR", "-SIN", "-TAN", "-ARC", "-NCP", "-GLS", "-MER", "-AIT" and "-STG".
+*/
+
+/*-----------------------------------------------------------------------*/
+/* routine to determine accurate position for pixel coordinates */
+/* returns 0 if successful otherwise: */
+/* 501 = angle too large for projection; */
+/* does: -CAR, -SIN, -TAN, -ARC, -NCP, -GLS, -MER, -AIT -STG projections*/
+/* 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;
+ double geo1, geo2, geo3;
+ double deps = 1.0e-5;
+ char *cptr;
+
+ if (*status > 0)
+ return(*status);
+
+/* Offset from ref pixel */
+ dx = (xpix-xrefpix) * xinc;
+ dy = (ypix-yrefpix) * yinc;
+
+/* Take out rotation */
+ cosr = cos(rot * D2R);
+ sinr = sin(rot * D2R);
+ if (rot != 0.0) {
+ temp = dx * cosr - dy * sinr;
+ dy = dy * cosr + dx * sinr;
+ dx = temp;
+ }
+
+/* convert to radians */
+ ra0 = xref * D2R;
+ dec0 = yref * D2R;
+
+ l = dx * D2R;
+ m = dy * D2R;
+ sins = l*l + m*m;
+ cos0 = cos(dec0);
+ sin0 = sin(dec0);
+
+ if (*type != '-') { /* unrecognized projection code */
+ return(*status = 504);
+ }
+
+ cptr = type + 1;
+
+ if (*cptr == 'C') { /* linear -CAR */
+ if (*(cptr + 1) != 'A' || *(cptr + 2) != 'R') {
+ return(*status = 504);
+ }
+ rat = ra0 + l;
+ dect = dec0 + m;
+
+ } else if (*cptr == 'T') { /* -TAN */
+ if ( !(*(cptr + 1) == 'A' && *(cptr + 2) == 'N') &&
+ !(*(cptr + 1) == 'P' && *(cptr + 2) == 'V') ) {
+ return(*status = 504);
+ }
+ 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) );
+
+ } else if (*cptr == 'S') {
+
+ if (*(cptr + 1) == 'I' && *(cptr + 2) == 'N') { /* -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;
+
+ } else if (*(cptr + 1) == 'T' && *(cptr + 2) == 'G') { /* -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;
+ } else {
+ return(*status = 504);
+ }
+
+ } else if (*cptr == 'A') {
+
+ if (*(cptr + 1) == 'R' && *(cptr + 2) == 'C') { /* 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);
+
+ } else if (*(cptr + 1) == 'I' && *(cptr + 2) == 'T') { /* -AIT Aitoff */
+ dt = yinc*cosr + xinc*sinr;
+ if (dt==0.0)
+ dt = 1.0;
+ dt = dt * D2R;
+ dy = yref * D2R;
+ 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 * D2R;
+ 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)) {
+ 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;
+ }
+ } else {
+ return(*status = 504);
+ }
+
+ } else if (*cptr == 'N') { /* -NCP North celestial pole*/
+ if (*(cptr + 1) != 'C' || *(cptr + 2) != 'P') {
+ return(*status = 504);
+ }
+ 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;
+
+ } else if (*cptr == 'G') { /* -GLS global sinusoid */
+ if (*(cptr + 1) != 'L' || *(cptr + 2) != 'S') {
+ return(*status = 504);
+ }
+ 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;
+
+ } else if (*cptr == 'M') { /* -MER mercator*/
+ if (*(cptr + 1) != 'E' || *(cptr + 2) != 'R') {
+ return(*status = 504);
+ }
+ dt = yinc * cosr + xinc * sinr;
+ if (dt==0.0) dt = 1.0;
+ dy = (yref/2.0 + 45.0) * D2R;
+ dx = dy + dt / 2.0 * D2R;
+ dy = log (tan (dy));
+ dx = log (tan (dx));
+ geo2 = dt * D2R / (dx - dy);
+ geo3 = geo2 * dy;
+ geo1 = cos (yref*D2R);
+ if (geo1<=0.0) geo1 = 1.0;
+ rat = l / geo1 + ra0;
+ if (fabs(rat - ra0) > TWOPI)
+ return(*status = 501);
+ dt = 0.0;
+ if (geo2!=0.0) dt = (m + geo3) / geo2;
+ dt = exp (dt);
+ dect = 2.0 * atan (dt) - TWOPI / 4.0;
+
+ } else {
+ return(*status = 504);
+ }
+
+ /* correct for RA rollover */
+ if (rat-ra0>TWOPI/2.0) rat = rat - TWOPI;
+ if (rat-ra0<-TWOPI/2.0) rat = rat + TWOPI;
+ if (rat < 0.0) rat += TWOPI;
+
+ /* convert to degrees */
+ *xpos = rat / D2R;
+ *ypos = dect / D2R;
+ return(*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)
+
+/* This routine is based on the classic AIPS WCS routine.
+
+ It converts from RA,Dec to pixel location to for 9 projective geometries:
+ "-CAR", "-SIN", "-TAN", "-ARC", "-NCP", "-GLS", "-MER", "-AIT" and "-STG".
+*/
+/*-----------------------------------------------------------------------*/
+/* routine to determine accurate pixel coordinates for an RA and Dec */
+/* returns 0 if successful otherwise: */
+/* 501 = angle too large for projection; */
+/* 502 = bad values */
+/* 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 deps=1.0e-5;
+ char *cptr;
+
+ if (*type != '-') { /* unrecognized projection code */
+ return(*status = 504);
+ }
+
+ cptr = type + 1;
+
+ 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;
+
+ /* Correct for rotation */
+ r = rot * D2R;
+ 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;
+
+ if (*cptr == 'C') { /* linear -CAR */
+ if (*(cptr + 1) != 'A' || *(cptr + 2) != 'R') {
+ return(*status = 504);
+ }
+
+ return(*status); /* done if linear */
+ }
+
+ /* Non linear position */
+ ra0 = xref * D2R;
+ dec0 = yref * D2R;
+ ra = xpos * D2R;
+ dec = ypos * D2R;
+
+ /* 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 */
+ if (*cptr == 'T') { /* -TAN tan */
+ if (*(cptr + 1) != 'A' || *(cptr + 2) != 'N') {
+ return(*status = 504);
+ }
+
+ 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);
+ }
+
+ } else if (*cptr == 'S') {
+
+ if (*(cptr + 1) == 'I' && *(cptr + 2) == 'N') { /* -SIN */
+ if (sint<0.0)
+ return(*status = 501);
+ m = sins * cos(dec0) - coss * sin(dec0) * cos(ra-ra0);
+
+ } else if (*(cptr + 1) == 'T' && *(cptr + 2) == 'G') { /* -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));
+
+ } else {
+ return(*status = 504);
+ }
+
+ } else if (*cptr == 'A') {
+
+ if (*(cptr + 1) == 'R' && *(cptr + 2) == 'C') { /* 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;
+
+ } else if (*(cptr + 1) == 'I' && *(cptr + 2) == 'T') { /* -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 * D2R;
+ dy = yref * D2R;
+ 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 * D2R;
+ 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;
+
+ } else {
+ return(*status = 504);
+ }
+
+ } else if (*cptr == 'N') { /* -NCP North celestial pole*/
+ if (*(cptr + 1) != 'C' || *(cptr + 2) != 'P') {
+ return(*status = 504);
+ }
+
+ if (dec0==0.0)
+ return(*status = 501); /* can't stand the equator */
+ else
+ m = (cos(dec0) - coss * cos(ra-ra0)) / sin(dec0);
+
+ } else if (*cptr == 'G') { /* -GLS global sinusoid */
+ if (*(cptr + 1) != 'L' || *(cptr + 2) != 'S') {
+ return(*status = 504);
+ }
+
+ 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;
+
+ } else if (*cptr == 'M') { /* -MER mercator*/
+ if (*(cptr + 1) != 'E' || *(cptr + 2) != 'R') {
+ return(*status = 504);
+ }
+
+ dt = yinc * cosr + xinc * sinr;
+ if (dt==0.0) dt = 1.0;
+ dy = (yref/2.0 + 45.0) * D2R;
+ dx = dy + dt / 2.0 * D2R;
+ dy = log (tan (dy));
+ dx = log (tan (dx));
+ geo2 = dt * D2R / (dx - dy);
+ geo3 = geo2 * dy;
+ geo1 = cos (yref*D2R);
+ 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;
+
+ } else {
+ return(*status = 504);
+ }
+
+ /* convert to degrees */
+ dx = l / D2R;
+ dy = m / D2R;
+
+ /* 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);
+}
diff --git a/vendor/cfitsio/winDumpExts.mak b/vendor/cfitsio/winDumpExts.mak
new file mode 100644
index 00000000..9534d733
--- /dev/null
+++ b/vendor/cfitsio/winDumpExts.mak
@@ -0,0 +1,191 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on winDumpExts.dsp
+!IF "$(CFG)" == ""
+CFG=Win32 Debug
+!MESSAGE No configuration specified. Defaulting to Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "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="Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "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)" == "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)" == "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)" == "Win32 Release" || "$(CFG)" == "Win32 Debug"
+SOURCE=.\winDumpExts.c
+
+"$(INTDIR)\winDumpExts.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/vendor/cfitsio/windumpexts.c b/vendor/cfitsio/windumpexts.c
new file mode 100644
index 00000000..c09a613b
--- /dev/null
+++ b/vendor/cfitsio/windumpexts.c
@@ -0,0 +1,502 @@
+/*
+ * 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++.
+ *----------------------------------------------------------------------
+ *
+ */
+
+#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);
+}
diff --git a/vendor/cfitsio/zcompress.c b/vendor/cfitsio/zcompress.c
new file mode 100644
index 00000000..b8d7e79f
--- /dev/null
+++ b/vendor/cfitsio/zcompress.c
@@ -0,0 +1,504 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+
+unsigned int GZBUFSIZE = 115200; /* 40 FITS blocks */
+int BUFFINCR = 28800; /* 10 FITS blocks */
+
+/* prototype for the following functions */
+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 disk file into memory. Fill whatever amount of memory has
+ already been allocated, then realloc more memory, using the supplied
+ input function, if necessary.
+*/
+{
+ int err, len;
+ char *filebuff;
+ z_stream d_stream; /* decompression stream */
+
+ if (*status > 0)
+ return(*status);
+
+ /* Allocate memory to hold compressed bytes read from the file. */
+ filebuff = (char*)malloc(GZBUFSIZE);
+ if (!filebuff) return(*status = 113); /* memory error */
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+ d_stream.next_out = (unsigned char*) *buffptr;
+ d_stream.avail_out = *buffsize;
+
+ /* Initialize the decompression. The argument (15+16) tells the
+ decompressor that we are to use the gzip algorithm */
+
+ err = inflateInit2(&d_stream, (15+16));
+ if (err != Z_OK) return(*status = 414);
+
+ /* loop through the file, reading a buffer and uncompressing it */
+ for (;;)
+ {
+ len = fread(filebuff, 1, GZBUFSIZE, diskfile);
+ if (ferror(diskfile)) {
+ inflateEnd(&d_stream);
+ free(filebuff);
+ return(*status = 414);
+ }
+
+ if (len == 0) break; /* no more data */
+
+ d_stream.next_in = (unsigned char*)filebuff;
+ d_stream.avail_in = len;
+
+ for (;;) {
+ /* uncompress as much of the input as will fit in the output */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+
+ if (err == Z_STREAM_END ) { /* We reached the end of the input */
+ break;
+ } else if (err == Z_OK ) {
+
+ if (!d_stream.avail_in) break; /* need more input */
+
+ /* need more space in output buffer */
+ if (mem_realloc) {
+ *buffptr = mem_realloc(*buffptr,*buffsize + BUFFINCR);
+ if (*buffptr == NULL){
+ inflateEnd(&d_stream);
+ free(filebuff);
+ return(*status = 414); /* memory allocation failed */
+ }
+
+ d_stream.avail_out = BUFFINCR;
+ d_stream.next_out = (unsigned char*) (*buffptr + *buffsize);
+ *buffsize = *buffsize + BUFFINCR;
+ } else { /* error: no realloc function available */
+ inflateEnd(&d_stream);
+ free(filebuff);
+ return(*status = 414);
+ }
+ } else { /* some other error */
+ inflateEnd(&d_stream);
+ free(filebuff);
+ return(*status = 414);
+ }
+ }
+
+ if (feof(diskfile)) break;
+
+ d_stream.next_out = (unsigned char*) (*buffptr + d_stream.total_out);
+ d_stream.avail_out = *buffsize - d_stream.total_out;
+ }
+
+ /* Set the output file size to be the total output data */
+ *filesize = d_stream.total_out;
+
+ free(filebuff); /* free temporary output data buffer */
+
+ err = inflateEnd(&d_stream); /* End the decompression */
+ if (err != Z_OK) return(*status = 414);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+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 in memory into memory. Fill whatever amount of memory has
+ already been allocated, then realloc more memory, using the supplied
+ input function, if necessary.
+*/
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ if (*status > 0)
+ return(*status);
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ /* Initialize the decompression. The argument (15+16) tells the
+ decompressor that we are to use the gzip algorithm */
+ err = inflateInit2(&d_stream, (15+16));
+ if (err != Z_OK) return(*status = 414);
+
+ d_stream.next_in = (unsigned char*)inmemptr;
+ d_stream.avail_in = inmemsize;
+
+ d_stream.next_out = (unsigned char*) *buffptr;
+ d_stream.avail_out = *buffsize;
+
+ for (;;) {
+ /* uncompress as much of the input as will fit in the output */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+
+ if (err == Z_STREAM_END) { /* We reached the end of the input */
+ break;
+ } else if (err == Z_OK ) { /* need more space in output buffer */
+
+ if (mem_realloc) {
+ *buffptr = mem_realloc(*buffptr,*buffsize + BUFFINCR);
+ if (*buffptr == NULL){
+ inflateEnd(&d_stream);
+ return(*status = 414); /* memory allocation failed */
+ }
+
+ d_stream.avail_out = BUFFINCR;
+ d_stream.next_out = (unsigned char*) (*buffptr + *buffsize);
+ *buffsize = *buffsize + BUFFINCR;
+
+ } else { /* error: no realloc function available */
+ inflateEnd(&d_stream);
+ return(*status = 414);
+ }
+ } else { /* some other error */
+ inflateEnd(&d_stream);
+ return(*status = 414);
+ }
+ }
+
+ /* Set the output file size to be the total output data */
+ if (filesize) *filesize = d_stream.total_out;
+
+ /* End the decompression */
+ err = inflateEnd(&d_stream);
+
+ if (err != Z_OK) return(*status = 414);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+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 another file.
+*/
+{
+ int err, len;
+ unsigned long bytes_out = 0;
+ char *infilebuff, *outfilebuff;
+ z_stream d_stream; /* decompression stream */
+
+ if (*status > 0)
+ return(*status);
+
+ /* Allocate buffers to hold compressed and uncompressed */
+ infilebuff = (char*)malloc(GZBUFSIZE);
+ if (!infilebuff) return(*status = 113); /* memory error */
+
+ outfilebuff = (char*)malloc(GZBUFSIZE);
+ if (!outfilebuff) return(*status = 113); /* memory error */
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_out = (unsigned char*) outfilebuff;
+ d_stream.avail_out = GZBUFSIZE;
+
+ /* Initialize the decompression. The argument (15+16) tells the
+ decompressor that we are to use the gzip algorithm */
+
+ err = inflateInit2(&d_stream, (15+16));
+ if (err != Z_OK) return(*status = 414);
+
+ /* loop through the file, reading a buffer and uncompressing it */
+ for (;;)
+ {
+ len = fread(infilebuff, 1, GZBUFSIZE, indiskfile);
+ if (ferror(indiskfile)) {
+ inflateEnd(&d_stream);
+ free(infilebuff);
+ free(outfilebuff);
+ return(*status = 414);
+ }
+
+ if (len == 0) break; /* no more data */
+
+ d_stream.next_in = (unsigned char*)infilebuff;
+ d_stream.avail_in = len;
+
+ for (;;) {
+ /* uncompress as much of the input as will fit in the output */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+
+ if (err == Z_STREAM_END ) { /* We reached the end of the input */
+ break;
+ } else if (err == Z_OK ) {
+
+ if (!d_stream.avail_in) break; /* need more input */
+
+ /* flush out the full output buffer */
+ if ((int)fwrite(outfilebuff, 1, GZBUFSIZE, outdiskfile) != GZBUFSIZE) {
+ inflateEnd(&d_stream);
+ free(infilebuff);
+ free(outfilebuff);
+ return(*status = 414);
+ }
+ bytes_out += GZBUFSIZE;
+ d_stream.next_out = (unsigned char*) outfilebuff;
+ d_stream.avail_out = GZBUFSIZE;
+
+ } else { /* some other error */
+ inflateEnd(&d_stream);
+ free(infilebuff);
+ free(outfilebuff);
+ return(*status = 414);
+ }
+ }
+
+ if (feof(indiskfile)) break;
+ }
+
+ /* write out any remaining bytes in the buffer */
+ if (d_stream.total_out > bytes_out) {
+ if ((int)fwrite(outfilebuff, 1, (d_stream.total_out - bytes_out), outdiskfile)
+ != (d_stream.total_out - bytes_out)) {
+ inflateEnd(&d_stream);
+ free(infilebuff);
+ free(outfilebuff);
+ return(*status = 414);
+ }
+ }
+
+ free(infilebuff); /* free temporary output data buffer */
+ free(outfilebuff); /* free temporary output data buffer */
+
+ err = inflateEnd(&d_stream); /* End the decompression */
+ if (err != Z_OK) return(*status = 414);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+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.
+*/
+{
+ int err;
+ z_stream c_stream; /* compression stream */
+
+ if (*status > 0)
+ return(*status);
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ /* Initialize the compression. The argument (15+16) tells the
+ compressor that we are to use the gzip algorythm.
+ Also use Z_BEST_SPEED for maximum speed with very minor loss
+ in compression factor. */
+ err = deflateInit2(&c_stream, Z_BEST_SPEED, Z_DEFLATED,
+ (15+16), 8, Z_DEFAULT_STRATEGY);
+
+ if (err != Z_OK) return(*status = 413);
+
+ c_stream.next_in = (unsigned char*)inmemptr;
+ c_stream.avail_in = inmemsize;
+
+ c_stream.next_out = (unsigned char*) *buffptr;
+ c_stream.avail_out = *buffsize;
+
+ for (;;) {
+ /* compress as much of the input as will fit in the output */
+ err = deflate(&c_stream, Z_FINISH);
+
+ if (err == Z_STREAM_END) { /* We reached the end of the input */
+ break;
+ } else if (err == Z_OK ) { /* need more space in output buffer */
+
+ if (mem_realloc) {
+ *buffptr = mem_realloc(*buffptr,*buffsize + BUFFINCR);
+ if (*buffptr == NULL){
+ deflateEnd(&c_stream);
+ return(*status = 413); /* memory allocation failed */
+ }
+
+ c_stream.avail_out = BUFFINCR;
+ c_stream.next_out = (unsigned char*) (*buffptr + *buffsize);
+ *buffsize = *buffsize + BUFFINCR;
+
+ } else { /* error: no realloc function available */
+ deflateEnd(&c_stream);
+ return(*status = 413);
+ }
+ } else { /* some other error */
+ deflateEnd(&c_stream);
+ return(*status = 413);
+ }
+ }
+
+ /* Set the output file size to be the total output data */
+ if (filesize) *filesize = c_stream.total_out;
+
+ /* End the compression */
+ err = deflateEnd(&c_stream);
+
+ if (err != Z_OK) return(*status = 413);
+
+ return(*status);
+}
+/*--------------------------------------------------------------------------*/
+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.
+*/
+{
+ int err;
+ unsigned long bytes_out = 0;
+ char *outfilebuff;
+ z_stream c_stream; /* compression stream */
+
+ if (*status > 0)
+ return(*status);
+
+ /* Allocate buffer to hold compressed bytes */
+ outfilebuff = (char*)malloc(GZBUFSIZE);
+ if (!outfilebuff) return(*status = 113); /* memory error */
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ /* Initialize the compression. The argument (15+16) tells the
+ compressor that we are to use the gzip algorythm.
+ Also use Z_BEST_SPEED for maximum speed with very minor loss
+ in compression factor. */
+ err = deflateInit2(&c_stream, Z_BEST_SPEED, Z_DEFLATED,
+ (15+16), 8, Z_DEFAULT_STRATEGY);
+
+ if (err != Z_OK) return(*status = 413);
+
+ c_stream.next_in = (unsigned char*)inmemptr;
+ c_stream.avail_in = inmemsize;
+
+ c_stream.next_out = (unsigned char*) outfilebuff;
+ c_stream.avail_out = GZBUFSIZE;
+
+ for (;;) {
+ /* compress as much of the input as will fit in the output */
+ err = deflate(&c_stream, Z_FINISH);
+
+ if (err == Z_STREAM_END) { /* We reached the end of the input */
+ break;
+ } else if (err == Z_OK ) { /* need more space in output buffer */
+
+ /* flush out the full output buffer */
+ if ((int)fwrite(outfilebuff, 1, GZBUFSIZE, outdiskfile) != GZBUFSIZE) {
+ deflateEnd(&c_stream);
+ free(outfilebuff);
+ return(*status = 413);
+ }
+ bytes_out += GZBUFSIZE;
+ c_stream.next_out = (unsigned char*) outfilebuff;
+ c_stream.avail_out = GZBUFSIZE;
+
+
+ } else { /* some other error */
+ deflateEnd(&c_stream);
+ free(outfilebuff);
+ return(*status = 413);
+ }
+ }
+
+ /* write out any remaining bytes in the buffer */
+ if (c_stream.total_out > bytes_out) {
+ if ((int)fwrite(outfilebuff, 1, (c_stream.total_out - bytes_out), outdiskfile)
+ != (c_stream.total_out - bytes_out)) {
+ deflateEnd(&c_stream);
+ free(outfilebuff);
+ return(*status = 413);
+ }
+ }
+
+ free(outfilebuff); /* free temporary output data buffer */
+
+ /* Set the output file size to be the total output data */
+ if (filesize) *filesize = c_stream.total_out;
+
+ /* End the compression */
+ err = deflateEnd(&c_stream);
+
+ if (err != Z_OK) return(*status = 413);
+
+ return(*status);
+}
diff --git a/vendor/cfitsio/zconf.h b/vendor/cfitsio/zconf.h
new file mode 100644
index 00000000..142c3305
--- /dev/null
+++ b/vendor/cfitsio/zconf.h
@@ -0,0 +1,426 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
+
+/* all linked symbols */
+# define _dist_code z__dist_code
+# define _length_code z__length_code
+# define _tr_align z__tr_align
+# define _tr_flush_block z__tr_flush_block
+# define _tr_init z__tr_init
+# define _tr_stored_block z__tr_stored_block
+# define _tr_tally z__tr_tally
+# define adler32 z_adler32
+# define adler32_combine z_adler32_combine
+# define adler32_combine64 z_adler32_combine64
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define crc32 z_crc32
+# define crc32_combine z_crc32_combine
+# define crc32_combine64 z_crc32_combine64
+# define deflate z_deflate
+# define deflateBound z_deflateBound
+# define deflateCopy z_deflateCopy
+# define deflateEnd z_deflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateInit_ z_deflateInit_
+# define deflateParams z_deflateParams
+# define deflatePrime z_deflatePrime
+# define deflateReset z_deflateReset
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateSetHeader z_deflateSetHeader
+# define deflateTune z_deflateTune
+# define deflate_copyright z_deflate_copyright
+# define get_crc_table z_get_crc_table
+# define gz_error z_gz_error
+# define gz_intmax z_gz_intmax
+# define gz_strwinerror z_gz_strwinerror
+# define gzbuffer z_gzbuffer
+# define gzclearerr z_gzclearerr
+# define gzclose z_gzclose
+# define gzclose_r z_gzclose_r
+# define gzclose_w z_gzclose_w
+# define gzdirect z_gzdirect
+# define gzdopen z_gzdopen
+# define gzeof z_gzeof
+# define gzerror z_gzerror
+# define gzflush z_gzflush
+# define gzgetc z_gzgetc
+# define gzgets z_gzgets
+# define gzoffset z_gzoffset
+# define gzoffset64 z_gzoffset64
+# define gzopen z_gzopen
+# define gzopen64 z_gzopen64
+# define gzprintf z_gzprintf
+# define gzputc z_gzputc
+# define gzputs z_gzputs
+# define gzread z_gzread
+# define gzrewind z_gzrewind
+# define gzseek z_gzseek
+# define gzseek64 z_gzseek64
+# define gzsetparams z_gzsetparams
+# define gztell z_gztell
+# define gztell64 z_gztell64
+# define gzungetc z_gzungetc
+# define gzwrite z_gzwrite
+# define inflate z_inflate
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define inflateBackInit_ z_inflateBackInit_
+# define inflateCopy z_inflateCopy
+# define inflateEnd z_inflateEnd
+# define inflateGetHeader z_inflateGetHeader
+# define inflateInit2_ z_inflateInit2_
+# define inflateInit_ z_inflateInit_
+# define inflateMark z_inflateMark
+# define inflatePrime z_inflatePrime
+# define inflateReset z_inflateReset
+# define inflateReset2 z_inflateReset2
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateUndermine z_inflateUndermine
+# define inflate_copyright z_inflate_copyright
+# define inflate_fast z_inflate_fast
+# define inflate_table z_inflate_table
+# define uncompress z_uncompress
+# define zError z_zError
+# define zcalloc z_zcalloc
+# define zcfree z_zcfree
+# define zlibCompileFlags z_zlibCompileFlags
+# define zlibVersion z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+# define Byte z_Byte
+# define Bytef z_Bytef
+# define alloc_func z_alloc_func
+# define charf z_charf
+# define free_func z_free_func
+# define gzFile z_gzFile
+# define gz_header z_gz_header
+# define gz_headerp z_gz_headerp
+# define in_func z_in_func
+# define intf z_intf
+# define out_func z_out_func
+# define uInt z_uInt
+# define uIntf z_uIntf
+# define uLong z_uLong
+# define uLongf z_uLongf
+# define voidp z_voidp
+# define voidpc z_voidpc
+# define voidpf z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+# define gz_header_s z_gz_header_s
+# define internal_state z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if !defined(MSDOS) && !defined(WINDOWS) && !defined(WIN32)
+# define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef STDC
+# include <sys/types.h> /* for off_t */
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if -_LARGEFILE64_SOURCE - -1 == 1
+# undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# ifndef z_off_t
+# define z_off_t off_t
+# endif
+#endif
+
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+# define z_off64_t off64_t
+#else
+# define z_off64_t z_off_t
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+ #pragma map(deflateInit_,"DEIN")
+ #pragma map(deflateInit2_,"DEIN2")
+ #pragma map(deflateEnd,"DEEND")
+ #pragma map(deflateBound,"DEBND")
+ #pragma map(inflateInit_,"ININ")
+ #pragma map(inflateInit2_,"ININ2")
+ #pragma map(inflateEnd,"INEND")
+ #pragma map(inflateSync,"INSY")
+ #pragma map(inflateSetDictionary,"INSEDI")
+ #pragma map(compressBound,"CMBND")
+ #pragma map(inflate_table,"INTABL")
+ #pragma map(inflate_fast,"INFA")
+ #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/vendor/cfitsio/zlib.h b/vendor/cfitsio/zlib.h
new file mode 100644
index 00000000..bfbba83e
--- /dev/null
+++ b/vendor/cfitsio/zlib.h
@@ -0,0 +1,1613 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.5, April 19th, 2010
+
+ Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.5"
+#define ZLIB_VERNUM 0x1250
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 5
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed data.
+ This version of the library supports only one compression method (deflation)
+ but other algorithms will be added later and will have the same stream
+ interface.
+
+ Compression can be done in a single step if the buffers are large enough,
+ or can be done by repeated calls of the compression function. In the latter
+ case, the application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never crash
+ even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has dropped
+ to zero. It must update next_out and avail_out when avail_out has dropped
+ to zero. The application must initialize zalloc, zfree and opaque before
+ calling the init function. All other fields are set by the compression
+ library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this if
+ the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers
+ returned by zalloc for objects of exactly 65536 bytes *must* have their
+ offset normalized to zero. The default allocation function provided by this
+ library ensures this (see zutil.c). To reduce memory requirements and avoid
+ any allocation of 64K objects, at the expense of compression ratio, compile
+ the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or progress
+ reports. After compression, total_in holds the total size of the
+ uncompressed data and may be saved for use in the decompressor (particularly
+ if the decompressor wants to decompress everything in a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+#define Z_TREES 6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is not
+ compatible with the zlib.h header file used by the application. This check
+ is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+ allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at all
+ (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION
+ requests a default compromise between speed and compression (currently
+ equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if level is not a valid compression level, or
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION). msg is set to null
+ if there is no error message. deflateInit does not perform any compression:
+ this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications). Some
+ output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating avail_in or avail_out accordingly; avail_out should
+ never be zero before the call. The application can consume the compressed
+ output when it wants, for example when the output buffer is full (avail_out
+ == 0), or after each call of deflate(). If deflate returns Z_OK and with
+ zero avail_out, it must be called again after making room in the output
+ buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumulate before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In
+ particular avail_in is zero after the call if enough output space has been
+ provided before the call.) Flushing may degrade compression for some
+ compression algorithms and so it should be used only when necessary. This
+ completes the current deflate block and follows it with an empty stored block
+ that is three bits plus filler bits to the next byte, followed by four bytes
+ (00 00 ff ff).
+
+ If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+ output buffer, but the output is not aligned to a byte boundary. All of the
+ input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+ This completes the current deflate block and follows it with an empty fixed
+ codes block that is 10 bits long. This assures that enough bytes are output
+ in order for the decompressor to finish the block before the empty fixed code
+ block.
+
+ If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+ for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+ seven bits of the current block are held to be written as the next byte after
+ the next deflate block is completed. In this case, the decompressor may not
+ be provided enough bits at this point in order to complete decompression of
+ the data provided so far to the compressor. It may need to wait for the next
+ block to be emitted. This is for advanced applications that need to control
+ the emission of deflate blocks.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there was
+ enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the stream
+ are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least the
+ value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect the
+ compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case, msg
+ may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the
+ exact value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit() does not process any header information -- that is deferred
+ until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing will
+ resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there is
+ no more input data or no more space in the output buffer (see below about
+ the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating the next_* and avail_* values accordingly. The
+ application can consume the uncompressed output when it wants, for example
+ when the output buffer is full (avail_out == 0), or after each call of
+ inflate(). If inflate returns Z_OK and with zero avail_out, it must be
+ called again after making room in the output buffer because there might be
+ more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+ Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate()
+ stop if and when it gets to the next deflate block boundary. When decoding
+ the zlib or gzip format, this will cause inflate() to return immediately
+ after the header and before the first block. When doing a raw inflate,
+ inflate() will go ahead and process the first block, and will return when it
+ gets to the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64 if
+ inflate() is currently decoding the last block in the deflate stream, plus
+ 128 if inflate() returned immediately after decoding an end-of-block code or
+ decoding the complete header up to just before the first byte of the deflate
+ stream. The end-of-block will not be indicated until all of the uncompressed
+ data from that block has been written to strm->next_out. The number of
+ unused bits may in general be greater than seven, except when bit 7 of
+ data_type is set, in which case the number of unused bits will be less than
+ eight. data_type is set as noted here every time inflate() returns for all
+ flush options, and so can be used to determine the amount of currently
+ consumed input in bits.
+
+ The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+ end of each deflate block header is reached, before any actual data in that
+ block is decoded. This allows the caller to determine the length of the
+ deflate block header for later use in random access within a deflate block.
+ 256 is added to the value of strm->data_type when inflate() returns
+ immediately after reaching the end of the deflate block header.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step (a
+ single call of inflate), the parameter flush should be set to Z_FINISH. In
+ this case all pending input is processed and all pending output is flushed;
+ avail_out must be large enough to hold all the uncompressed data. (The size
+ of the uncompressed data may have been saved by the compressor for this
+ purpose.) The next operation on this stream must be inflateEnd to deallocate
+ the decompression state. The use of Z_FINISH is never required, but can be
+ used to inform inflate that a faster approach may be used for the single
+ inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK or Z_TREES is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically, if requested when
+ initializing with inflateInit2(). Any information contained in the gzip
+ header is not retained, so applications that need that information should
+ instead use raw inflate, see inflateInit2() below, or inflateBack() and
+ perform their own processing of the gzip header and trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may
+ then call inflateSync() to look for a good compression block if a partial
+ recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by the
+ caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero), no
+ header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but is
+ slow and reduces compression ratio; memLevel=9 uses maximum memory for
+ optimal speed. The default value is 8. See zconf.h for total memory usage
+ as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as
+ fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The
+ strategy parameter only affects the compression ratio but not the
+ correctness of the compressed output even if it is not set appropriately.
+ Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+ decoder for special applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+ method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+ incompatible with the version assumed by the caller (ZLIB_VERSION). msg is
+ set to null if there is no error message. deflateInit2 does not perform any
+ compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any call
+ of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size
+ provided in deflateInit or deflateInit2. Thus the strings most likely to be
+ useful should be put at the end of the dictionary, not at the front. In
+ addition, the current implementation of deflate will use at most the window
+ size minus 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and can
+ consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state. The
+ stream will keep the same compression level and any other attributes that
+ may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different strategy.
+ If the compression level is changed, the input available so far is
+ compressed with the old level (and may be flushed); the new level will take
+ effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to be
+ compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+ strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit() or
+ deflateInit2(), and after deflateSetHeader(), if used. This would be used
+ to allocate an output buffer for deflation in a single pass, and so would be
+ called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the bits
+ leftover from a previous deflate stream when appending to it. As such, this
+ function can only be used for raw deflate, and must be used before the first
+ deflate() call after a deflateInit2() or deflateReset(). bits must be less
+ than or equal to 16, and that many of the least significant bits of value
+ will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be zero to request that inflate use the window size in
+ the zlib header of the compressed stream.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a
+ crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit2 does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit2() does not process any header information -- that is
+ deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been
+ found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the
+ success case, the application may save the current current value of total_in
+ which indicates where valid compressed data was found. In the error case,
+ the application may repeatedly call inflateSync, providing more input each
+ time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state. The
+ stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+ int windowBits));
+/*
+ This function is the same as inflateReset, but it also permits changing
+ the wrap and window size requests. The windowBits parameter is interpreted
+ the same as it is for inflateInit2.
+
+ inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+ the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ If bits is negative, then the input stream bit buffer is emptied. Then
+ inflatePrime() can be called again to put bits in the buffer. This is used
+ to clear out bits leftover after feeding inflate a block description prior
+ to feeding inflate codes.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+ This function returns two values, one in the lower 16 bits of the return
+ value, and the other in the remaining upper bits, obtained by shifting the
+ return value down 16 bits. If the upper value is -1 and the lower value is
+ zero, then inflate() is currently decoding information outside of a block.
+ If the upper value is -1 and the lower value is non-zero, then inflate is in
+ the middle of a stored block, with the lower value equaling the number of
+ bytes from the input remaining to copy. If the upper value is not -1, then
+ it is the number of bits back from the current bit position in the input of
+ the code (literal or length/distance pair) currently being processed. In
+ that case the lower value is the number of bytes already emitted for that
+ code.
+
+ A code is being processed if inflate is waiting for more input to complete
+ decoding of the code, or if it has completed decoding but is waiting for
+ more output space to write the literal or match data.
+
+ inflateMark() is used to mark locations in the input data for random
+ access, which may be at bit positions, and to note those cases where the
+ output of a code may span boundaries of random access blocks. The current
+ location in the input stream can be determined from avail_in and data_type
+ as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+ inflateMark returns the value noted above or -1 << 16 if the provided
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be
+ used to force inflate() to return immediately after header processing is
+ complete and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When any
+ of extra, name, or comment are not Z_NULL and the respective field is not
+ present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not be
+ allocated, or Z_VERSION_ERROR if the version of the library does not match
+ the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free the
+ allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects only
+ the raw deflate stream to decompress. This is different from the normal
+ behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+ in the deflate stream (in which case strm->msg is set to indicate the nature
+ of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+ In the case of Z_BUF_ERROR, an input or output error can be distinguished
+ using strm->next_in which will be Z_NULL only if in() returned an error. If
+ strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+ non-zero. (in() will always be called before out(), so strm->next_in is
+ assured to be defined if out() returns non-zero.) Note that inflateBack()
+ cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the basic
+ stream-oriented functions. To simplify the interface, some default options
+ are assumed (compression level and memory usage, standard memory allocation
+ functions). The source code of these utility functions can be modified if
+ you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before a
+ compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be large enough to hold the entire
+ uncompressed data. (The size of the uncompressed data must have been saved
+ previously by the compressor and transmitted to the decompressor by some
+ mechanism outside the scope of this compression library.) Upon exit, destLen
+ is the actual size of the uncompressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+ /* gzip file access functions */
+
+/*
+ This library supports reading and writing files in gzip (.gz) format with
+ an interface similar to that of stdio, using the functions that start with
+ "gz". The gzip format is different from the zlib format. gzip is a gzip
+ wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef voidp gzFile; /* opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+ Opens a gzip (.gz) file for reading or writing. The mode parameter is as
+ in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+ a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+ compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+ for fixed code compression as in "wb9F". (See the description of
+ deflateInit2 for more information about the strategy parameter.) Also "a"
+ can be used instead of "w" to request that the gzip stream that will be
+ written be appended to the file. "+" will result in an error, since reading
+ and writing to the same gzip file is not supported.
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened, if there was
+ insufficient memory to allocate the gzFile state, or if an invalid mode was
+ specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+ errno can be checked to determine if the reason gzopen failed was that the
+ file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen associates a gzFile with the file descriptor fd. File descriptors
+ are obtained from calls like open, dup, creat, pipe or fileno (if the file
+ has been previously opened with fopen). The mode parameter is as in gzopen.
+
+ The next call of gzclose on the returned gzFile will also close the file
+ descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+ fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+ mode);. The duplicated descriptor should be saved to avoid a leak, since
+ gzdopen does not close fd if it fails.
+
+ gzdopen returns NULL if there was insufficient memory to allocate the
+ gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+ provided, or '+' was provided), or if fd is -1. The file descriptor is not
+ used until the next gz* read, write, seek, or close operation, so gzdopen
+ will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+ Set the internal buffer size used by this library's functions. The
+ default buffer size is 8192 bytes. This function must be called after
+ gzopen() or gzdopen(), and before any other calls that read or write the
+ file. The buffer memory allocation is always deferred to the first read or
+ write. Two buffers are allocated, either both of the specified size when
+ writing, or one of the specified size and the other twice that size when
+ reading. A larger buffer size of, for example, 64K or 128K bytes will
+ noticeably increase the speed of decompression (reading).
+
+ The new buffer size also affects the maximum length for gzprintf().
+
+ gzbuffer() returns 0 on success, or -1 on failure, such as being called
+ too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file. If
+ the input file was not in gzip format, gzread copies the given number of
+ bytes into the buffer.
+
+ After reaching the end of a gzip stream in the input, gzread will continue
+ to read, looking for another gzip stream, or failing that, reading the rest
+ of the input file directly without decompression. The entire input file
+ will be read if gzread is called until it returns less than the requested
+ len.
+
+ gzread returns the number of uncompressed bytes actually read, less than
+ len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes written or 0 in case of
+ error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the arguments to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written, or 0 in case of error. The number of
+ uncompressed bytes written is limited to 8191, or one less than the buffer
+ size given to gzbuffer(). The caller should assure that this limit is not
+ exceeded. If it is exceeded, then gzprintf() will return an error (0) with
+ nothing written. In this case, there may also be a buffer overflow with
+ unpredictable consequences, which is possible only if zlib was compiled with
+ the insecure functions sprintf() or vsprintf() because the secure snprintf()
+ or vsnprintf() functions were not available. This can be determined using
+ zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or a
+ newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. If any characters are read or if len == 1, the
+ string is terminated with a null character. If no characters are read due
+ to an end-of-file or len < 1, then the buffer is left untouched.
+
+ gzgets returns buf which is a null-terminated string, or it returns NULL
+ for end-of-file or in case of error. If there was an error, the contents at
+ buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file. gzputc
+ returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte or -1
+ in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read as the first character
+ on the next read. At least one character of push-back is allowed.
+ gzungetc() returns the character pushed, or -1 on failure. gzungetc() will
+ fail if c is -1, and may fail if a character has been pushed but not read
+ yet. If gzungetc is used immediately after gzopen or gzdopen, at least the
+ output buffer size of pushed characters is allowed. (See gzbuffer above.)
+ The pushed character will be discarded if the stream is repositioned with
+ gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter flush
+ is as in the deflate() function. The return value is the zlib error number
+ (see function gzerror below). gzflush is only permitted when writing.
+
+ If the flush parameter is Z_FINISH, the remaining data is written and the
+ gzip stream is completed in the output. If gzwrite() is called again, a new
+ gzip stream will be started in the output. gzread() is able to read such
+ concatented gzip streams.
+
+ gzflush should be called only when strictly necessary because it will
+ degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+
+ Returns the starting position for the next gzread or gzwrite on the given
+ compressed file. This position represents a number of bytes in the
+ uncompressed data stream, and is zero when starting, even if appending or
+ reading a gzip stream from the middle of a file using gzdopen().
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+ Returns the current offset in the file being read or written. This offset
+ includes the count of bytes that precede the gzip stream, for example when
+ appending or when using gzdopen() for reading. When reading, the offset
+ does not include as yet unused buffered input. This information can be used
+ for a progress indicator. On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns true (1) if the end-of-file indicator has been set while reading,
+ false (0) otherwise. Note that the end-of-file indicator is set only if the
+ read tried to go past the end of the input, but came up short. Therefore,
+ just like feof(), gzeof() may return false even if there is no more data to
+ read, in the event that the last read request was for the exact number of
+ bytes remaining in the input file. This will happen if the input file size
+ is an exact multiple of the buffer size.
+
+ If gzeof() returns true, then the read functions will return no more data,
+ unless the end-of-file indicator is reset by gzclearerr() and the input file
+ has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns true (1) if file is being copied directly while reading, or false
+ (0) if file is a gzip stream being decompressed. This state can change from
+ false to true while reading the input file if the end of a gzip stream is
+ reached, but is followed by data that is not another gzip stream.
+
+ If the input file is empty, gzdirect() will return true, since the input
+ does not contain a gzip stream.
+
+ If gzdirect() is used immediately after gzopen() or gzdopen() it will
+ cause buffers to be allocated to allow reading the file to determine if it
+ is a gzip file. Therefore if gzbuffer() is used, it should be called before
+ gzdirect().
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file and
+ deallocates the (de)compression state. Note that once file is closed, you
+ cannot call gzerror with file, since its structures have been deallocated.
+ gzclose must not be called more than once on the same file, just as free
+ must not be called more than once on the same allocation.
+
+ gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+ file operation error, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+ Same as gzclose(), but gzclose_r() is only for use when reading, and
+ gzclose_w() is only for use when writing or appending. The advantage to
+ using these instead of gzclose() is that they avoid linking in zlib
+ compression or decompression code that is not used when only reading or only
+ writing respectively. If gzclose() is used, then both compression and
+ decompression code will be included the application when linking to a static
+ zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the given
+ compressed file. errnum is set to zlib error number. If an error occurred
+ in the file system and not in the compression library, errnum is set to
+ Z_ERRNO and the application may consult errno to get the exact error code.
+
+ The application must not modify the returned string. Future calls to
+ this function may invalidate the previously returned string. If file is
+ closed, then the string previously returned by gzerror will no longer be
+ available.
+
+ gzerror() should be used to distinguish errors from end-of-file for those
+ functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the compression
+ library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is Z_NULL, this function returns the
+ required initial value for the checksum.
+
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster.
+
+ Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is Z_NULL, this function returns the required
+ initial value for the for the crc. Pre- and post-conditioning (one's
+ complement) is performed within this function so it shouldn't be done by the
+ application.
+
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0
+# define gzopen gzopen64
+# define gzseek gzseek64
+# define gztell gztell64
+# define gzoffset gzoffset64
+# define adler32_combine adler32_combine64
+# define crc32_combine crc32_combine64
+# ifdef _LARGEFILE64_SOURCE
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+# endif
+#else
+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/vendor/cfitsio/zuncompress.c b/vendor/cfitsio/zuncompress.c
new file mode 100644
index 00000000..c73ee6de
--- /dev/null
+++ b/vendor/cfitsio/zuncompress.c
@@ -0,0 +1,603 @@
+/* gzcompress.h -- definitions for the .Z decompression routine used in CFITSIO */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#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;
+
+/* private version of MIN function */
+#define MINZIP(a,b) ((a) <= (b) ? (a) : (b))
+
+/* Return codes from gzip */
+#define OK 0
+#define ERROR 1
+#define COMPRESSED 1
+#define DEFLATED 8
+#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 LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
+
+/* 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 fill_inbuf OF((int eof_ok));
+local void write_buf OF((voidp buf, unsigned cnt));
+local void error OF((char *m));
+local int unlzw OF((FILE *in, FILE *out));
+
+typedef int file_t; /* Do not use stdio */
+
+int (*work) OF((FILE *infile, FILE *outfile)) = unlzw; /* function to call */
+
+local void error OF((char *m));
+
+ /* global buffers */
+
+static DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
+static DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+static DECLARE(ush, d_buf, DIST_BUFSIZE);
+static DECLARE(uch, window, 2L*WSIZE);
+
+#ifndef MAXSEG_64K
+ static DECLARE(ush, tab_prefix, 1L<<BITS);
+#else
+ static DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
+ static DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
+#endif
+
+ /* local variables */
+
+/* 11/25/98: added 'static' to local variable definitions, to avoid */
+/* conflict with external source files */
+
+static int maxbits = BITS; /* max bits per code for LZW */
+static int method = DEFLATED;/* compression method */
+static int exit_code = OK; /* program exit code */
+static int last_member; /* set for .zip and .Z files */
+static long bytes_in; /* number of input bytes */
+static long bytes_out; /* number of output bytes */
+static char ifname[128]; /* input file name */
+static FILE *ifd; /* input file descriptor */
+static FILE *ofd; /* output file descriptor */
+static void **memptr; /* memory location for uncompressed file */
+static size_t *memsize; /* size (bytes) of memory allocated for file */
+void *(*realloc_fn)(void *p, size_t newsize); /* reallocation function */
+static unsigned insize; /* valid bytes in inbuf */
+static unsigned inptr; /* index of next byte to be processed in inbuf */
+
+/* prototype for the following functions */
+int zuncompress2mem(char *filename,
+ FILE *diskfile,
+ char **buffptr,
+ size_t *buffsize,
+ void *(*mem_realloc)(void *p, size_t newsize),
+ size_t *filesize,
+ int *status);
+
+/*--------------------------------------------------------------------------*/
+int zuncompress2mem(char *filename, /* name of input file */
+ FILE *indiskfile, /* 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.
+*/
+{
+ char magic[2]; /* magic header */
+
+ if (*status > 0)
+ return(*status);
+
+ /* save input parameters into global variables */
+ ifname[0] = '\0';
+ strncat(ifname, filename, 127);
+ ifd = indiskfile;
+ memptr = (void **) buffptr;
+ memsize = buffsize;
+ realloc_fn = mem_realloc;
+
+ /* clear input and output buffers */
+
+ insize = inptr = 0;
+ bytes_in = bytes_out = 0L;
+
+ magic[0] = (char)get_byte();
+ magic[1] = (char)get_byte();
+
+ if (memcmp(magic, LZW_MAGIC, 2) != 0) {
+ error("ERROR: input .Z file is in unrecognized compression format.\n");
+ return(-1);
+ }
+
+ work = unlzw;
+ method = COMPRESSED;
+ last_member = 1;
+
+ /* do the uncompression */
+ if ((*work)(ifd, ofd) != OK) {
+ method = -1; /* force cleanup */
+ *status = 414; /* report some sort of decompression error */
+ }
+
+ if (filesize) *filesize = bytes_out;
+
+ return(*status);
+}
+/*=========================================================================*/
+/*=========================================================================*/
+/* this marks the begining of the original file 'unlzw.c' */
+/*=========================================================================*/
+/*=========================================================================*/
+
+/* unlzw.c -- decompress files in LZW format.
+ * The code in this file is directly derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ */
+
+typedef unsigned char char_type;
+typedef long code_int;
+typedef unsigned long count_int;
+typedef unsigned short count_short;
+typedef unsigned long cmp_code_int;
+
+#define MAXCODE(n) (1L << (n))
+
+#ifndef REGISTERS
+# define REGISTERS 2
+#endif
+#define REG1
+#define REG2
+#define REG3
+#define REG4
+#define REG5
+#define REG6
+#define REG7
+#define REG8
+#define REG9
+#define REG10
+#define REG11
+#define REG12
+#define REG13
+#define REG14
+#define REG15
+#define REG16
+#if REGISTERS >= 1
+# undef REG1
+# define REG1 register
+#endif
+#if REGISTERS >= 2
+# undef REG2
+# define REG2 register
+#endif
+#if REGISTERS >= 3
+# undef REG3
+# define REG3 register
+#endif
+#if REGISTERS >= 4
+# undef REG4
+# define REG4 register
+#endif
+#if REGISTERS >= 5
+# undef REG5
+# define REG5 register
+#endif
+#if REGISTERS >= 6
+# undef REG6
+# define REG6 register
+#endif
+#if REGISTERS >= 7
+# undef REG7
+# define REG7 register
+#endif
+#if REGISTERS >= 8
+# undef REG8
+# define REG8 register
+#endif
+#if REGISTERS >= 9
+# undef REG9
+# define REG9 register
+#endif
+#if REGISTERS >= 10
+# undef REG10
+# define REG10 register
+#endif
+#if REGISTERS >= 11
+# undef REG11
+# define REG11 register
+#endif
+#if REGISTERS >= 12
+# undef REG12
+# define REG12 register
+#endif
+#if REGISTERS >= 13
+# undef REG13
+# define REG13 register
+#endif
+#if REGISTERS >= 14
+# undef REG14
+# define REG14 register
+#endif
+#if REGISTERS >= 15
+# undef REG15
+# define REG15 register
+#endif
+#if REGISTERS >= 16
+# undef REG16
+# define REG16 register
+#endif
+
+#ifndef BYTEORDER
+# define BYTEORDER 0000
+#endif
+
+#ifndef NOALLIGN
+# define NOALLIGN 0
+#endif
+
+
+union bytes {
+ long word;
+ struct {
+#if BYTEORDER == 4321
+ char_type b1;
+ char_type b2;
+ char_type b3;
+ char_type b4;
+#else
+#if BYTEORDER == 1234
+ char_type b4;
+ char_type b3;
+ char_type b2;
+ char_type b1;
+#else
+# undef BYTEORDER
+ int dummy;
+#endif
+#endif
+ } bytes;
+};
+
+#if BYTEORDER == 4321 && NOALLIGN == 1
+# define input(b,o,c,n,m){ \
+ (c) = (*(long *)(&(b)[(o)>>3])>>((o)&0x7))&(m); \
+ (o) += (n); \
+ }
+#else
+# define input(b,o,c,n,m){ \
+ REG1 char_type *p = &(b)[(o)>>3]; \
+ (c) = ((((long)(p[0]))|((long)(p[1])<<8)| \
+ ((long)(p[2])<<16))>>((o)&0x7))&(m); \
+ (o) += (n); \
+ }
+#endif
+
+#ifndef MAXSEG_64K
+ /* DECLARE(ush, tab_prefix, (1<<BITS)); -- prefix code */
+# define tab_prefixof(i) tab_prefix[i]
+# define clear_tab_prefixof() memzero(tab_prefix, 256);
+#else
+ /* DECLARE(ush, tab_prefix0, (1<<(BITS-1)); -- prefix for even codes */
+ /* DECLARE(ush, tab_prefix1, (1<<(BITS-1)); -- prefix for odd codes */
+ ush *tab_prefix[2];
+# define tab_prefixof(i) tab_prefix[(i)&1][(i)>>1]
+# define clear_tab_prefixof() \
+ memzero(tab_prefix0, 128), \
+ memzero(tab_prefix1, 128);
+#endif
+#define de_stack ((char_type *)(&d_buf[DIST_BUFSIZE-1]))
+#define tab_suffixof(i) tab_suffix[i]
+
+int block_mode = BLOCK_MODE; /* block compress mode -C compatible with 2.0 */
+
+/* ============================================================================
+ * Decompress in to out. This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets iptr to insize-1 included.
+ * The magic header has already been checked and skipped.
+ * bytes_in and bytes_out have been initialized.
+ */
+local int unlzw(FILE *in, FILE *out)
+ /* input and output file descriptors */
+{
+ REG2 char_type *stackp;
+ REG3 code_int code;
+ REG4 int finchar;
+ REG5 code_int oldcode;
+ REG6 code_int incode;
+ REG7 long inbits;
+ REG8 long posbits;
+ REG9 int outpos;
+/* REG10 int insize; (global) */
+ REG11 unsigned bitmask;
+ REG12 code_int free_ent;
+ REG13 code_int maxcode;
+ REG14 code_int maxmaxcode;
+ REG15 int n_bits;
+ REG16 int rsize;
+
+ ofd = out;
+
+#ifdef MAXSEG_64K
+ tab_prefix[0] = tab_prefix0;
+ tab_prefix[1] = tab_prefix1;
+#endif
+ maxbits = get_byte();
+ block_mode = maxbits & BLOCK_MODE;
+ if ((maxbits & LZW_RESERVED) != 0) {
+ error( "warning, unknown flags in unlzw decompression");
+ }
+ maxbits &= BIT_MASK;
+ maxmaxcode = MAXCODE(maxbits);
+
+ if (maxbits > BITS) {
+ error("compressed with too many bits; cannot handle file");
+ exit_code = ERROR;
+ return ERROR;
+ }
+ rsize = insize;
+ maxcode = MAXCODE(n_bits = INIT_BITS)-1;
+ bitmask = (1<<n_bits)-1;
+ oldcode = -1;
+ finchar = 0;
+ outpos = 0;
+ posbits = inptr<<3;
+
+ free_ent = ((block_mode) ? FIRST : 256);
+
+ clear_tab_prefixof(); /* Initialize the first 256 entries in the table. */
+
+ for (code = 255 ; code >= 0 ; --code) {
+ tab_suffixof(code) = (char_type)code;
+ }
+ do {
+ REG1 int i;
+ int e;
+ int o;
+
+ resetbuf:
+ e = insize-(o = (posbits>>3));
+
+ for (i = 0 ; i < e ; ++i) {
+ inbuf[i] = inbuf[i+o];
+ }
+ insize = e;
+ posbits = 0;
+
+ if (insize < INBUF_EXTRA) {
+/* modified to use fread instead of read - WDP 10/22/97 */
+/* if ((rsize = read(in, (char*)inbuf+insize, INBUFSIZ)) == EOF) { */
+
+ if ((rsize = fread((char*)inbuf+insize, 1, INBUFSIZ, in)) == EOF) {
+ error("unexpected end of file");
+ exit_code = ERROR;
+ return ERROR;
+ }
+ insize += rsize;
+ bytes_in += (ulg)rsize;
+ }
+ inbits = ((rsize != 0) ? ((long)insize - insize%n_bits)<<3 :
+ ((long)insize<<3)-(n_bits-1));
+
+ while (inbits > posbits) {
+ if (free_ent > maxcode) {
+ posbits = ((posbits-1) +
+ ((n_bits<<3)-(posbits-1+(n_bits<<3))%(n_bits<<3)));
+ ++n_bits;
+ if (n_bits == maxbits) {
+ maxcode = maxmaxcode;
+ } else {
+ maxcode = MAXCODE(n_bits)-1;
+ }
+ bitmask = (1<<n_bits)-1;
+ goto resetbuf;
+ }
+ input(inbuf,posbits,code,n_bits,bitmask);
+ Tracev((stderr, "%d ", code));
+
+ if (oldcode == -1) {
+ if (code >= 256) {
+ error("corrupt input.");
+ exit_code = ERROR;
+ return ERROR;
+ }
+
+ outbuf[outpos++] = (char_type)(finchar = (int)(oldcode=code));
+ continue;
+ }
+ if (code == CLEAR && block_mode) {
+ clear_tab_prefixof();
+ free_ent = FIRST - 1;
+ posbits = ((posbits-1) +
+ ((n_bits<<3)-(posbits-1+(n_bits<<3))%(n_bits<<3)));
+ maxcode = MAXCODE(n_bits = INIT_BITS)-1;
+ bitmask = (1<<n_bits)-1;
+ goto resetbuf;
+ }
+ incode = code;
+ stackp = de_stack;
+
+ if (code >= free_ent) { /* Special case for KwKwK string. */
+ if (code > free_ent) {
+ if (outpos > 0) {
+ write_buf((char*)outbuf, outpos);
+ bytes_out += (ulg)outpos;
+ }
+ error("corrupt input.");
+ exit_code = ERROR;
+ return ERROR;
+
+ }
+ *--stackp = (char_type)finchar;
+ code = oldcode;
+ }
+
+ while ((cmp_code_int)code >= (cmp_code_int)256) {
+ /* Generate output characters in reverse order */
+ *--stackp = tab_suffixof(code);
+ code = tab_prefixof(code);
+ }
+ *--stackp = (char_type)(finchar = tab_suffixof(code));
+
+ /* And put them out in forward order */
+ {
+ /* REG1 int i; already defined above (WDP) */
+
+ if (outpos+(i = (de_stack-stackp)) >= OUTBUFSIZ) {
+ do {
+ if (i > OUTBUFSIZ-outpos) i = OUTBUFSIZ-outpos;
+
+ if (i > 0) {
+ memcpy(outbuf+outpos, stackp, i);
+ outpos += i;
+ }
+ if (outpos >= OUTBUFSIZ) {
+ write_buf((char*)outbuf, outpos);
+ bytes_out += (ulg)outpos;
+ outpos = 0;
+ }
+ stackp+= i;
+ } while ((i = (de_stack-stackp)) > 0);
+ } else {
+ memcpy(outbuf+outpos, stackp, i);
+ outpos += i;
+ }
+ }
+
+ if ((code = free_ent) < maxmaxcode) { /* Generate the new entry. */
+
+ tab_prefixof(code) = (unsigned short)oldcode;
+ tab_suffixof(code) = (char_type)finchar;
+ free_ent = code+1;
+ }
+ oldcode = incode; /* Remember previous code. */
+ }
+ } while (rsize != 0);
+
+ if (outpos > 0) {
+ write_buf((char*)outbuf, outpos);
+ bytes_out += (ulg)outpos;
+ }
+ return OK;
+}
+/* ========================================================================*/
+/* this marks the start of the code from 'util.c' */
+
+local int fill_inbuf(int eof_ok)
+ /* set if EOF acceptable as a result */
+{
+ int len;
+
+ /* Read as much as possible from file */
+ insize = 0;
+ do {
+ len = fread((char*)inbuf+insize, 1, INBUFSIZ-insize, ifd);
+ if (len == 0 || len == EOF) break;
+ insize += len;
+ } while (insize < INBUFSIZ);
+
+ if (insize == 0) {
+ if (eof_ok) return EOF;
+ error("unexpected end of file");
+ exit_code = ERROR;
+ return ERROR;
+ }
+
+ bytes_in += (ulg)insize;
+ inptr = 1;
+ return inbuf[0];
+}
+/* =========================================================================== */
+local void write_buf(voidp buf, unsigned cnt)
+/* copy buffer into memory; allocate more memory if required*/
+{
+ if (!realloc_fn)
+ {
+ /* append buffer to file */
+ /* added 'unsigned' to get rid of compiler warning (WDP 1/1/99) */
+ if ((unsigned long) fwrite(buf, 1, cnt, ofd) != cnt)
+ {
+ error
+ ("failed to write buffer to uncompressed output file (write_buf)");
+ exit_code = ERROR;
+ return;
+ }
+ }
+ else
+ {
+ /* get more memory if current buffer is too small */
+ if (bytes_out + cnt > *memsize)
+ {
+ *memptr = realloc_fn(*memptr, bytes_out + cnt);
+ *memsize = bytes_out + cnt; /* new memory buffer size */
+
+ if (!(*memptr))
+ {
+ error("malloc failed while uncompressing (write_buf)");
+ exit_code = ERROR;
+ return;
+ }
+ }
+ /* copy into memory buffer */
+ memcpy((char *) *memptr + bytes_out, (char *) buf, cnt);
+ }
+}
+/* ======================================================================== */
+local void error(char *m)
+/* Error handler */
+{
+ ffpmsg(ifname);
+ ffpmsg(m);
+}
diff --git a/vendor/cfitsio/zutil.c b/vendor/cfitsio/zutil.c
new file mode 100644
index 00000000..15645c5e
--- /dev/null
+++ b/vendor/cfitsio/zutil.c
@@ -0,0 +1,316 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch ((int)(sizeof(uInt))) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch ((int)(sizeof(uLong))) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch ((int)(sizeof(voidpf))) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch ((int)(sizeof(z_off_t))) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/vendor/cfitsio/zutil.h b/vendor/cfitsio/zutil.h
new file mode 100644
index 00000000..1f5a6c0e
--- /dev/null
+++ b/vendor/cfitsio/zutil.h
@@ -0,0 +1,272 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ)
+# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+# define ZLIB_INTERNAL
+#endif
+
+#include "zlib.h"
+
+#ifdef STDC
+# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# ifdef M_I86
+# include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+#if defined(__BORLANDC__)
+ #pragma warn -8004
+ #pragma warn -8008
+ #pragma warn -8066
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+#ifdef VMS
+# define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int ZLIB_INTERNAL z_verbose;
+ extern void ZLIB_INTERNAL z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+ unsigned size));
+void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */