Index: /trunk/extsrc/gpcsw/gpcsrc/Make.Common
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/Make.Common	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/Make.Common	(revision 23490)
@@ -0,0 +1,726 @@
+#
+# $Id: Make.Common,v 2.17 2004/09/05 10:10:45 thomas Exp $
+# $Locker:  $
+#
+# 2006-2-25: Windows cross-compilation support (not in CFHT RCS.)
+# 2006-4-19: "PREFIX" patch added by Sidik (not in CFHT RCS.)
+#
+# Make.Common - include at top of Makefiles for some common defaults.
+# Override any variables by setting them after including this file.
+# Then include Make.Common a second time, followed by any project
+# specific targets. For example, a typical library Makefile looks like this:
+#
+#   # Makefile for libfoo
+#   include ../Make.Common
+#   SRCS=foo1.c foo2.c foo3.c
+#   HDRS=foo.h
+#   include ../Make.Common
+#
+# If SRCS just equals *.c and *.cc (recommended) then you can
+# omit it completely from your makefile.  When a new C file
+# appears in the directory for libfoo, it will then automatically
+# be added to libfoo on the next build.  HDRS gives the header
+# files you want to install.  If you do not have any internal .h
+# files in your library, you can omit HDRS as well and *.h is assumed.
+# For a program, a typical Makefile looks like this:
+#
+#   # Makefile for foo
+#   include ../Make.Common
+#   VERSION=1.1
+#   $(EXECNAME): $(OBJS) libfoo.a libcfht.a
+#   include ../Make.Common
+#
+# Again, if you don't want it to pick up *.c and *.cc, then you might
+# want to define SRCS explicitly (OBJS will be generated for you).
+# If you omit VERSION, the current date (YYMMDD) is used instead.
+# And for a project toplevel directory, a Makefile might look like:
+#
+#   # Makefile for foo project directory
+#   include ../Make.Common
+#   SUBDIRS=libfoo foo
+#   foo.d: libfoo.d.install
+#   include ../Make.Common
+#
+# Use this last template whenever creating a subdirectory off of
+# the main directory which contains Make.Common.  Create a symlink
+# in the new directory so that the "leaves" (programs and libraries)
+# can always include "../Make.Common" from their Makefiles.
+#
+# The dependency line "foo.d: libfoo.d.install" indicates that libfoo
+# must be _installed_ before foo is _built_.  Other dependencies
+# within a program are generated automatically by "make dep".  It
+# only generates dependencies for files included with "" (quotes)
+# and not <>, so if want your program to rebuild if cfht.h changes,
+# include it with "cfht/cfht.h" instead of <cfht/cfht.h>.
+#
+# More user information can be found at http://software/make.html
+# The rest of the comments in this file mostly pertain to hacking
+# on Make.Common itself.
+#
+# ---------------------------------------------------------------------------
+ifndef HAVE_VARS
+#
+# On the first pass, define defaults for makefile variables.
+# Then the user gets a chance to override any, and finally
+# Make.Common is included again.
+#
+HAVE_VARS := True
+#
+# Default is to build everything, but not install it (except that
+# some libraries may get installed if other projects depend on them).
+#
+default: all
+#
+#                          --- Directories ---
+#
+# Find out where to store the architecture dependent objects.
+# Apr 2000: Added some temporary transitional hacks to help migration.
+#           Remove /tmp_mnt, /local, /usr/local/cfht to /cfht, /cfht/dev -> /cfht/src
+#           This might break building at other sites!
+# 
+FIND_ROOT := $(shell DA=`pwd`; DR="obs"; \
+while [ ! -f $$DA/ThisIsTopLevel -a "$$DA" != "/" ]; do \
+  DA=`cd $$DA/..;pwd | sed -e 's,^/local/,/,' -e 's,/tmp_mnt/,/,' -e 's,^/usr/local/cfht/,/cfht/,' -e 's,/cfht/dev,/cfht/src,'`; DR=../$$DR; \
+done; \
+if [ "$$DA" = "/" ]; then \
+echo "ERROR: You must create an empty file called \`ThisIsTopLevel' in a common" 1>&2;\
+echo "  directory shared by project sources.  e.g.: /usr/local/src/ThisIsTopLevel" 1>&2;\
+echo "  The directory one level higher will be used as a base for lib,bin,include" 1>&2;\
+echo "  e.g. /usr/local/{bin,lib,...} if you create /usr/local/src/ThisIsTopLevel." 1>&2;\
+echo "*** Please press ^C now and create this file before continuing..." 1>&2;\
+read Dmy; else \
+echo `cd $$DA/..;pwd | sed -e 's,^/local/,/,' -e 's,/tmp_mnt/,/,' -e 's,^/usr/local/cfht/,/cfht/,' -e 's,/cfht/dev,/cfht/src,'` ../$$DR $$DA; fi)
+
+#
+# This defines that basic paths that are commonly used during the build
+# process.  DIR_GNU must be the prefix where you've installed gcc,
+# gmake, and ginstall.  The rest are all install locations for header
+# files, man pages, libraries, objects, and programs.
+#
+DIR_GNU   := /apps/gnu
+PREFIX    := $(word 1,$(FIND_ROOT))
+DIR_OBSREL:= $(word 2,$(FIND_ROOT))
+DIR_SRC   := $(word 3,$(FIND_ROOT))
+#
+# Allow local settings to override PREFIX.  Make.Local is
+# included again at the very end, allowing any other
+# variables to be overridden.
+#
+ifeq ($(DIR_SRC)/Make.Local,$(wildcard $(DIR_SRC)/Make.Local))
+include $(DIR_SRC)/Make.Local
+endif
+#
+DIR_ROOT  := $(PREFIX)
+DIR_CONF  := $(DIR_ROOT)/conf
+DIR_BIN   := $(DIR_ROOT)/bin
+DIR_LIB   := $(DIR_ROOT)/lib
+DIR_MAN   := $(DIR_ROOT)/man
+DIR_INC   := $(DIR_ROOT)/include
+DIR_OBS   := $(DIR_ROOT)/obs
+#
+#                         --- Build Tools ---
+#
+# MAKEFILE may be useful during migration (if a project needs two styles
+# of makefiles at once.)  PATH should have at least DIR_GNU and DIR_BIN.
+# Rest are just the basic programs used to build the program.  User is
+# expected to run GNU Make 3.74 or better.  After that, everything here
+# should take care of making sure the right versions of things are run.
+#
+MAKEFILE = Makefile
+PATH     := .:$(DIR_GNU)/bin:$(DIR_BIN):/usr/local/bin:/usr/5bin:/usr/bin:/bin:/usr/ucb:$(PATH)
+SHELL	 = /bin/sh
+INSTALL  = ginstall
+INSTSTRIP= $(INSTALL) -s
+TAR	 = gtar
+AR	 = ar
+FC       = gfortran
+CC	 = gcc
+LD       = gcc
+CXX	 = g++
+CMM	 = g++	# for make depend
+PURIFY   = purify
+#
+#                       --- Build Tool Flags ---
+#
+# Standard flags to ar and gcc during compile/link phases.  The GNU compiler
+# allows -g and -O at the same time.  At installation, the executables are
+# stripped and become the equivalent of just a "-O" compiled version.  The
+# copy with the symbols stays in $(DIR_OBS) until the next make or make clean.
+#
+# The setting of CCWARN here gives messages comparable to most things that
+# lint used to check for.  Override in the project makefile by setting it
+# to nothing if it's too noisy.
+#
+# The flags in CCSHARE apply to two different things: -fPIC is used during
+# compilation and -shared applies to the link stage.
+#
+FCDEBUG  = -g -O -fno-automatic
+FFWARN   = -Wall
+FFLAGS   = $(FCDEBUG) $(EXTRA_FFLAGS) $(FFWARN) $(CCDEFS) $(CCINCS)
+CCDEBUG  = -g -O
+CCSHARE  = -fPIC -shared
+CCWARN	 = -Wall -Wstrict-prototypes # -Wshadow
+CFLAGS   = $(CCDEBUG) $(EXTRA_CFLAGS) $(CCWARN) $(CCDEFS) $(CCINCS) $(CCHACKS)
+LDFLAGS  = $(CCDEBUG) $(EXTRA_CFLAGS) $(CCLIBS)
+CXXFLAGS = $(subst -Wstrict-prototypes,,$(CFLAGS))
+ARFLAGS  = -rc
+#
+# Find out the host name and type that we are currently running on.
+# TARGET=OSname-OSmajor. No support is provided for cross-compilers.
+# Later in this file TARGET is looked at and is used to define
+# one of: -DHPUX -DCYGWIN32 -DLINUX -DSOLARIS or -DSUNOS.  If absolutely
+# necessary, use this for conditional compiles in your code.  If
+# further distinctions are needed for other OSes or OS versions,
+# make up a new define and add it to the section that checks TARGET.
+#
+HOSTNAME := $(strip $(shell hostname))
+ifeq ($(TARGET),)
+TARGET := $(shell echo `uname -s`-`uname -r | cut -d . -f 1`)
+endif
+DOMAIN := $(shell domainname 2> /dev/null || echo "unknown")
+#
+# At CFHT, make sure stuff gets installed as group `daprog':
+#
+ifeq ($(DOMAIN),cfht)
+INSTALL += -g daprog
+endif
+#
+# Override or += these variables in the project's Makefile
+#
+VERSION_DATE := $(shell date +%y%m%d | sed -e 's/:/0/')
+VERSION      = $(VERSION_DATE)
+EXTRA_CFLAGS =
+#
+# Include the following defines by adding CCDEFS+=$(VERSIONDEFS) to Makefile:
+#
+VERSIONDEFS=-DVERSION=$(VERSION) -DSOURCEDATE="\"`sourcedate . 2> /dev/null`\"" -DBUILDDATE="\"`date +'%b %d %Y'`\""
+#
+# Provide a HINT for programs that can use either syslog or cfht_log
+#
+ifeq ($(origin NO_CFHTLOG), undefined)
+NO_CFHTLOG   := $(shell if [ ! -p /tmp/pipes/syslog.np ];then echo "-DNO_CFHTLOG";fi)
+endif
+#
+# Don't build in support for EPICS except on saturn and neptune (RPM & hform)
+#
+ifeq ($(origin USE_EPICS), undefined)
+USE_EPICS    := $(shell if [ "$(HOSTNAME)" = "saturn" -o "$(HOSTNAME)" = "neptune" ]; then echo "-DUSE_EPICS";fi)
+endif
+#
+CCDEFS       = $(NO_CFHTLOG) $(USE_EPICS)
+CCINCS       = -I. -Iinclude -I$(DIR_INC)
+CCLIBS       = -L$(DIR_LIB)
+CCHACKS      =
+#
+#                        --- Program Files ---
+#
+# The *INST variables end up containing the list of targets as their
+# installed names with the full paths like $(DIR_INC) and $(DIR_CONF)
+# tacked on to each filename.  NEEDTITLES is a list of files which
+# Sidik's titler program should attempt to place a copyright header in.
+#
+SRCS	     = $(shell ls *.f *.f77 *.c *.cc 2> /dev/null)
+HDRS	     = $(shell ls *.h *.hh 2> /dev/null)
+HDRINST	     = $(HDRS:%=$(DIR_INC)/$(PROJBASE)/%)
+MAN1         = $(shell cd ./man 2>/dev/null && /bin/ls *.1 2>/dev/null)
+MAN2         = $(shell cd ./man 2>/dev/null && /bin/ls *.2 2>/dev/null)
+MAN3         = $(shell cd ./man 2>/dev/null && /bin/ls *.3 2>/dev/null)
+MAN4         = $(shell cd ./man 2>/dev/null && /bin/ls *.4 2>/dev/null)
+MAN5         = $(shell cd ./man 2>/dev/null && /bin/ls *.5 2>/dev/null)
+MAN6         = $(shell cd ./man 2>/dev/null && /bin/ls *.6 2>/dev/null)
+MAN7         = $(shell cd ./man 2>/dev/null && /bin/ls *.7 2>/dev/null)
+MAN8         = $(shell cd ./man 2>/dev/null && /bin/ls *.8 2>/dev/null)
+CONFS        = $(shell cd ./conf 2>/dev/null && /bin/ls *.def *.par *.bm *.xbm *.rdb *.xrdb 2>/dev/null)
+SCRIPTS      = $(shell cd ./scripts 2>/dev/null && /bin/ls *.sh 2>/dev/null)
+COPYINST     = $(CONFS:%=$(DIR_CONF)/%) $(SCRIPTS:%.sh=$(DIR_BIN)/%) \
+	$(MAN1:%=$(DIR_MAN)/man1/%) \
+	$(MAN2:%=$(DIR_MAN)/man2/%) \
+	$(MAN3:%=$(DIR_MAN)/man3/%) \
+	$(MAN4:%=$(DIR_MAN)/man4/%) \
+	$(MAN5:%=$(DIR_MAN)/man5/%) \
+	$(MAN6:%=$(DIR_MAN)/man6/%) \
+	$(MAN7:%=$(DIR_MAN)/man7/%) \
+	$(MAN8:%=$(DIR_MAN)/man8/%)
+NEEDTITLES   = $(shell ls * | egrep -v "^\#|~$$" 2> /dev/null)
+#
+# SUBDIRS gets overridden only by Makefiles that just build other
+# subdirectories in their tree.  These directory nodes cannot generate
+# a program or a library (this is only done at the `leaves')
+#
+SUBDIRS      =
+#
+#                       --- System Dependent ---
+#
+# Some typical places we might find X11, typical extension for shared lib,
+# and extension for executables.
+#
+CCINCSX11 = -I/usr/X11/include
+CCLIBSX11 = -L/usr/X11/lib
+CCLINKX11 = -lX11 -lXext
+OBJ_LINK = obj
+EXE =
+SL  = .so
+#
+# Some overrides for a Win32 system running a cygnus win32 gcc
+#
+ifeq ($(TARGET), CYGWIN32_NT-4)
+CCDEFS   += -DCYGWIN32
+EXE       = .exe
+SL        = .dll
+endif
+#
+# Some overrides for HPUX (X11 in non-standard place, .sl for shared libs)
+#
+ifeq ($(TARGET), HP-UX-A)
+CCINCSX11 = -I/usr/include/X11R5
+CCLIBSX11 = -L/usr/lib/X11R5
+CCLINKX11 = -lX11
+CCDEFS   += -DHPUX -DHACK_XLIBS -DHACK_SELECT
+# X Libraries may have bugs, so X clients (hform) that really care
+# about this should add /usr/local/lib/wm (a CFHT-ism) to SHLIB_PATH.
+# select() prototype is broken, and missing_protos.h should fix it.
+CCHACKS   = -fwritable-strings
+SL        = .sl
+endif
+#
+# HP-UX 10.20 no longer has the scanf bug in the C library, so
+# doesn't need -fwritable-strings anymore.  X is also up to R6 now.
+#
+ifeq ($(TARGET), HP-UX-B)
+CCINCSX11 = -I/usr/include/X11R6
+CCLIBSX11 = -L/usr/lib/X11R6
+CCLINKX11 = -lX11
+CCDEFS   += -DHPUX
+SL        = .sl
+endif
+#
+# Linux often has dns in a separate libresolv and crypt in libcrypt.
+# Some installations require them to be explicitly linked.
+# Linux's utilities (tar, install) are the GNU versions, so no need
+# for the `g' prefix which we use on other platforms to ensure that
+# we're getting the GNU versions.
+#
+ifeq ($(TARGET), Linux-2)
+TAR = tar
+INSTALL = install
+CCINCSX11 = -I/usr/X11R6/include
+CCLIBSX11 = -L/usr/X11R6/lib
+CCLINKX11 = -lX11
+CCLINK  = -Wl,-R,$(DIR_LIB)
+ifeq (/usr/lib/libresolv.so,$(wildcard /usr/lib/libresolv.so))
+CCLINKNET += -lresolv
+endif
+ifeq (/usr/lib/libcrypt.so,$(wildcard /usr/lib/libcrypt.so))
+CCLINKNET += -lcrypt
+endif
+CCDEFS   += -DLINUX
+endif
+#
+# Solaris needs to link with libsocket and libnsl.  Also X11 is with openwin.
+#
+ifeq ($(TARGET), SunOS-5)
+CCINCSX11 = -I/usr/openwin/include
+CCLIBSX11 = -L/usr/openwin/lib
+CCLINKNET = -lsocket -lnsl
+# Without this the Solaris dynamic linker may not be able to find shared
+# versions of libg++ and libstdc++.  SunOS builds it from the -L's.
+CCLINK  = -Wl,-R,$(DIR_GNU)/lib
+CCDEFS   += -DSOLARIS
+endif
+#
+# Old suns are missing EXIT_FAILURE and EXIT_SUCCESS from stdlib.h
+#
+ifeq ($(TARGET), SunOS-4)
+CCDEFS   += -DSUNOS -D__USE_FIXED_PROTOTYPES__ -DEXIT_FAILURE=1 -DEXIT_SUCCESS=0
+endif
+#
+# Cross-compiler for VxWorks on a Sparc
+#
+ifeq ($(TARGET), VXSPARC)
+AR      = vxarsparc
+CC      = vxgccsparc
+LD      = vxgccsparc
+CXX     = vxg++sparc
+CMM	= vxg++sparc	# for make depend
+CROSSCC = vxsparc
+OBJ_LINK     = obj.vxsparc
+CCDEFS += -DCPU=SPARC -DVXWORKS -Dmain=$(PROJECT)
+DIR_BIN   := $(DIR_BIN)/$(CROSSCC)
+DIR_LIB   := $(DIR_LIB)/$(CROSSCC)
+DIR_OBS   := $(DIR_OBS)/$(CROSSCC)
+DIR_OBSREL:= $(DIR_OBSREL)/$(CROSSCC)
+NO_CFHTLOG:= -DNO_CFHTLOG
+INSTSTRIP= $(INSTALL)
+endif
+#
+# Cross-compiler for VxWorks on a PowerPC
+#
+ifeq ($(TARGET), VXPOWERPC)
+AR      = vxarpowerpc
+CC      = vxgccpowerpc
+LD      = vxgccpowerpc
+CXX     = vxg++powerpc
+CMM	= vxgccpowerpc	# for make depend, change to ++ if vxg++powerpc works
+CROSSCC = vxpowerpc
+OBJ_LINK     = obj.vxpowerpc
+CCDEFS += -DCPU=PPC604 -DVXWORKS -Dmain=$(PROJECT)
+DIR_BIN   := $(DIR_BIN)/$(CROSSCC)
+DIR_LIB   := $(DIR_LIB)/$(CROSSCC)
+DIR_OBS   := $(DIR_OBS)/$(CROSSCC)
+DIR_OBSREL:= $(DIR_OBSREL)/$(CROSSCC)
+NO_CFHTLOG:= -DNO_CFHTLOG
+INSTSTRIP= $(INSTALL)
+endif
+#
+# Cross-compiler for PowerPC405 (embedded)
+#
+ifeq ($(TARGET), PPC405)
+AR      = /apps/ppc405/powerpc-405-linux-gnu/gcc-3.4.2-glibc-2.2.5/bin/powerpc-405-linux-gnu-ar
+CC      = /apps/ppc405/powerpc-405-linux-gnu/gcc-3.4.2-glibc-2.2.5/bin/powerpc-405-linux-gnu-gcc
+LD      = /apps/ppc405/powerpc-405-linux-gnu/gcc-3.4.2-glibc-2.2.5/bin/powerpc-405-linux-gnu-gcc
+CXX     = /apps/ppc405/powerpc-405-linux-gnu/gcc-3.4.2-glibc-2.2.5/bin/powerpc-405-linux-gnu-g++
+CMM	= /apps/ppc405/powerpc-405-linux-gnu/gcc-3.4.2-glibc-2.2.5/bin/powerpc-405-linux-gnu-g++
+CROSSCC = ppc405
+OBJ_LINK     = obj.ppc405
+CCDEFS += -DPPC405
+DIR_BIN   := $(DIR_BIN)/$(CROSSCC)
+DIR_LIB   := $(DIR_LIB)/$(CROSSCC)
+DIR_OBS   := $(DIR_OBS)/$(CROSSCC)
+DIR_OBSREL:= $(DIR_OBSREL)/$(CROSSCC)
+NO_CFHTLOG:= -DNO_CFHTLOG
+INSTSTRIP= $(INSTALL)
+endif
+#
+# Cross-compiler for Windows i386
+#
+ifeq ($(TARGET), MINGW32)
+PATH   := /usr/local/cross-tools/bin:$(PATH)
+AR      = i386-mingw32msvc-ar
+CC      = i386-mingw32msvc-gcc
+LD      = i386-mingw32msvc-gcc
+CXX     = i386-mingw32msvc-g++
+CMM     = i386-mingw32msvc-g++
+CROSSCC = mingw32
+OBJ_LINK     = obj.mingw32
+EXE       = .exe
+SL        = .dll
+CCDEFS += -DMINGW32
+#DIR_BIN   := $(DIR_BIN)/$(CROSSCC)
+DIR_LIB   := $(DIR_LIB)/$(CROSSCC)
+DIR_OBS   := $(DIR_OBS)/$(CROSSCC)
+DIR_OBSREL:= $(DIR_OBSREL)/$(CROSSCC)
+NO_CFHTLOG:= -DNO_CFHTLOG
+INSTSTRIP= $(INSTALL)
+endif
+#
+#                  --- Project and Target Names ---
+#
+OBJ	  = $(DIR_OBS)/$(PROJECT)
+#
+# OBJS1 is just a temporary variable with *.cc converted to *.o and
+# OBJS contains *.cc + *.c -> *.o.  OBJS_PIC lists the names that
+# would be used if a shared library is being build (*.pic.o, in the
+# same directory where the other *.o files went.
+#
+OBJS3    = $(SRCS:%.cc=$(OBJ)/%.o)
+OBJS2	 = $(OBJS3:%.c=$(OBJ)/%.o)
+OBJS1    = $(OBJS2:%.f=$(OBJ)/%.o)
+OBJS     = $(OBJS1:%.f77=$(OBJ)/%.o)
+OBJS_PIC = $(OBJS:%.o=%.pic.o)
+#
+# If a program or library is generated, the subdirectory MUST have the
+# same name as the program it generates.  This is placed in PROJECT.
+# PROJBASE contains the same thing, unless it started with `lib', in
+# which case the lib is trimmed off.  This is how we know if we are
+# building a library or not.
+#
+PROJECT   = $(patsubst %-$(VERSION),%,$(notdir $(shell pwd)))
+PROJBASE  = $(PROJECT:lib%=%)
+#
+# `make all' causes the program to be deposited in this temporary directory
+#
+EXECNAME  = $(OBJ)/$(PROJBASE)$(EXE)
+#
+# `make install' strips it and copies it to the main bin/ directory.
+#
+EXECINST  = $(DIR_BIN)/$(PROJBASE)$(EXE)
+#
+# `make all' for libraries first assembles the .a here
+#
+LIBNAME   = $(OBJ)/$(PROJECT).a
+#
+# `make install' for libraries copies it unstripped to the lib/ directory
+#
+LIBINST   = $(DIR_LIB)/$(PROJECT).a
+#
+# Same all over again, except for the shared versions of the libraries.
+#
+SHLIBNAME = $(OBJ)/$(PROJECT)$(SL)
+SHLIBINST = $(DIR_LIB)/$(PROJECT)$(SL)
+#
+# This is where we detect if this is a library or a program
+#
+ifeq ($(PROJECT), $(PROJBASE))
+ALL	= $(EXECNAME)
+ALLINST = $(COPYINST) $(EXECINST)
+HDRINST =
+else
+ALL	= $(LIBNAME)
+# ALL += $(SHLIBNAME)
+ALLINST = $(HDRINST) $(LIBINST)
+# ALLINS += $(SHLIBINST)
+endif
+#
+# ------------------------- End of Variables -----------------------------
+else
+# -------------------------- Start of Rules ------------------------------
+#
+# This section gets read during the second pass.  It defines the standard
+# rules defined at http://software/make.html, using the variables defined
+# above (possibly with some overrides that the user put in between.)
+#
+.SUFFIXES: ; # Do not use default targets like '.c.o' and '.cc.o'
+#
+# Tell make never to expect a file by any of these names:
+#
+.PHONY:	clean all dep default checkdep checkbin preinstall libinstall install execlist execlist-sh
+#
+vpath %.h     $(DIR_INC)/cfht:$(DIR_INC)	# include files
+vpath %.hh    $(DIR_INC)			# C++ include files
+vpath %.bm    $(DIR_INC)			# bitmap include files
+vpath %.a     $(DIR_LIB)			# libraries
+vpath %$(SL)  $(DIR_LIB)			# shared libraries
+#
+#                        --- Rule Patterns ---
+#
+# These are just the standard ways to cause gcc to generate a .o from a .c,
+# g++ to generate a .o from a .cc, and to create libraries with ar (or
+# gcc in the case of shared libraries... which we are not really using yet.)
+#
+$(OBJ)/%.o: %.f          ; $(FC)  $(FFLAGS)   -c $*.f  -o $@
+$(OBJ)/%.o: %.c          ; $(CC)  $(CFLAGS)   -c $*.c  -o $@
+$(OBJ)/%.o: %.cc         ; $(CXX) $(CXXFLAGS) -c $*.cc -o $@
+$(OBJ)/%.pic.o: %.f      ; $(CC)  $(CFLAGS)   $(CCSHARE) -c $*.f  -o $@
+$(OBJ)/%.pic.o: %.c      ; $(CC)  $(CFLAGS)   $(CCSHARE) -c $*.c  -o $@
+$(OBJ)/%.pic.o: %.cc     ; $(CXX) $(CXXFLAGS) $(CCSHARE) -c $*.cc -o $@
+$(LIBNAME):  $(OBJS)      ; rm -f $@ ; $(AR) $(ARFLAGS) $@~ $^ ; mv $@~ $@
+$(SHLIBNAME): $(OBJS_PIC) ; rm -f $@ ; $(LD) $(LDFLAGS) $(CCSHARE) $^ $(CCLINK) -o $@
+#
+# The cryptic substitution that starts with $(^... takes all the dependencies
+# that this executable has and replaces anything like /usr/local/lib/libcfht.a
+# with a -lcfht.  WARNING: if a shared version exists, it will be used!
+#
+$(EXECNAME):
+	$(LD) $(LDFLAGS) $(^:$(DIR_LIB)/lib%.a=-l%) $(CCLINK) -o $@~
+	@mv $@~ $@
+#
+# NOTE: Use `make obj/myprogram-pure' to invoke this.  Also be sure you have
+#       $(EXECNAME) $(EXECNAME)-pure: in your project Makefile
+#
+$(EXECNAME)-pure: ; $(PURIFY) $(LD) $(LDFLAGS) $^ $(CCLINK) -o $@
+#
+# Sidik's titler program will insert comment header blocks into all your
+# source files if you create the proper Index files.
+#
+titles: ; @titler $(NEEDTITLES)
+#
+# `make execlist' at any level produces a list of all the "executables"
+# (scripts or compiled C programs) from the current level down.  It is
+# used by the version programs for pegasus accounts.
+#
+execlist: execlist-sh
+execlist-sh:
+	@for i in "" $(SCRIPTS:%.sh=%); do if [ "$$i" != "" ]; then echo $$i; fi; done
+
+ifneq ($(SUBDIRS),)
+#
+#         --- Standard Targets for project parent directories ---
+#                                    (See http://software/make.html)
+world: all install
+install:	$(COPYINST)
+ifneq ($(SUBDIRS),NONE)
+all preinstall libinstall dep depend: Make.Common
+all:     	$(SUBDIRS:%=%.d)
+preinstall:	$(SUBDIRS:%=%.d.preinstall)
+libinstall:	$(SUBDIRS:%=%.d.libinstall)
+install: 	$(SUBDIRS:%=%.d.install)
+titles: 	$(SUBDIRS:%=%.d.titles)
+clean:   	$(SUBDIRS:%=%.d.clean)
+dep depend:	$(SUBDIRS:%=%.d.depend)
+execlist:	$(SUBDIRS:%=%.d.execlist)
+endif
+#
+# Define rule patterns %.d.TARGET, which mean go into directory % and
+# build TARGET.  The % can get replaced by all dirs in $SUBDIRS.
+#
+%.d:		; $(MAKE) -f $(MAKEFILE) -C $(@:%.d=%) all
+%.d.preinstall:	; $(MAKE) -f $(MAKEFILE) -C $(@:%.d.preinstall=%) preinstall
+%.d.libinstall:	; $(MAKE) -f $(MAKEFILE) -C $(@:%.d.libinstall=%) libinstall
+%.d.install:	; $(MAKE) -f $(MAKEFILE) -C $(@:%.d.install=%) install
+%.d.clean:	; $(MAKE) -f $(MAKEFILE) -C $(@:%.d.clean=%) clean
+%.d.depend:	; $(MAKE) -f $(MAKEFILE) -C $(@:%.d.depend=%) depend
+%.d.execlist:	; @$(MAKE) -s -f $(MAKEFILE) -C $(@:%.d.execlist=%) execlist
+%.d.titles:	; @$(MAKE) -f $(MAKEFILE) -C $(@:%.d.titles=%) titles || \
+	        sh -c "cd $(@:%.d.titles=%) ; titler $(NEEDTITLES)"
+#
+# Regenerate Make.Common symlinks if they were lost by SVN.
+#
+Make.Common:
+	ln -s ../Make.Common $@
+else
+#
+#       --- Standard Targets for program and library directories ---
+#
+all: checkbin checkdep $(ALL)
+preinstall: $(HDRINST)
+install: checkbin checkdep $(ALLINST)
+world: ; $(MAKE) -f $(MAKEFILE) -C.. all install
+clean: ; -rm -rf $(DIR_OBS)/$(PROJECT)
+ifeq ($(PROJECT), $(PROJBASE))
+execlist: ; @echo $(PROJBASE)
+else
+# This target exists for the "mama-make" pass which only installs
+# libraries.  (After that, the mama-make gets all the programs.)
+libinstall: install
+endif
+#
+# Check if there are any dependencies in the Makefile, if not, run `make dep'
+#
+checkdep: ; @fgrep -e '# Dependencies by Make.Common $$Revision: 2.17 $$' $(MAKEFILE) > /dev/null || $(MAKE) -f $(MAKEFILE) dep
+#
+# Auto-generate dependencies.  This is very GNU C dependent.  The -MM
+# option tells gcc to only generate dependencies for files that are
+# #include'd with ""'s and not <> or system include files.  (So it is
+# generally ok to recompile on a different architecture without remaking
+# the dependencies.)
+#
+# Loop through each file in $SRCS and stick obj/ in front of each
+# .o dependency that gcc outputs (it does not have a way to tell it that
+# our .o's are not going into the current directory, and I couldn't get
+# it to work right with vpath.)  Strip off full paths to DIR_INC since
+# vpath *does* handle this correctly, allowing the same dependencies to
+# be re-used even if DIR_INC is in a different place on a different machine.
+#
+dep depend:
+	@fgrep -e "# Dependencies" $(MAKEFILE) > /dev/null || \
+	echo "# Dependencies" >> $(MAKEFILE)
+	@-rm -rf .Mtmp
+	sed -e 's/^\#\ Dependencies.*$$/\#\ Dependencies by Make.Common $$Revision: 2.17 $$/' -e '/^\#\ Dependencies/q' < $(MAKEFILE) > $(MAKEFILE).New
+	if [ "$(SRCS)" != "" ]; then for i in $(SRCS); do 		\
+	  ( echo;echo '$$(OBJ)/' )| dd bs=8 count=1 2>/dev/null>>.Mtmp;	\
+          DIRNAME=`dirname $$i`; [ $$DIRNAME != "." ] && echo -n $$DIRNAME/ >>.Mtmp; \
+	  $(CMM) -MM $(CFLAGS) $$i >> .Mtmp || exit 1;			\
+	  done;								\
+	  sed 's|$(DIR_INC)/||g' < .Mtmp >> $(MAKEFILE).New;		\
+	  sed 's| /[^ ]*.h||g' < $(MAKEFILE).New > .Mtmp;               \
+	  mv .Mtmp $(MAKEFILE).New;                                     \
+	  mv $(MAKEFILE) $(MAKEFILE).bak;				\
+	  mv $(MAKEFILE).New $(MAKEFILE);				\
+	fi
+	@-rm -rf .Mtmp
+endif
+#
+# Make a tar file snapshot of a current directory tree.
+#
+tar tgz: ; ( PD=`pwd`; PDV=`basename $$PD -$(VERSION)`-$(VERSION); cd .. ; \
+	$(TAR) -czvf $$PDV.tgz --exclude "*~" --exclude "#*#" \
+	--exclude "obj" --exclude "obj.*" \
+	--exclude "*.orig" --exclude "*.rej" --exclude "*.bak" \
+	--exclude ".xvpics" --exclude ".svn" --exclude "RCS" `basename $$PD` )
+
+#
+# Make sure that the $(DIR_OBS)/$(PROJECT) dir at least exists, which is
+# where programs, libraries, and/or .o's go before they are installed.
+# Directories are created with group write permissions.  The ./obj link
+# will be re-created if it doesn't point to a real directory after the
+# $(DIR_OBS)/$(PROJECT) is created.  This also checks that $(DIR_BIN) exists,
+# which is not really correct, but other targets fail if its not done now :-(
+#
+# The ./obj link is now just for convenience.  The makefile rules
+# do not require this to succeed, so it is possible to build with
+# "src" mounted read-only, as long as someone did "make dep" first.
+#
+# 2002-8-1: Clean the project OBS directory if it was previously used for
+#   another version (alternative would be to use /cfht/obs/proj-version).
+#
+checkbin:
+	@test -d $(DIR_BIN) || $(INSTALL) -m 0775 -d $(DIR_BIN)
+	@test -d $(DIR_OBS)/$(PROJECT) || $(INSTALL) -m 0775 -d $(DIR_OBS)/$(PROJECT)
+	@test -d $(OBJ_LINK) || ( rm -rf $(OBJ_LINK) 2> /dev/null && \
+	             ln -s $(DIR_OBSREL)/$(PROJECT) $(OBJ_LINK) ) 2> /dev/null \
+		     || true
+	@if [ "$(VERSION)" != "$(VERSION_DATE)" ]; then 		\
+	   if [ ! -r "$(DIR_OBS)/$(PROJECT)/version-$(VERSION)" ]; then	\
+	     rm -rf $(DIR_OBS)/$(PROJECT)/* ; 				\
+	     touch "$(DIR_OBS)/$(PROJECT)/version-$(VERSION)" ;		\
+	   fi ; 							\
+	fi
+
+# Final installed version of a program depends on the versioned installed
+# program.  This has to depend on the special target .PRECIOUS so that GNU
+# make will not see the versioned file as a temporary and try to remove it
+# at the end of a make install.  See the echo "--> ..." lines in the rest
+# of these targets for a description of what they install.
+#
+# The install line for "program" includes a -s, which strips the executable
+# at the same time that it is copied into the main bin/ directory.
+#
+.PRECIOUS: $(DIR_BIN)/%-$(VERSION)
+
+$(DIR_BIN)/%:	$(DIR_BIN)/%-$(VERSION)
+	@echo "--> Installing link to $(notdir $<) as $(notdir $@)"
+	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || /bin/true
+	@-rm -f $(DIR_BIN)/*.TEXT_FILE_BUSY 2> /dev/null || /bin/true
+	@ln $< $@
+	# @-setuidinst $@
+
+$(DIR_BIN)/%-$(VERSION): scripts/%.sh
+	@echo "--> Installing sh script $(notdir $@)"
+	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || /bin/true
+	@$(INSTALL) -m 0555 $< $@ || ( rm -f $@ && exit 1 )
+
+$(DIR_BIN)/%-$(VERSION): $(EXECNAME)
+	@echo "--> Installing program $(notdir $@)"
+	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || /bin/true
+	@$(INSTSTRIP) -m 0755 $< $@ || ( rm -f $@ && exit 1 )
+	@chmod 0555 $@
+
+$(LIBINST):	$(LIBNAME)
+	@echo "--> Installing archive library $(notdir $<)"
+	@test -d $(DIR_LIB) || $(INSTALL) -m 0775 -d $(DIR_LIB)
+	@$(INSTALL) -m 0444 $< $@ || ( rm -f $@ && exit 1 )
+
+$(SHLIBINST):	$(SHLIBNAME)
+	@echo "--> Installing shared library $(SHLIBNAME)"
+	@test -d $(DIR_LIB) || $(INSTALL) -m 0775 -d $(DIR_LIB)
+	@$(INSTALL) -m 0555 $< $@ || ( rm -f $@ && exit 1 )
+
+$(DIR_CONF)/%: conf/%
+	@echo "--> Installing conf file $(notdir $<)"
+	@test -d $(DIR_CONF) || $(INSTALL) -m 0775 -d $(DIR_CONF)
+	@$(INSTALL) -m 0444 $< $@ || ( rm -f $@ && exit 1 )
+
+$(DIR_MAN)/man1/%: man/%
+	@echo "--> Installing man page $(notdir $<)"
+	@test -d $(DIR_MAN) || $(INSTALL) -m 0775 -d $(DIR_MAN)
+	@test -d $(DIR_MAN)/man1 || $(INSTALL) -m 0775 -d $(DIR_MAN)/man1
+	@$(INSTALL) -m 0444 $< $@ || ( rm -f $@ && exit 1 )
+
+# %%% The rm -f $(DIR_INC)/cfht/foo.h is a temporary hack to remove header
+# files from the old location, so that other programs don't accidentally
+# find an old copy of the header file if their #include statements haven't
+# been updated from "cfht/foo.h" to "libname/foo.h".
+$(DIR_INC)/$(PROJBASE)/%: %
+	@echo "--> Installing header file $<"
+	@rm -f $(DIR_INC)/cfht/$<
+	@test -d $(DIR_INC)/$(PROJBASE) || $(INSTALL) -m 0775 -d $(DIR_INC)/$(PROJBASE)
+	@$(INSTALL) -m 0444 $< $@ || ( rm -f $@ && exit 1 )
+endif
+#
+# Local settings (at CFHT, we want to compile with -Werror for most projects)
+#
+ifeq ($(DIR_SRC)/Make.Local,$(wildcard $(DIR_SRC)/Make.Local))
+include $(DIR_SRC)/Make.Local
+endif
+#
+# End of Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/Makefile
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/Makefile	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/Makefile	(revision 23490)
@@ -0,0 +1,58 @@
+# Top-level Makefile to GigaPixelCamera project tree
+
+default: world-message
+include Make.Common
+world-message:
+	@echo "This is the top-level Makefile for GigaPixelCamera stuff."
+	@echo "NOTE: \`make' commands will result in:"
+	@echo ""
+	@echo "Temporary objects : $(DIR_OBS)     (can be removed to save space)"
+	@echo "Include files     : $(DIR_INC) (not required at run-time)"
+	@echo "Static libraries  : $(DIR_LIB)     (not required at run-time)"
+	@echo "Executables       : $(DIR_BIN)     (add this to your PATH)"
+	@echo ""
+	@echo "Relocate (mv) this directory tree to a place other than $(DIR_ROOT)"
+	@echo "if this is not the desired place for installation."
+	@echo ""
+	@echo "Type \`make world' to build and install everything."
+	@echo "Running \`make dep' first may also be necessary."
+	@echo ""
+	@/bin/false
+
+# Add new modules here, if they are to build automatically.  See Index.
+SUBDIRS=maketools network general fits facility detector
+
+world:	install
+	@echo "Congratulations!  All software successfully installed."
+
+# Before installing, build:
+install: all
+
+# But find all libraries and install them before building any programs:
+all: libinstall
+dep depend: preinstall
+
+# And before building libraries, install the header files, etc.
+libinstall: preinstall
+preinstall: $(DIR_INC)/missing_protos.h checkdirs
+
+# Deal with autofs if necessary for first-time builds.
+# This does not do anything if you do not use automounts.
+checkdirs:
+	for i in $(DIR_CONF) $(DIR_BIN) $(DIR_LIB) $(DIR_INC) $(DIR_OBS); do \
+	  ls $$i > /dev/null 2>&1 ; \
+	  test -L $$i && mkdir -p `/bin/ls -l $$i | sed -e 's/.*-> //'`||true;\
+	done
+
+# missing_protos.h is a hack that doesn't really belong anywhere.
+#
+$(DIR_INC)/missing_protos.h: missing_protos.h
+	@echo "--> Installing header file $<"
+	@test -d $(DIR_INC) || $(INSTALL) -m 0775 -d $(DIR_INC)
+	@$(INSTALL) -m 0444 $< $@
+
+# Create an empty missing_protos.h if none is needed
+missing_protos.h:
+	@test -f $@ || touch $@
+
+include Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/Make.Common
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/Make.Common	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/Make.Common	(revision 23490)
@@ -0,0 +1,1 @@
+link ../Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/Make.Common
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/Make.Common	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/Make.Common	(revision 23490)
@@ -0,0 +1,1 @@
+link ../Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/Makefile
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/Makefile	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/Makefile	(revision 23490)
@@ -0,0 +1,6 @@
+include ../Make.Common
+CCWARN+=$(WERROR)
+include ../Make.Common
+# Dependencies by Make.Common $Revision: 2.17 $
+
+$(OBJ)/pscoords.o: pscoords.c pscoords.h
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/pscoords.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/pscoords.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/pscoords.c	(revision 23490)
@@ -0,0 +1,469 @@
+/* Routine to convert microns in the focal plane to OTA/cell index and posn */
+/* Syntax: pscoords [args] < infile > outfile
+ *  args:
+ *     in=[sky | tp | fp | ota | cell]
+ *     out=[sky | tp | fp | ota | cell]
+ *
+ *   and other arguments required for various transformations: see syntax()
+ */
+/* See PSDC-730-003-01 (OTA FITS) and PSDC-730-005-00 (GPC Arch) for details */
+/* 080930 Sidik added TEST_MAIN - must be defined if you want main() test program. */
+/* 080904 Rev 1.1, renamed from fpota.c */
+/* 071023 Rev 1.0 John Tonry */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#include "pscoords.h"
+
+static char
+#if defined(__GNUC__) && defined(__STDC__)
+__attribute__ ((__unused__))
+#endif
+rcsid[] = "$Id: pscoords.c,v 1.2 2008/09/06 03:26:48 jt Exp jt $";
+
+/* Overall focal plane offset and rotation (um, rad) */
+const PSC_OFFROT_T psc_psc_fpoff={0.,0.,0.};
+
+/* Offsets and rotations of each OTA (um, millirad) */
+const PSC_OFFROT_T psc_otaoff[PSC_NX*PSC_NY]={	/* Offsets and rotations derived o4885 090228 */
+   {   0.0,   0.0,  0.00}, {  20.2, -59.5, -1.23},  /* OTA00 , OTA10 */
+   {  28.1,-138.1,  0.18}, {   2.0, -43.6, -1.22},  /* OTA20 , OTA30 */
+   {  33.6,  91.5, -0.38}, {  20.3,  48.8, -0.81},  /* OTA40 , OTA50 */
+   {  22.5, -67.5, -1.48}, {   0.0,   0.0,  0.00},  /* OTA60 , OTA70 */
+   {   4.8, -29.1,  0.83}, { -51.8, -51.7,  0.95},  /* OTA01 , OTA11 */
+   {  31.8,  -8.6, -0.68}, { -13.7,  11.3, -0.82},  /* OTA21 , OTA31 */
+   {  -2.3,  58.7,  0.92}, {   5.5,  67.5, -0.26},  /* OTA41 , OTA51 */
+   { -11.8,   3.1, -1.55}, {  -3.0,   1.2,  0.36},  /* OTA61 , OTA71 */
+   { -26.1,  40.6,  2.75}, {   0.4, -53.7,  0.53},  /* OTA02 , OTA12 */
+   {  26.6, -56.8, -1.51}, {  19.4,-178.7,  1.78},  /* OTA22 , OTA32 */
+   { -22.5,   4.8, -1.04}, { -14.4,  -1.9,  0.06},  /* OTA42 , OTA52 */
+   {  19.2,  -7.8, -2.04}, {  89.9,  34.9,  1.79},  /* OTA62 , OTA72 */
+   { -24.6,  20.4,  0.15}, {-103.2, -84.4,  1.98},  /* OTA03 , OTA13 */
+   { 110.1,  11.1,  1.11}, {  12.6, -24.9,  0.53},  /* OTA23 , OTA33 */
+   { -50.5,  34.5, -0.73}, { -11.0,  20.0,  0.49},  /* OTA43 , OTA53 */
+   {  17.2, -29.8,  1.52}, {  27.9, -72.3, -0.84},  /* OTA63 , OTA73 */
+   { -43.7,   1.5,  0.23}, { -21.4, -11.6,  0.23},  /* OTA04 , OTA14 */
+   {  64.5, 208.5, -0.36}, { -48.1, -91.1,  0.98},  /* OTA24 , OTA34 */
+   { -14.2,  16.8,  0.01}, { -41.3,   1.9,  0.01},  /* OTA44 , OTA54 */
+   {  10.8,  49.3,  1.34}, {  89.7,  -7.2,  0.43},  /* OTA64 , OTA74 */
+   { -29.2,  38.4,  2.74}, {  20.8,  -7.5, -0.59},  /* OTA05 , OTA15 */
+   { -34.1,  -7.2,  1.70}, { -16.2, -36.1,  0.02},  /* OTA25 , OTA35 */
+   { -51.9,  45.6, -0.60}, {  23.9,  82.4,  0.68},  /* OTA45 , OTA55 */
+   { -34.9,  57.1, -0.47}, {  72.4, -32.0,  0.68},  /* OTA65 , OTA75 */
+   {  16.2,  62.6,  0.17}, { -11.8,   7.5, -0.88},  /* OTA06 , OTA16 */
+   { -82.3, -39.5,  1.37}, {  11.2, -40.0,  0.56},  /* OTA26 , OTA36 */
+   {  -7.5,  31.1, -1.27}, {  26.4,  34.2,  0.26},  /* OTA46 , OTA56 */
+   {  14.1,   3.6, -1.42}, {  20.1,  58.0, -0.23},  /* OTA66 , OTA76 */
+   {   0.0,   0.0,  0.00}, {  50.4,  20.4, -0.47},  /* OTA07 , OTA17 */
+   {  77.9,  -1.5, -0.60}, { -35.0, -47.0,  0.68},  /* OTA27 , OTA37 */
+   { -74.8,   0.3, -0.92}, { -44.6,  -1.6, -1.78},  /* OTA47 , OTA57 */
+   { -50.3,  72.1, -0.47}, {   0.0,   0.0,  0.00}}; /* OTA67 , OTA77 */
+
+#ifdef RUN_TWO
+/* Offsets and rotations of each OTA (um, millirad) */
+const PSC_OFFROT_T psc_otaoff[PSC_NX*PSC_NY]={	/* Offsets and rotations derived o4699-o4724 */
+   {   0.0,   0.0,  0.0 },  {  57.4, -71.7,  0.41},  /* OTA00 , OTA10 */
+   {  35.0,-136.4,  0.29},  {  -7.6, -47.4,  2.20},  /* OTA20 , OTA30 */
+   {  -4.1,  75.8,  0.52},  {  13.9,  19.4, -1.73},  /* OTA40 , OTA50 */
+   {  27.3, -24.3,  0.62},  {   0.0,   0.0,  0.0 },  /* OTA60 , OTA70 */
+   {  26.3, -36.1,  0.57},  { -54.7, -89.1,  1.64},  /* OTA01 , OTA11 */
+   {  -1.1, -33.2, -1.09},  {  -4.7, -71.7, -0.25},  /* OTA21 , OTA31 */
+   {  25.6,  51.8,  0.62},  {   2.1,  55.6,  0.32},  /* OTA41 , OTA51 */
+   {  44.5,  41.5,  0.15},  {  53.8,  52.8,  0.33},  /* OTA61 , OTA71 */
+   {   0.9,  25.3,  2.30},  { -33.1, -63.5,  2.85},  /* OTA02 , OTA12 */
+   {  27.9, -87.0, -0.20},  {  62.6, -20.8,  0.50},  /* OTA22 , OTA32 */
+   { -35.4, -14.7, -1.42},  {  24.6,  53.9, -0.82},  /* OTA42 , OTA52 */
+   {  29.9,  36.7, -1.10},  { 100.5,  21.9,  1.27},  /* OTA62 , OTA72 */
+   {  -1.1,  26.8, -1.16},  {  31.0, -46.0,  3.07},  /* OTA03 , OTA13 */
+   { 113.2,  53.7,  0.39},  {  65.1, -17.3, -0.98},  /* OTA23 , OTA33 */
+   { -54.9,  12.8,  0.10},  {  19.9,  30.6,  1.08},  /* OTA43 , OTA53 */
+   {  35.3, -12.8,  1.68},  {  60.8,  30.3, -0.37},  /* OTA63 , OTA73 */
+   { -79.8, -28.2,  0.53},  { -50.8, -63.1,  0.21},  /* OTA04 , OTA14 */
+   {  33.4, -38.1, -0.18},  {   7.5, -89.4,  0.67},  /* OTA24 , OTA34 */
+   {  -9.7,  56.5, -0.71},  {  -2.4,  42.5,  0.42},  /* OTA44 , OTA54 */
+   {  -0.4,  32.8,  2.13},  {  23.1, -48.4,  0.41},  /* OTA64 , OTA74 */
+   { -87.1,   7.8,  1.24},  { -42.1, -62.0,  2.01},  /* OTA05 , OTA15 */
+   { -77.4,   2.4,  1.59},  { -38.4, -37.6,  1.00},  /* OTA25 , OTA35 */
+   { -23.2,  50.4, -1.81},  {   1.0,  58.4,  0.33},  /* OTA45 , OTA55 */
+   { -28.3,   7.1, -0.69},  {   3.8, -60.3, -0.15},  /* OTA65 , OTA75 */
+   { -20.0,  28.7,  1.57},  { -26.0,  45.6,  3.08},  /* OTA06 , OTA16 */
+   { -36.4, -69.0,  0.49},  {  26.1,  -4.9, -1.47},  /* OTA26 , OTA36 */
+   { -24.2,  98.6,  0.09},  { -51.5,  14.7, -0.88},  /* OTA46 , OTA56 */
+   {  16.6,  31.0, -1.34},  {   7.1,  12.4, -0.13},  /* OTA66 , OTA76 */
+   {   0.0,   0.0,  0.0 },  {  -6.5,  39.8, -0.03},  /* OTA06 , OTA17 */
+   { -15.7,   3.9,  0.65},  { -26.4,  16.5,  0.07},  /* OTA27 , OTA37 */
+   { -41.1,  76.3,  0.56},  { -60.8,  43.0, -0.16},  /* OTA47 , OTA57 */
+   { -52.6,  65.1,  0.58},  {   0.0,   0.0,  0.0 }}; /* OTA67 , OTA77 */
+#endif
+
+#ifdef FIRST_GUESS
+/* Offsets and rotations of each OTA (um, rad) */
+PSC_OFFROT_T psc_otaoff[PSC_NX*PSC_NY]={	/* Offsets and rotations derived o4678 */
+   {   0.0,   0.0, 0.00000},  {  46.8, -82.5, 0.00102},  /* OTA00 , OTA10 */
+   {  29.1,-130.8, 0.00145},  {   1.7, -46.3, 0.00315},  /* OTA20 , OTA30 */
+   {  14.4,  70.8, 0.00095},  {  20.0,  30.3,-0.00145},  /* OTA40 , OTA50 */
+   {   4.0,  -1.2, 0.00121},  {   0.0,   0.0, 0.00000},  /* OTA60 , OTA70 */
+   {  -2.9, -67.9, 0.00090},  { -98.0,-105.0, 0.00107},  /* OTA01 , OTA11 */
+   { -22.2, -23.0,-0.00171},  {  12.0, -72.2,-0.00056},  /* OTA21 , OTA31 */
+   {  57.1,  33.0, 0.00030},  {  18.6,  54.9,-0.00055},  /* OTA41 , OTA51 */
+   {  22.0,  80.7,-0.00063},  {  21.4,  81.2, 0.00027},  /* OTA61 , OTA71 */
+   { -16.9,  23.8, 0.00248},  { -32.3, -46.8, 0.00181},  /* OTA02 , OTA12 */
+   {  58.7, -45.0,-0.00045},  { 118.1,  -3.0, 0.00076},  /* OTA22 , OTA32 */
+   {  32.3, -48.0,-0.00113},  {  76.6,  25.5,-0.00131},  /* OTA42 , OTA52 */
+   {  46.2,  48.4,-0.00198},  { 104.5,  39.2, 0.00182},  /* OTA62 , OTA72 */
+   {  -1.2,  42.8,-0.00095},  {  43.2, -10.4, 0.00274},  /* OTA03 , OTA13 */
+   { 139.5, 114.3, 0.00086},  {  96.9,   7.9, 0.00011},  /* OTA23 , OTA33 */
+   { -18.8, -22.2, 0.00117},  {  43.1, -23.5, 0.00148},  /* OTA43 , OTA53 */
+   {  44.9, -33.1, 0.00138},  {  69.1,  25.9, 0.00006},  /* OTA63 , OTA73 */
+   { -87.3, -12.1, 0.00112},  { -48.1, -43.0, 0.00014},  /* OTA04 , OTA14 */
+   {  10.9,  20.4, 0.00041},  { -29.1, -59.1, 0.00185},  /* OTA24 , OTA34 */
+   { -44.8,  30.6, 0.00053},  { -25.0, -15.0, 0.00084},  /* OTA44 , OTA54 */
+   { -15.0,  -1.9, 0.00182},  {  18.0, -58.7, 0.00067},  /* OTA64 , OTA74 */
+   { -92.8,   9.3, 0.00202},  { -55.1, -63.4, 0.00168},  /* OTA05 , OTA15 */
+   {-125.6,  35.0, 0.00142},  {-112.7,  -6.6, 0.00137},  /* OTA25 , OTA35 */
+   { -90.2,  36.4,-0.00160},  { -34.4,  20.9, 0.00005},  /* OTA45 , OTA55 */
+   { -25.9, -11.9,-0.00160},  {  19.8, -59.5,-0.00020},  /* OTA65 , OTA75 */
+   {   1.3,  43.8, 0.00208},  {   0.2,  21.7, 0.00234},  /* OTA06 , OTA16 */
+   { -47.8, -61.4,-0.00023},  { -13.6,  21.8,-0.00201},  /* OTA26 , OTA36 */
+   { -50.1, 104.1,-0.00061},  { -34.3,  14.9,-0.00148},  /* OTA46 , OTA56 */
+   {  72.3,  53.8,-0.00213},  {  58.0,  47.6,-0.00012},  /* OTA66 , OTA76 */
+   {   0.0,   0.0, 0.00000},  {  31.1,  44.6, 0.00113},  /* OTA07 , OTA17 */
+   {  -8.2,   5.3, 0.00087},  { -39.8,  35.0, 0.00031},  /* OTA27 , OTA37 */
+   { -47.8,  85.1, 0.00135},  { -28.8,  51.0, 0.00037},  /* OTA47 , OTA57 */
+   {  -2.6,  91.5, 0.00071},  {   0.0,   0.0, 0.00000}}; /* OTA67 , OTA77 */
+#endif
+
+static int DOOFFSET;	/* Do these offsets or no? */
+
+#if 0
+#define IRAS	/* Gnomonic? irsa.ipac.edu/IRASdocs/surveys/coordproj.html */
+#define PSC_REFRACT_CONST 55.7	/* Standard refraction ("/tanz) at STP */
+#endif
+
+/* Enable application of chip offsets? */
+int psc_do_chipoff(int doit)
+{
+   DOOFFSET = doit;
+   return(0);
+}
+
+/* Convert a focal plane position to OTA otax,otay, Cell cellx,celly, Pixel */
+int psc_fp_to_pixel(double xfp, double yfp, 	/* FP position (um) */
+		int *ota_xid, int *ota_yid,	/* OTA ID (0:7) */
+		double *xota, double *yota)	/* OTA position (pix) */
+{
+   double mechgap=0.5*(PSC_HMECH-PSC_HDIE);	/* Assume equal L/R/T chip gap */
+   int idx;				/* Index of this OTA in otaoff */
+   int lhs;				/* Left/right hand side = +1/-1 */
+   double xc, yc, x, y, xp, yp;
+
+/* Position in FP after removing offset and rotation */
+   if(DOOFFSET) {
+      x =  (xfp-psc_fpoff.dx)*cos(psc_fpoff.rot) + (yfp-psc_fpoff.dy)*sin(psc_fpoff.rot);
+      y = -(xfp-psc_fpoff.dx)*sin(psc_fpoff.rot) + (yfp-psc_fpoff.dy)*cos(psc_fpoff.rot);
+   } else {
+      x = xfp;
+      y = yfp;
+   }
+
+/* Guess at which side we are on */
+   lhs = x > 0 ? +1 : -1;
+
+/* Guess at which OTA this is */
+   *ota_xid = NINT(PSC_NX/2-0.5-x/PSC_HMECH);
+   *ota_yid = NINT((y-lhs*0.5*(PSC_VMOFF+PSC_VMECH-PSC_VDIE-2*mechgap))/PSC_VMECH+(PSC_NY/2-0.5));
+/* Stop at the edges of the focal plane */
+   if (*ota_xid < 0)       *ota_xid = 0;
+   if (*ota_xid >= PSC_NX) *ota_xid = PSC_NX-1;
+   if (*ota_yid < 0)       *ota_yid = 0;
+   if (*ota_yid >= PSC_NY) *ota_yid = PSC_NY-1;
+   idx = *ota_xid+*ota_yid*PSC_NX;
+
+/* Center of nominal mechanical PSC_HMECH,PSC_VMECH envelope wrt FP center */
+   xc = ((PSC_NX/2-0.5)-*ota_xid) * PSC_HMECH;
+   yc = (*ota_yid-(PSC_NY/2-0.5)) * PSC_VMECH + lhs*0.5*(PSC_VMOFF+PSC_VMECH-PSC_VDIE-2*mechgap);
+
+/* Center of OTA (8x8 set of cells) within mechanical envelope wrt FP center */
+   xc -= lhs*(0.5*PSC_HMECH - mechgap - PSC_LBORDER - PSC_NX/2*PSC_HCELL - (PSC_NX/2-0.5)*PSC_VSTREET);
+   yc -= lhs*(0.5*PSC_VMECH - mechgap - PSC_TBORDER - PSC_NY/2*PSC_VCELL - (PSC_NY/2-0.5)*PSC_HSTREET);
+
+/* Position wrt nominal OTA center prior to offset and rotation correction */
+   xp = x - xc;
+   yp = y - yc;
+
+/* Position wrt OTA center after correction for offset and rotation */
+   if(DOOFFSET) {
+      x =  (xp-psc_otaoff[idx].dx)*cos(psc_otaoff[idx].rot*0.001) + 
+	 (yp-psc_otaoff[idx].dy)*sin(psc_otaoff[idx].rot*0.001);
+      y = -(xp-psc_otaoff[idx].dx)*sin(psc_otaoff[idx].rot*0.001) + 
+	 (yp-psc_otaoff[idx].dy)*cos(psc_otaoff[idx].rot*0.001);
+   } else {
+      x = xp;
+      y = yp;
+   }
+
+/* Position in pixels relative to OTA origin */
+   *xota =  (lhs*x + (PSC_NX/2*PSC_HCELL + (PSC_NX/2-0.5)*PSC_VSTREET)) / PSC_PIXEL;
+   *yota = -(lhs*y - (PSC_NY/2*PSC_VCELL + (PSC_NY/2-0.5)*PSC_HSTREET)) / PSC_PIXEL;
+
+   return(0);
+}
+
+/* Convert a pixel position in OTA ota_xid,ota_yid to FP */
+int psc_pixel_to_fp(int ota_xid, int ota_yid,	/* OTA ID (0:7) */
+		double xota, double yota,	/* OTA position (pix) */
+		double *xfp, double *yfp)	/* FP position (um) */
+{
+   int idx=ota_xid+ota_yid*PSC_NX;		/* Index of this OTA in otaoff */
+   double mechgap=0.5*(PSC_HMECH-PSC_HDIE);	/* Assume equal L/R/T chip gap */
+   int lhs=ota_xid < PSC_NX/2 ? +1 : -1;	/* Left/right hand side = +1/-1 */
+   double xc, yc, x, y, xp, yp;
+
+/* Pixel position in um relative to OTA center */
+   x = lhs * ( xota*PSC_PIXEL - (PSC_NX/2*PSC_HCELL + (PSC_NX/2-0.5)*PSC_VSTREET));
+   y = lhs * (-yota*PSC_PIXEL + (PSC_NY/2*PSC_VCELL + (PSC_NY/2-0.5)*PSC_HSTREET));
+
+/* Position wrt nominal OTA center after its offset and rotation */
+   if(DOOFFSET) {
+      xp = psc_otaoff[idx].dx + x*cos(psc_otaoff[idx].rot*0.001) - y*sin(psc_otaoff[idx].rot*0.001);
+      yp = psc_otaoff[idx].dy + x*sin(psc_otaoff[idx].rot*0.001) + y*cos(psc_otaoff[idx].rot*0.001);
+   } else {
+      xp = x;
+      yp = y;
+   }
+
+/* Center of nominal mechanical PSC_HMECH,PSC_VMECH envelope wrt FP center */
+   xc = ((PSC_NX/2-0.5)-ota_xid) * PSC_HMECH;
+   yc = (ota_yid-(PSC_NY/2-0.5)) * PSC_VMECH + lhs*0.5*(PSC_VMOFF+PSC_VMECH-PSC_VDIE-2*mechgap);
+
+/* Center of OTA (8x8 set of cells) within mechanical envelope wrt FP center */
+   xc -= lhs*(0.5*PSC_HMECH - mechgap - PSC_LBORDER - PSC_NX/2*PSC_HCELL - (PSC_NX/2-0.5)*PSC_VSTREET);
+   yc -= lhs*(0.5*PSC_VMECH - mechgap - PSC_TBORDER - PSC_NY/2*PSC_VCELL - (PSC_NY/2-0.5)*PSC_HSTREET);
+
+/* Position within FP */
+   x = xp + xc;
+   y = yp + yc;
+
+/* Final position from FP offset and rotation */
+   if(DOOFFSET) {
+      *xfp = psc_fpoff.dx + x*cos(psc_fpoff.rot) - y*sin(psc_fpoff.rot);
+      *yfp = psc_fpoff.dy + x*sin(psc_fpoff.rot) + y*cos(psc_fpoff.rot);
+   } else {
+      *xfp = x;
+      *yfp = y;
+   }
+
+   return(0);
+}
+
+/* Convert an OTA pixel position to cell ID and cell coords */
+int psc_pixel_to_cell(double xota, double yota,	/* OTA position (pix) */
+		  int *cell_xid, int *cell_yid,	/* Cell ID (0:7) or -1 */
+		  double *xcell, double *ycell)	/* Cell position (pix) */
+{
+   double x, y;
+   x = xota*PSC_PIXEL / (PSC_HCELL+PSC_VSTREET);
+   *cell_xid = (int)x;
+   *xcell = (x - (int)x) * (PSC_HCELL+PSC_VSTREET) / PSC_PIXEL;
+   if(x < 0 || *cell_xid > PSC_NX-1 || 
+      (x-*cell_xid) > 1-PSC_VSTREET/(PSC_HCELL+PSC_VSTREET)) *cell_xid = -1;
+   *xcell = PSC_HCELL/PSC_PIXEL - *xcell;
+
+   y = yota*PSC_PIXEL / (PSC_VCELL+PSC_HSTREET);
+   *cell_yid = (int)y;
+   *ycell = (y - (int)y) * (PSC_VCELL+PSC_HSTREET) / PSC_PIXEL;
+   if(y < 0 || *cell_yid > PSC_NY-1 ||
+      (y-*cell_yid) > 1-PSC_HSTREET/(PSC_VCELL+PSC_HSTREET)) *cell_yid = -1;
+
+   return(0);
+}
+
+/* Convert a cell position and ID to OTA coords */
+int psc_cell_to_pixel(int cell_xid, int cell_yid,	/* Cell ID (0:7) */
+		  double xcell, double ycell,	/* Cell position (pix) */
+		  double *xota, double *yota)	/* OTA position (pix) */
+{
+   *xota = (PSC_HCELL/PSC_PIXEL - xcell) + cell_xid*(PSC_HCELL+PSC_VSTREET) / PSC_PIXEL;
+   *yota = ycell + cell_yid*(PSC_VCELL+PSC_HSTREET) / PSC_PIXEL;
+   return(0);
+}
+
+/* Evaluate an optical model: arcsec -> microns notionally */
+/* Offset, scale with distortion, rotate */
+int psc_psoptics(double x, double y, double dx, double dy, double dpa, 
+	 double pscale, double d3, double *xfp, double *yfp)
+{
+   double w2=((x-dx)*(x-dx)+(y-dy)*(y-dy));
+   x = pscale * (1.0 + d3*w2) * (x-dx);
+   y = pscale * (1.0 + d3*w2) * (y-dy);
+/* Apply any extra TP-FP rotation */
+   *xfp =  x * cos(dpa) + y * sin(dpa);
+   *yfp = -x * sin(dpa) + y * cos(dpa);
+   return(0);
+}
+
+/* Evaluate an inverse optical model: microns -> arcsec notionally */
+/* Offset, scale with *small* distortion, rotate */
+int psc_invoptics(double xfp, double yfp, double dx, double dy, double dpa, 
+	  double pscale, double d3, double *x, double *y)
+{
+   double xp, yp;
+/* Undo any extra TP-FP rotation */
+   xp = (xfp * cos(dpa) - yfp * sin(dpa)) / pscale;
+   yp = (xfp * sin(dpa) + yfp * cos(dpa)) / pscale;
+   *x = xp / (1.0 + d3*(xp*xp+yp*yp)) + dx;
+   *y = yp / (1.0 + d3*(xp*xp+yp*yp)) + dy;
+   return(0);
+}
+
+
+/* Project RA,Dec (a,d) to the tangent plane (x,y) at (a0,d0,pa) [radians] */
+/* y is rotated CCW by pa from N; NOTE: x is west when PA = 0 (pos parity) */
+int psc_tproject(double a, double d, double a0, double d0, double pa,
+	 double density, double zenith, double vertical, 
+	 double *x, double *y)
+{
+#ifndef IRAS
+   double pdotx, pdoty, pdotz, E, N, dx, dy, z, Up, Horiz, sec2rad=atan(1.0)/(45*3600);
+   pdotx = cos(a0)*cos(d0)*cos(a)*cos(d) + 
+      sin(a0)*cos(d0)*sin(a)*cos(d) + sin(d0)*sin(d);
+   pdoty = -sin(a0)*cos(a)*cos(d) + cos(a0)*sin(a)*cos(d);
+   pdotz = -cos(a0)*sin(d0)*cos(a)*cos(d) -
+      sin(a0)*sin(d0)*sin(a)*cos(d) + cos(d0)*sin(d);
+   E = pdoty / pdotx;
+   N = pdotz / pdotx;
+   *x = -E*cos(pa) + N*sin(pa);
+   *y =  E*sin(pa) + N*cos(pa);
+/* Differential refraction? */
+   if(density > 0) {
+/* Rotate to vertical */
+      Horiz =  *x * cos(vertical) + *y * sin(vertical);
+      Up = -*x * sin(vertical) + *y * cos(vertical);
+      z = sqrt(Horiz*Horiz+(zenith-Up)*(zenith-Up));
+      dx = -density*sec2rad*PSC_REFRACT_CONST*tan(z)*Horiz/z;
+      dy = density*sec2rad*PSC_REFRACT_CONST*(tan(z)*(zenith-Up)/z - tan(zenith));
+      Horiz += dx;
+      Up += dy;
+/* Rotate back */
+      *x =  Horiz * cos(vertical) - Up * sin(vertical);
+      *y =  Horiz * sin(vertical) + Up * cos(vertical);
+   }
+
+#else
+   double C, F, E, N;
+   C = cos(d)*cos(a-a0);
+   F = 1/(sin(d0)*sin(d)+C*cos(d0));
+   N = -F*(cos(d0)*sin(d) - C*sin(d0));
+   E = -F*cos(d)*sin(a-a0);
+   *x =  E*cos(pa) + N*sin(pa);
+   *y = -E*sin(pa) + N*cos(pa);
+#endif
+   return(0);
+}
+
+/* Convert tangent plane (x,y) at (a0,d0,pa) to RA,Dec (a,d) [radians] */
+/* y is rotated CCW by pa from N; NOTE: x is west when PA = 0 (pos parity) */
+int psc_tplonglat(double x, double y, double a0, double d0, double pa,
+	  double density, double zenith, double vertical, 
+	  double *a, double *d)
+{
+#ifndef IRAS
+   double px, py, pz, E, N, pi=4*atan(1.0), dx, dy, z, sec2rad=atan(1.0)/(45*3600);
+   double Horiz, Up;
+/* Undo differential refraction? */
+   if(density > 0) {
+/* Rotate to vertical */
+      Horiz =  x * cos(vertical) + y * sin(vertical);
+      Up = -x * sin(vertical) + y * cos(vertical);
+      z = sqrt(Horiz*Horiz+(zenith-Up)*(zenith-Up));
+      dx = -density*sec2rad*PSC_REFRACT_CONST*tan(z)*Horiz/z;
+      dy = density*sec2rad*PSC_REFRACT_CONST*(tan(z)*(zenith-Up)/z - tan(zenith));
+      Horiz -= dx;
+      Up -= dy;
+/* Rotate back */
+      x =  Horiz * cos(vertical) - Up * sin(vertical);
+      y =  Horiz * sin(vertical) + Up * cos(vertical);
+   }
+   E = -x*cos(pa) + y*sin(pa);
+   N =  x*sin(pa) + y*cos(pa);
+   px = cos(a0)*cos(d0) - E*sin(a0) - N*cos(a0)*sin(d0);
+   py = sin(a0)*cos(d0) + E*cos(a0) - N*sin(a0)*sin(d0);
+   pz = sin(d0) + N*cos(d0);
+   *a = atan2(py, px);
+   if(pz >= 1)       *d =  pi/2;
+   else if(pz <= -1) *d = -pi/2;
+   else              *d = asin(pz);
+#else
+   double DD, B, XX, YY, E, N;
+   E = -x*cos(pa) + y*sin(pa);
+   N =  x*sin(pa) + y*cos(pa);
+   DD = atan(sqrt(x*x+y*y));
+   B = atan2(-x, y);
+   XX = sin(d0)*sin(DD)*cos(B) + cos(d0)*cos(DD);
+   YY = sin(DD)*sin(B);
+   *a = a0 + atan2(YY, XX);
+   *d = asin(sin(d0)*cos(DD)-cos(d0)*sin(DD)*cos(B));
+#endif
+   return(0);
+}
+
+#ifdef TEST_MAIN
+static
+void bomb(char *msg)
+{
+   fprintf(stderr, "%s", msg);
+   exit(1);
+}
+
+static
+void syntax(char *prog)
+{
+   printf("Syntax: %s [options] < input_coords > output coords\n", prog);
+   printf("\nOptions:\n");
+   printf("  in=[sky | tp | fp | ota | cell]     Select input coord type\n");
+   printf("  out=[sky | tp | fp | ota | cell]    Select output coord type\n");
+   printf("\nRequired extra arguments:\n");
+   printf("  sky:   requires ra=R dec=D pa=P for boresight [deg]\n");
+   printf("  tp-fp: requires dx=X dy=Y [\"] dpa=P [deg] sc=S [um/\"] [d3=D [\"^-2]] for optical model [deg]\n");
+   printf("\nOptional extra arguments:\n");
+   printf("  offset=[t|f]    Apply OTA/FP offsets (default f)\n");
+   printf("\nInputs and outputs:\n");
+   printf("  sky:   RA, Dec [deg]\n");
+   printf("  tp:    x,y rotated by PA from N [arcsec]\n");
+   printf("  fp:    xfp,yfp [um] (aka camera coords)\n");
+   printf("  ota:   OTAxy ID and xota,yota [pix]\n");
+   printf("  cell:  OTAxy Cellxy IDs and xcell,ycell [pix]\n");
+   printf("   (OTAxy can be omitted for OTA-Cell conversions only\n");
+   printf("\nSynonyms:\n");
+   printf("  ra=R    or    -ra R     Boresight pointing (deg)\n");
+   printf("  dec=D   or    -dec D    Boresight pointing (deg)\n");
+   printf("  pa=P    or    -pa P     PA of image on sky (deg)\n");
+   printf("  dx=X    or    -dx X     FP offset wrt boresight (arcsec)\n");
+   printf("  dy=Y    or    -dy Y     FP offset wrt boresight (arcsec)\n");
+   printf("  dpa=P   or    -dpa P    FP rotation wrt PA (deg)\n");
+   printf("  sc=S    or    -sc S     Plate scale (um/arcsec)\n");
+   printf("  d3=D    or    -d3 D     Cubic distortiont (arcsec^-2)\n");
+   printf("  offset=t         or    -dooff    Apply OTA offsets? (def=f)\n");
+   printf("  offset=f         or    -nooff    Apply OTA offsets? (def=f)\n");
+   printf("  in=sky out=tp    or    -skytp\n");
+   printf("  in=tp out=fp     or    -tpfp\n");
+   printf("  in=fp out=ota    or    -fpota\n");
+   printf("  in=cell out=ota  or    -clota\n");
+   printf("  in=ota out=fp    or    -otafp\n");
+   printf("\nTo implement differential refraction in Sky-TP:\n");
+   printf("  alt=A   or    -alt A     Altitude (deg)\n");
+   printf("  dens=D  or    -dens D    P/T (wrt STP, 0.71 for HK)\n");
+   printf("  vert=V  or    -vert V    Rotator angle (deg)\n");
+   printf("\nExamples:\n");
+   printf(" echo 33 13 277.36 61.79 | pscoords out=sky in=cell ra=105 dec=7 pa=10 dx=0 dy=112 dpa=20 sc=38.856\n");
+   printf(" -> 105.100000   7.100022\n");
+   printf(" echo 105.1 7.1 | pscoords out=cell in=sky ra=105 dec=7 pa=10 dx=0 dy=112 dpa=20 sc=38.856\n");
+   printf(" -> 33 13    277.36     61.79\n");
+   printf("(note slight bug in Sky<->TP projections depending on distance from pole)\n");
+   printf("\nVersion:  %s\n", rcsid);
+
+   exit(0);
+}
+#endif /* TEST_MAIN */
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/pscoords.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/pscoords.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpscoords/pscoords.h	(revision 23490)
@@ -0,0 +1,200 @@
+/* Three-quarter-assed pscoords.h until jt writes me a real one */
+#define NINT(x) (x<0?(int)((x)-0.5):(int)((x)+0.5))
+
+/* Silicon layout of OTAs (um) */
+#define PSC_PIXEL     10.0	/* Pixel size of an OTA */
+#define PSC_HCELL   5900.0	/* Horizontal cell size */
+#define PSC_VCELL   5980.0	/* Vertical cell size */
+#define PSC_HSTREET  120.0	/* Horizontal street between cells (HS) */
+#define PSC_VSTREET  180.0	/* Vertical street between cells (VS) */
+#define PSC_LBORDER  442.0	/* Left border (to left-most cell) (LB) */
+#define PSC_RBORDER  418.0	/* Right border (to right-most vertical street) (RB) */
+#define PSC_TBORDER  354.5	/* Top border (to top-most cell) (TB) */
+#define PSC_BBORDER  975.5	/* Bottom border (to lowest horizontal street) (BB) */
+#define PSC_HDIE   49500.0	/* Horizontal size of silicon die */
+#define PSC_VDIE   50130.0	/* Vertical size of silicon die */
+
+/* Mechanical layout of OTAs (um) */
+#define PSC_HMECH  (1.957*25400)	/* Horizontal mech spacing of OTA placement */
+#define PSC_VMECH  (2.025*25400)	/* Vertical mech spacing of OTA placement */
+#define PSC_VMOFF (PSC_VDIE-(1.568+0.375)*25400) /* Vert die offset between sides */
+
+#define PSC_REFRACT_CONST 60.0	/* Standard refraction ("/tanz) at STP */
+
+/* Number of OTAs populating focal plane */
+#define PSC_NX	     8  /* Number of OTAs in FP in x */
+#define PSC_NY	     8  /* Number of OTAs in FP in y */
+
+/* Cell layout, looking down on back illuminated cell:
+ *  NOTE: center of pixel 0,0 is physical location 0.5,0.5 pixel;
+ *        cell origin is lower left edge of P0,0.
+ *
+ *                +------------------+
+ *                | P0,597  P589,597 |
+ *                |  ...    ...      |
+ *     Amplifier<<| P0,0    P589,0   |
+ *                +------------------+
+ */
+
+/* OTA layout, looking down on back illuminated CCD:
+ * NOTE:  OTA coordinates increase in x from Cell xy0n to Cell xy7n, y from
+ *          Cell xyn0 to Cell xyny, origin is P0,0 in C00, units are pixels.
+ *        "center" of OTA is the middle of the streets between cell 3 and 4
+ *        therefore center is at (xota, yota) = (2423.0, 2434.0)
+ *        Cell coordinates are flipped wrt OTA coordinates, so the x=589
+ *        pixel is the left most one in OTA coordinates, i.e in OTA
+ *        coordinates a cell looks like:    +---------------+
+ *                                          | 589,597 0,597 |
+ *                                          | ...      ...  |
+ *                                          | 589,0   0,0   |> Amp
+ *                                          +---------------+
+ *    +--------Top----------+
+ *    |         TB          |
+ *    L  C07 VS ... C77 VS  R  Cnn is 590x598 10um pixels
+ *    e   HS         HS     i
+ *    fLB...         ...  RBg
+ *    t  C00 VS ... C70 VS  h
+ *    |   HS         HS     t
+ *    |         BB          |
+ *    +-------Bottom--------+ (amp side)
+ */
+
+/* FP layout, looking down on FP:
+ *
+ * NOTE: edge to edge spacing of dice is HMECH,VMECH;
+ *       RHS vertically offset by VMOFF from LHS
+ *          to align pixel i,597 on LHS with pixel i,0 on RHS;
+ *
+ *       "center" is midpoint: OTA33 Cell00 Pix00 and OTA44 Cell00 Pix00
+ *
+ *       Physical coordinate convention runs right to left in x, in 
+ *       order to comply with the "sky view" convention.
+ *
+ *          +--B--+ +--B--+ +--B--+ (VMOFF)
+ *          |     | |     | |     | +--T--+ +--T--+ +--T--+
+ *          R 17  L R 27  L R 37  L |     | |     | |     |
+ *          |     | |     | |     | L 47  R L 57  R L 67  R
+ *          +--T--+ +--T--+ +--T--+ |     | |     | |     |
+ *  +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+
+ *  |     | |     | |     | |     | +--T--+ +--T--+ +--T--+ +--T--+
+ *  R 06  L R 16  L R 26  L R 36  L |     | |     | |     | |     |
+ *  |     | |     | |     | |     | L 46  R L 56  R L 66  R L 76  R
+ *  +--T--+ +--T--+ +--T--+ +--T--+ |     | |     | |     | |     |
+ *  +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+
+ *  |     | |     | |     | |     | +--T--+ +--T--+ +--T--+ +--T--+
+ *  R 05  L R 15  L R 25  L R 35  L |     | |     | |     | |     |
+ *  |     | |     | |     | |     | L 45  R L 55  R L 65  R L 75  R
+ *  +--T--+ +--T--+ +--T--+ +--T--+ |     | |     | |     | |     |
+ *  +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+
+ *  |     | |     | |     | |     | +--T--+ +--T--+ +--T--+ +--T--+
+ *  R 04  L R 14  L R 24  L R 34  L |     | |     | |     | |     |
+ *  |     | |     | |     | |     | L 44  R L 54  R L 64  R L 74  R
+ *  +--T--+ +--T--+ +--T--+ +--T--+ |     | |     | |     | |     |
+ *  +--B--+ +--B--+ +--B--+ +--B--+X+--B--+ +--B--+ +--B--+ +--B--+
+ *  |     | |     | |     | |     | +--T--+ +--T--+ +--T--+ +--T--+
+ *  R 03  L R 13  L R 23  L R 33  L |     | |     | |     | |     |
+ *  |     | |     | |     | |     | L 43  R L 53  R L 63  R L 73  R
+ *  +--T--+ +--T--+ +--T--+ +--T--+ |     | |     | |     | |     |
+ *  +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+
+ *  |     | |     | |     | |     | +--T--+ +--T--+ +--T--+ +--T--+
+ *  R 02  L R 12  L R 22  L R 32  L |     | |     | |     | |     |
+ *  |     | |     | |     | |     | L 42  R L 52  R L 62  R L 72  R
+ *  +--T--+ +--T--+ +--T--+ +--T--+ |     | |     | |     | |     |
+ *  +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+
+ *  |     | |     | |     | |     | +--T--+ +--T--+ +--T--+ +--T--+
+ *  R 01  L R 11  L R 21  L R 31  L |     | |     | |     | |     |
+ *  |     | |     | |     | |     | L 41  R L 51  R L 61  R L 71  R
+ *  +--T--+ +--T--+ +--T--+ +--T--+ |     | |     | |     | |     |
+ *          +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+ +--B--+
+ *          |     | |     | |     | +--T--+ +--T--+ +--T--+
+ *          R 10  L R 20  L R 30  L |     | |     | |     |           y
+ *          |     | |     | |     | L 40  R L 50  R L 60  R           ^
+ *          +--T--+ +--T--+ +--T--+ |     | |     | |     |           |
+ *                                  +--B--+ +--B--+ +--B--+           |
+ *                                                            x  <----+
+ */
+
+/* Structure for tweaks of OTA positions wrt mechanical */
+typedef struct {
+      double dx;	/* OTA x origin found at dx wrt mechanical (um) */
+      double dy;	/* OTA y origin found at dy wrt mechanical (um) */
+      double rot;	/* OTA rotated CCW by rot wrt mechanical (rad) */
+} PSC_OFFROT_T;
+
+/* Overall focal plane offset and rotation (um, rad) */
+const PSC_OFFROT_T psc_fpoff;
+
+/* Offsets and rotations of each OTA (um, millirad) */
+const PSC_OFFROT_T psc_otaoff[PSC_NX*PSC_NY];
+
+/**********************/
+/* Normal Application */
+/**********************/
+/*
+ * To go from a position (a,d) relative to (a0,d0,pa) pointing to cell coords:
+ * ---------------------------------------------------------------------------
+ *   psc_tproject(a, d, a0, d0, pa, density, pi/2-alt, vertical, &x, &y);
+ *   psc_psoptics(x/sec2rad, y/sec2rad, dx, dy, dpa, pscale, d3, &xfp, &yfp);
+ *   psc_fp_to_pixel(xfp, yfp, &ota_xid, &ota_yid, &xota, &yota);
+ *   psc_pixel_to_cell(xota, yota, &cell_xid, &cell_yid, &xcell, &ycell);
+ *
+ * To go from cell coords to a position (a,d) relative to (a0,d0,pa) pointing:
+ * ---------------------------------------------------------------------------
+ *   psc_cell_to_pixel(cell_xid,cell_yid, xcell,ycell, &xota,&yota);
+ *   psc_pixel_to_fp(ota_xid, ota_yid, xota, yota, &xfp, &yfp);
+ *   psc_invoptics(xfp, yfp, dx, dy, dpa, pscale, d3, &x, &y);
+ *   psc_tplonglat(x*sec2rad, y*sec2rad, a0, d0, pa, density,  pi/2-alt, vertical, &a, &d);
+ */
+
+
+/**************/
+/* Prototypes */
+/**************/
+/* Enable application of chip offsets? */
+int psc_do_chipoff(int doit); 	/* Apply chip offsets? (0/1, default=0) */
+
+/* Convert a focal plane position to OTA otax,otay, Cell cellx,celly, Pixel */
+int psc_fp_to_pixel(double xfp_um, double yfp_um, 	/* FP position (um) */
+		int *ota_xid, int *ota_yid,		/* OTA ID (0:7) */
+		double *xota_pix, double *yota_pix);	/* OTA position (pix) */
+
+/* Convert a pixel position in OTA ota_xid,ota_yid to FP */
+int psc_pixel_to_fp(int ota_xid, int ota_yid,		/* OTA ID (0:7) */
+		double xota_pix, double yota_pix,	/* OTA position (pix) */
+		double *xfp_um, double *yfp_um);	/* FP position (um) */
+
+/* Convert an OTA pixel position to cell ID and cell coords */
+int psc_pixel_to_cell(double xota_pix, double yota_pix,	/* OTA position (pix) */
+		  int *cell_xid, int *cell_yid,		/* Cell ID (0:7) or -1 */
+		  double *xcell_pix, double *ycell_pix);/* Cell position (pix) */
+
+/* Convert a cell position and ID to OTA coords */
+int psc_cell_to_pixel(int cell_xid, int cell_yid,	/* Cell ID (0:7) */
+		  double xcell_pix, double ycell_pix,	/* Cell position (pix) */
+		  double *xota_pix, double *yota_pix);	/* OTA position (pix) */
+
+/* Convert tangent plane (x,y) at (a0,d0,pa) to RA,Dec (a,d) [radians] */
+/* y is rotated CCW by pa from N; NOTE: x is west when PA = 0 (pos parity) */
+/* Set density=0 to apply no correction for differential refraction, otherwise P/T in STP */
+int psc_tplonglat(double x_rad, double y_rad, double a0_rad, double d0_rad, double pa_rad,
+		  double density/*0.71 for HK*/, double zenith_rad/*pi/2-ALT*/, 
+		  double vertical_rad/*ROT*/, double *a_rad, double *d_rad);
+
+/* Project RA,Dec (a,d) to the tangent plane (x,y) at (a0,d0,pa) [radians] */
+/* y is rotated CCW by pa from N; NOTE: x is west when PA = 0 (pos parity) */
+/* Set density=0 to apply no correction for differential refraction, otherwise P/T in STP */
+int psc_tproject(double a_rad, double d_rad, double a0_rad, double d0_rad, double pa_rad,
+		 double density/*0.71 for HK*/, double zenith_rad/*pi/2-ALT*/, 
+		 double vertical_rad/*ROT*/, double *x_rad, double *y_rad);
+
+/* Evaluate an inverse optical model: microns -> arcsec notionally */
+/* Offset, scale with *small* distortion, rotate */
+int psc_invoptics(double xfp_um, double yfp_um, double dx_sec, double dy_sec, double dpa_rad, 
+		  double pscale/*38.86um/sec*/, double d3/*1.49e-10sec^-2*/, 
+		  double *x_sec, double *y_sec);
+
+/* Evaluate an optical model: arcsec -> microns notionally */
+/* Offset, scale with distortion, rotate */
+int psc_psoptics(double x_sec, double y_sec, double dx_sec, double dy_sec, double dpa_rad, 
+		 double pscale/*38.86um/sec*/, double d3/*1.49e-10sec^-2*/, 
+		 double *xfp_um, double *yfp_um);
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/Make.Common
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/Make.Common	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/Make.Common	(revision 23490)
@@ -0,0 +1,1 @@
+link ../Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/Makefile
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/Makefile	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/Makefile	(revision 23490)
@@ -0,0 +1,13 @@
+include ../Make.Common
+CCWARN+=$(WERROR)
+
+EXTRA_FFLAGS=-fno-automatic
+
+include ../Make.Common
+# Dependencies by Make.Common $Revision: 2.17 $
+
+$(OBJ)/psfmargin.o: psfmargin.c psf.h
+$(OBJ)/psfmoment.o: psfmoment.c psf.h
+$(OBJ)/psfdonut.o: psfdonut.c psf.h
+$(OBJ)/psf2dim.o: psf2dim.f psf.h
+$(OBJ)/psf.o: psf.c psf.h
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf.c	(revision 23490)
@@ -0,0 +1,228 @@
+/* psf.c: find and fit the brightest star in an image */
+/* 081009 v1.0 John Tonry */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <string.h>
+#include <math.h>
+#include "psf.h"
+
+#define SNMIN 5.0	/* Minimum S/N to proceed with PSF_MERGE */
+#define FWMIN 1.0	/* Minimum FWHM to proceed with PSF_MERGE */
+#define FWMAX 8.5	/* Maximum FWHM to proceed with PSF_MERGE */
+#define FWMRG 5.5	/* FWHM which is halfway through MARGIN/MOMENT merge */
+#define FWLAP 1.0	/* Transition width of MARGIN/MOMENT merge */
+#define FWCTE 2.0	/* Maximum yfw/xfw ratio to proceed with PSF_MERGE */
+#define EDGE  2.0	/* Minimum edge proximity to proceed with PSF_MERGE */
+
+int psf(int nx,			/* x size of image */
+	int ny,			/* y size of image */
+	unsigned short *data,	/* Data array */
+	PSF_ALGORITHM alg,	/* Choice of PSF algorithm */
+	PSF_IMPARAM *imparam,	/* Extra image parameters */
+	PSF_PARAM *psfout,	/* Results of fit */
+	PSF_EXTRA *psfextra)	/* Extra results from fit */
+{
+   int err=1;
+   int sx=0, sy=0, binx=1, biny=1, bordx=4, bordy=2, extra, fmax, NX=nx;
+   double xu, yu, fwhm, xfwhm, yfwhm, bkgnd, ftot, weight, snr;
+   int fmax2;
+   double xu2, yu2, fwhm2, xfwhm2, yfwhm2, bkgnd2, ftot2, weight2, snr2;
+   double frac, f;
+
+/* Load up parameters (with a few sanity checks!) */
+   if(imparam != NULL) {
+      sx = imparam->sx;
+      sy = imparam->sy;
+      if(imparam->binx > 0) binx = imparam->binx;
+      if(imparam->biny > 0) biny = imparam->biny;
+      if(imparam->nodata != 0) {
+	 fprintf(stderr, "*NODATA* normally is 0!\n");
+/* Ignore imparam->nodata != 0 (the default) for now! */
+      }
+      if(imparam->NX > 0) NX = imparam->NX;
+      if(imparam->bordx >= 0) bordx = imparam->bordx;
+      if(imparam->bordy >= 0) bordy = imparam->bordy;
+   }
+
+   switch(alg) {
+      case PSF_MARGIN:
+	 err = psfmargin(sx, sy, binx, biny, bordx, bordy,
+			 nx, ny, NX, data, &xu, &yu, &fmax, &fwhm,
+			 &xfwhm, &yfwhm, &bkgnd, &ftot, &weight, &snr);
+	 break;
+
+      case PSF_MOMENT:
+	 err = psfmoment(sx, sy, binx, biny, bordx, bordy,
+			 nx, ny, NX, data, &xu, &yu, &fmax, &fwhm,
+			 &xfwhm, &yfwhm, &bkgnd, &ftot, &weight, &snr, &extra);
+	 break;
+
+      case PSF_BIN:
+	 err = psfdonut(sx, sy, binx, biny, bordx, bordy,
+			 nx, ny, NX, data, &xu, &yu, &fmax, &fwhm,
+			 &xfwhm, &yfwhm, &bkgnd, &ftot, &weight, &snr, &extra);
+	 break;
+
+      case PSF_2DIM:
+	 err = psf2dim(nx, ny, data, imparam, psfout, psfextra);
+	 break;
+
+      case PSF_MERGE:
+	 err = psfmoment(sx, sy, binx, biny, bordx, bordy,
+			 nx, ny, NX, data, &xu, &yu, &fmax, &fwhm,
+			 &xfwhm, &yfwhm, &bkgnd, &ftot, &weight, &snr, &extra);
+/* Do we proceed with psfmargin? */
+	 if(!err && snr > SNMIN && 
+	    fwhm > FWMIN && fwhm < FWMAX && xfwhm < yfwhm*FWCTE &&
+	    xu > sx+EDGE && xu < sx+nx*binx-EDGE && 
+	    yu > sy+EDGE && yu < sy+ny*biny-EDGE) {
+	    err = psfmargin(sx, sy, binx, biny, bordx, bordy,
+			    nx, ny, NX, data, &xu2, &yu2, &fmax2, &fwhm2,
+			    &xfwhm2, &yfwhm2, &bkgnd2, &ftot2, &weight2, &snr2);
+/* Merge the results: frac = fraction of MOMENT to use */
+	    if(!err) {
+/* Control variable f is a linear combination of MAR/MOM */
+	       if(fwhm > FWMRG+FWLAP)      f = fwhm;
+	       else if(fwhm < FWMRG-FWLAP) f = fwhm2;
+	       else f = (fwhm-FWMRG+FWLAP)/(2*FWLAP)*(fwhm-fwhm2)+fwhm2;
+	       f = (f-FWMRG)/(2*FWLAP);
+	       if(f >= 1.0) 	     frac = 1.0;
+	       else if(f <= -1.0)    frac = 0.0;
+	       else 		     frac = 0.5*(sin(f*1.5708)+1);
+	       xu = (1-frac)*xu2 + frac*xu;
+	       yu = (1-frac)*yu2 + frac*yu;
+	       fwhm = (1-frac)*fwhm2 + frac*fwhm;
+	       xfwhm = (1-frac)*xfwhm2 + frac*xfwhm;
+	       yfwhm = (1-frac)*yfwhm2 + frac*yfwhm;
+	       ftot = (1-frac)*ftot2 + frac*ftot;
+	       snr = (1-frac)*snr2 + frac*snr;
+	       weight = (1-frac)*weight2 + frac*weight;
+	    }
+	 }
+
+	 break;
+
+      default:
+	 fprintf(stderr, "Unknown algorithm! %d\n", alg);
+	 return(-1);
+   }
+
+/* Load up results (with a few sanity checks!) */
+   if(psfout != NULL && alg != PSF_2DIM) {
+      psfout->ix = 0;
+      psfout->iy = 0;
+      psfout->x0 = xu;
+      psfout->y0 = yu;
+      psfout->peak = fmax;
+      psfout->fwhm = fwhm;
+      psfout->bkgnd = bkgnd;
+      psfout->flux = ftot;
+      psfout->sn = snr;
+      psfout->weight = err ? 0.0 : snr;
+   }
+
+/* Load up results (with a few sanity checks!) */
+   if(psfextra != NULL) {
+      if(alg == PSF_BIN || alg == PSF_MOMENT || alg == PSF_MARGIN) {
+	 psfextra->xfw = xfwhm;
+	 psfextra->yfw = yfwhm;
+      }
+      if(alg == PSF_BIN) psfextra->binfactor = extra;
+   }
+   return(err);
+}
+
+
+static float *jtpsfbuf=NULL;
+static int jtpsfnpix=0;
+
+int psf2dim(int nx, int ny, unsigned short *data,
+	PSF_IMPARAM *imparam,	/* Extra image parameters */
+	PSF_PARAM *psfout,	/* Results of fit */
+	PSF_EXTRA *psfextra)	/* Extra results from fit */
+{
+   int err;
+   int ix, iy, big;
+   int sx=0, sy=0, binx=1, biny=1;
+   double x0, y0, fwhm, xfwhm, yfwhm, sn, sky, ftot;
+   int i, j, NX=nx;
+   int aprad, skyrad, nwpar;
+   float wpar[16], flux[5], eadu=1.0;
+
+   if(imparam != NULL) {
+      sx = imparam->sx;
+      sy = imparam->sy;
+      if(imparam->binx > 0) binx = imparam->binx;
+      if(imparam->biny > 0) biny = imparam->biny;
+      if(imparam->NX > 0) NX = imparam->NX;
+   }
+
+/* First run psfmargin_guts to get defaults for jtpsf */
+   err = psfmargin_guts(1, &ix, &iy, &big, &x0, &y0, &fwhm, &xfwhm, &yfwhm,
+			&sn, &sky, &ftot, nx, ny, NX, data);
+   if(err) return(err);
+
+/* Make sure that we have some space allocated for the image */
+   if(jtpsfnpix < nx*ny) {
+      if(jtpsfbuf != NULL) free(jtpsfbuf);
+      jtpsfbuf = (float *)calloc(nx*ny, sizeof(float));
+      jtpsfnpix = nx*ny;
+   }
+
+/* Copy the array */
+   for(j=0; j<ny; j++) {
+      for(i=0; i<nx; i++) jtpsfbuf[i+j*nx] = data[i+j*NX];
+   }
+
+/* Parameters to run jtpsf_() */
+   nwpar = 7;
+   wpar[0] = ix;
+   wpar[1] = iy;
+   aprad = 5*fwhm;
+   skyrad = MIN(0.4*nx, 0.4*ny);
+   skyrad = MIN(skyrad, 10*fwhm);
+//   skyrad = MIN(skyrad, 60);
+//   aprad = 32;
+//   skyrad = 60;
+
+//   fprintf(stderr, "nx, ny, aprad, skyrad, nwpar, wpar[0], wpar[1] = %d %d %d %d %d %.2f %.2f\n",
+//	  nx, ny, aprad, skyrad, nwpar, wpar[0], wpar[1]);
+
+   jtpsf_(&nx, &ny, jtpsfbuf, &eadu, &aprad, &skyrad, &nwpar, wpar, flux, &err);
+/* Load up results (with a few sanity checks!) */
+   if(psfout != NULL) {
+      psfout->ix = ix;
+      psfout->iy = iy;
+      psfout->x0 = sx + wpar[0]*binx;
+      psfout->y0 = sy + wpar[1]*biny;
+      psfout->peak = big;
+      psfout->fwhm = sqrt(MAX(0.0, wpar[9]*wpar[10]*binx*biny));
+      psfout->bkgnd = flux[0];
+      psfout->flux = flux[2];
+      psfout->sn = flux[2] / MAX(0.0, flux[3]);
+      psfout->weight = err ? 0.0 : psfout->sn;
+   }
+
+/* Load up extras */
+   if(psfextra != NULL) {
+/* Note that these major/minor things are messed up if binx!=biny */
+      psfextra->majfw = wpar[9]*binx;
+      psfextra->minfw = wpar[10]*biny;
+      psfextra->thfw = wpar[11];
+      psfextra->wpeak = wpar[2];
+      psfextra->wbkgnd = wpar[3];
+      psfextra->dflux = flux[3];
+      psfextra->dbkgnd = flux[1];
+      psfextra->rmsbkgnd = flux[4];
+   }
+   return(err);
+}
+
+void f77msg_(char *line, int len)
+{
+   int i;
+   for(i=len-2; i>0 && line[i] == ' '; i--);
+   line[i+1] = '\0';
+   fprintf(stderr, "f77: %s\n", line);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf.h	(revision 23490)
@@ -0,0 +1,221 @@
+/*
+ * There are four different algorithms here with different strengths.
+ *
+ * PSF_MARGIN finds the brightest spot, estimates a crude FWHM,
+ *   sums up a marginal profile in x and y, fits a 1D curve to it
+ *   (default Gaussian or parabola), and then sums up the total
+ *   flux with varying sophistication in estimating sky
+ *
+ * PSF_MOMENT estimates sky from the median and then simply computes
+ *   moments of the brightest pixels to ascertain center and FWHM.  It
+ *   iterates once using all pixels within an aperture from the first pass.
+ *   PSF_MOMENT's FWHM is actually 2.35 * the RMS, which is neither the 
+ *   FWHM of a condensed PSF nor the outer diameter of a donut.  It is 
+ *   monotonic in PSF size, so is very appropriate for focussing, especially
+ *   grossly out of focus donuts.
+ *
+ * PSF_2DIM is a rather involved (fortran) routine to fit a full 2-D
+ *   profile at an initial position.  The center, FWHM, position angle,
+ *   and flux it returns are very refined.  The psf() wrapper limits
+ *   some of the underlying features (such as floating data and some
+ *   of the fit quality diagnostics).
+ *
+ * PSF_BIN tries to cope with grossly out of focus data by sucessively
+ *   binning by factors of 2, fitting the profile by PSF_MOMENT.  The
+ *   results are scored and a best-guess combination is returned.
+ *
+ *       Ratings: E-G-F-P for excellent - good - fair - poor
+ *
+ *                        PSF_MARGIN  PSF_MOMENT  PSF_2DIM  PSF_BIN
+ *  Speed                     E           E           F        G
+ *  Overall robustness        E           G           F        G
+ *  Centroid accuracy         E           G           E        G
+ *  FWHM accuracy             G           F*          E        F
+ *  FWHM of donut             P           E           P        G
+ *  Flux/bkgnd accuracy       F           F           E        F
+ *  Extra FWHM info           F           G           E        F
+ *
+ *  PSF_MERGE runs PSF_MOMENT and then if the FWHM is small enough
+ *  it also runs PSF_MARGIN.  It merges the x,y,FWHM from both routines
+ *  in a smooth way as a function of FWHM; preferring MARGIN for small
+ *  FWHM and MOMENT for large.  Obviously it usually costs the CPU time
+ *  for running both routines.
+ */
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define ABS(a) (((a) > 0) ? (a) : -(a))
+
+/* Enumeration of PSF algorithm choices */
+typedef enum {
+   PSF_MERGE,			/* Merge results from moment and margin */
+   PSF_MARGIN,			/* 1D fit to x,y marginalized profiles */
+   PSF_MOMENT,			/* Moment estimates of center, FWHM */
+   PSF_BIN,			/* Iterative binning, the PSF_MARGIN */
+   PSF_2DIM			/* Full 2D fit of profile */
+} PSF_ALGORITHM;
+
+/* Structure describing extra PSF image parameters */
+typedef struct {
+         int sx; 		/* x offset:  x_real = sx + binx * x_array */
+	 int sy;  		/* y offset:  y_real = sy + biny * y_array */
+	 int binx;  		/* x bin factor */
+	 int biny;   		/* y bin factor */
+	 int nodata;   		/* data value meaning *NO DATA* */
+	 int NX;		/* stride of image storage: addr = [x+NX*y] */
+	 int bordx;  		/* avoidance border width in x */
+	 int bordy;   		/* avoidance border width in y */
+} PSF_IMPARAM;
+
+/* Structure describing output from psf() */
+typedef struct {
+         int ix;		/* Highest pixel x posn in array */
+	 int iy;		/* Highest pixel y posn in array */
+	 double x0;		/* Fitted location of centroid, x */
+	 double y0;		/* Fitted location of centroid, y */
+	 double fwhm;		/* Star fwhm */
+	 double peak;		/* Highest pixel (minus background) */
+	 double bkgnd;		/* Background level */
+	 double flux;		/* Total flux in star */
+	 double sn;		/* Flux signal to noise */
+	 double weight;		/* Overall weight of star: */
+	    			/*    1-10 so-so, 10-30 OK, >30 fine */
+} PSF_PARAM;
+
+/* Structure describing possible extra output from psf() */
+typedef struct {
+	 int binfactor;		/* Best bin factor used for PSF_BIN */
+         double xfw;		/* Star fwhm in x dir */
+	 double yfw;		/* Star fwhm in y dir */
+/* Results available only from PSF_2DIM */
+         double majfw;		/* Major axis fwhm */
+	 double minfw;		/* Minor axis fwhm */
+	 double thfw;		/* Angle of major axis (CCW from x) [rad] */
+	 double wpeak;		/* Peak of Waussian fit */
+	 double wbkgnd;		/* Background of Waussian fit */
+	 double dflux;		/* Uncertainty in total flux estimate */
+	 double dbkgnd;		/* Uncertainty in total background estimate */
+	 double rmsbkgnd;	/* RMS in background */
+} PSF_EXTRA;
+
+int psf(
+   int nx,			/* x size of image */
+   int ny,			/* y size of image */
+   unsigned short *im,		/* Data array */
+   PSF_ALGORITHM alg,		/* Choice of PSF algorithm */
+   PSF_IMPARAM *imparam,	/* Extra image parameters */
+   PSF_PARAM *psf,		/* Results of fit */
+   PSF_EXTRA *extra);		/* Extra results from fit */
+
+/* Prototypes */
+
+/* Basic PSF calculation routine */
+int psfmargin_guts(int algo,	/* What algorithm to use? */
+    int *ix,		/* Highest pixel x posn*/
+    int *iy,		/* Highest pixel y posn */
+    int *big,		/* Highest pixel */
+    double *x0,		/* Fitted location of centroid, x */
+    double *y0,		/* Fitted location of centroid, y */
+    double *fwhm,	/* Star fwhm */
+    double *xfwhm,	/* Star fwhm in x dir */
+    double *yfwhm,	/* Star fwhm in y dir */
+    double *sn,		/* Star signal to noise */
+    double *sky,	/* Sky level */
+    double *flux,	/* Total flux in star */
+    int nx,		/* x size of image */
+    int ny,		/* y size of image */
+    int mx,		/* x size of image storage */
+    unsigned short *im);	/* Data array */
+
+/* Find and report Gaussian fit to position of brightest star */
+int psfmargin(int sx, 			/* x offset of pixel 0,0 */
+	     int sy,  			/* y offset of pixel 0,0 */
+	     int binx,  		/* x bin factor */
+	     int biny,   		/* y bin factor */
+	     int bordx,  		/* x border */
+	     int bordy,   		/* y border */
+	     int nx,   			/* x size of image */
+	     int ny,    		/* y size of image */
+	     int NX,   			/* x stride of image */
+	     unsigned short *data,	/* ushort image data: 0 = *NO_DATA* */
+	     double *xu,		/* Fitted x position */
+	     double *yu,		/* Fitted y position */
+	     int *fmax,			/* Highest pixel in best bin */
+	     double *fwhm,		/* FWHM of psf (binx,y corrected) */
+	     double *xfwhm,		/* FWHM in x dir (binx corrected) */
+	     double *yfwhm,		/* FWHM in y dir (biny corrected) */
+	     double *bkgnd,		/* Sky level */
+	     double *ftot,		/* Total flux */
+	      double *weight,		/* Composite quality of star: <1 bad,*/
+	     				/*    1-10 so-so, 10-30 OK, >30 fine */
+	     double *snr);		/* S/N of (big-sky)/noise */
+
+/* Find and report moments of brightest star */
+int psfmoment(int sx, 			/* x offset of pixel 0,0 */
+	     int sy,  			/* y offset of pixel 0,0 */
+	     int binx,  		/* x bin factor */
+	     int biny,   		/* y bin factor */
+	     int bordx,  		/* x border */
+	     int bordy,   		/* y border */
+	     int nx,   			/* x size of image */
+	     int ny,    		/* y size of image */
+	     int NX,   			/* x stride of image */
+	     unsigned short *data,	/* ushort image data: 0 = *NO_DATA* */
+	     double *xu,		/* Fitted x position */
+	     double *yu,		/* Fitted y position */
+	     int *fmax,			/* Highest pixel in best bin */
+	     double *fwhm,		/* FWHM of psf (binx,y corrected) */
+	     double *xfwhm,		/* FWHM in x dir (binx corrected) */
+	     double *yfwhm,		/* FWHM in y dir (biny corrected) */
+	     double *bkgnd,		/* Sky level */
+	     double *ftot,		/* Total flux */
+	     double *weight,		/* Composite quality of star: <1 bad,*/
+	     				/*    1-10 so-so, 10-30 OK, >30 fine */
+	     double *snr,		/* S/N of (big-sky)/noise */
+	     int *extra);		/* More return stuff? */
+
+/* Find and report on brightest star via hierarchical binning */
+int psfdonut(int sx, 			/* x offset of pixel 0,0 */
+	     int sy,  			/* y offset of pixel 0,0 */
+	     int binx,  		/* x anamorphic compression factor */
+	     int biny,   		/* y anamorphic compression factor */
+	     int bordx,  		/* x border */
+	     int bordy,   		/* y border */
+	     int nx,   			/* x size of image */
+	     int ny,    		/* y size of image */
+	     int NX,   			/* x stride of image */
+	     unsigned short *data,	/* ushort image data: 0 = *NO_DATA* */
+	     double *xu,		/* Fitted x position */
+	     double *yu,		/* Fitted y position */
+	     int *fmax,			/* Highest pixel in best bin */
+	     double *fwhm,		/* FWHM of psf (binx,y corrected) */
+	     double *xfwhm,		/* FWHM in x dir (binx corrected) */
+	     double *yfwhm,		/* FWHM in y dir (biny corrected) */
+	     double *bkgnd,		/* Sky level */
+	     double *ftot,		/* Total flux */
+	     double *weight,		/* Composite quality of star: <1 bad,*/
+	     				/*    1-10 so-so, 10-30 OK, >30 fine */
+	     double *snr,		/* S/N of (big-sky)/noise */
+	     int *binfactor);		/* Best bin factor used */
+
+/* Find and report about brightest star via 2-D fit */
+int psf2dim(
+   int nx,   			/* x size of image */
+   int ny,    			/* y size of image */
+   unsigned short *data,	/* ushort image data: 0 = *NO_DATA* */
+   PSF_IMPARAM *imparam,	/* Extra image parameters */
+   PSF_PARAM *psfout,		/* Results of fit */
+   PSF_EXTRA *psfextra);	/* Extra results from fit */
+
+/* The fortran guts, bleah! */
+int jtpsf_(
+   int *nx,		/* x size */
+   int *ny,		/* y size */
+   float *data,		/* image */
+   float *eadu,		/* e/ADU for noise calc (use 1.0) */
+   int *aprad,		/* Aperture radius */
+   int *skyrad,		/* Sky radius */
+   int *nwpar,		/* Number of fit params (use 7) */
+   float *wpar,		/* Fit results (16) */
+   float *flux,		/* Flux results (5) */
+   int *err);		/* Error */
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf2dim.f
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf2dim.f	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psf2dim.f	(revision 23490)
@@ -0,0 +1,1297 @@
+      subroutine jtpsf(nx, ny, a, eadu, iaprad, iskyrad, 
+     $     nwpar, wpar, flux, ierr)
+* Data array A(NX,NY)
+* Noise scale EADU (i.e. variance = EADU * Sky_level)
+* Radius for aperture flux = IAPRAD
+* Radius for sky estimates = ISKYRAD
+* Order of Waussian fit = NWPAR
+* Coords of star = WPAR(1),WPAR(2)
+* Results of Waussian fit = WPAR:
+*   WPAR( 1) = x0 of fit (TK convention!)
+*   WPAR( 2) = y0 of fit
+*   WPAR( 3) = peak of Waussian
+*   WPAR( 4) = sky of Waussian fit
+*   WPAR( 5) = sx2
+*   WPAR( 6) = sxy
+*   WPAR( 7) = sy2
+*   WPAR( 8) = beta4 
+*   WPAR( 9) = beta6
+*   WPAR(10) = major axis fwhm of Waussian fit
+*   WPAR(11) = minor axis fwhm of Waussian fit
+*   WPAR(12) = angle of major axis (CCW from x axis) [rad]
+*   WPAR(13) = chi^2/Ndof of fit
+*   WPAR(14) = rms residual within a radius of 2 sigma
+*   WPAR(15) = average absolute residual within a radius of 2 sigma
+*   WPAR(16) = max residual within a radius of 2 sigma
+* Results of sky and aperture flux fit = FLUX:
+*   FLUX(1) = sky
+*   FLUX(2) = sky uncertainty
+*   FLUX(3) = flux
+*   FLUX(4) = flux uncertainty
+*   FLUX(5) = rms in sky
+* Error code = IERR
+*                   0: no error, 
+*                  -1: off image, 
+*                   1: fit didn't converge,
+*                N*10: N zero'ed pixels within FWHM
+*
+* Function WAUSS(X,Y,WPAR,Z2) provided below for Waussian evaluation at (x,y)
+*
+* v. 1.11 030527 (JT) added zero pixel error flag
+*
+* v. 1.10 030330 (JT) fixed a few bugs, cleaned up the logic a bit, 
+*      added proper calculation of chi^2/N, FLUX(5) is a new argument, BEWARE
+*
+* Initial version 1.0 030301 John Tonry, adapted from JT Vista fondle()
+*
+      parameter (RESIDCUT=2.0)
+      real a(nx,ny)
+      real wpar(16), flux(5)
+      parameter (MAXRAD=64)
+      real pmed(MAXRAD+1), pave(MAXRAD+1), prms(MAXRAD+1)
+      integer npix(MAXRAD+1), ntot(MAXRAD+1)
+      real smooth(MAXRAD+1), profile(MAXRAD+1)
+* 768 = MAXPT (from pixmedave) * sqrt(2) * (1+fudge)
+      real buf(768*MAXRAD)
+      real ring(MAXRAD), area(MAXRAD), avering(MAXRAD), ering(MAXRAD)
+      real waux(10)
+      real*8 cov(9*9)
+      character*1000 DEBUG
+
+      IGAUSSRAD = 2
+      FWHMGAUSS = 2*sqrt(2*alog(2.))
+
+      profile(1) = 0
+
+      ix = nint(wpar(1))
+      iy = nint(wpar(2))
+
+* Abort this star if it's off the image
+      if(ix.lt.1 .or. ix.gt.nx .or. iy.lt.1 .or. iy.gt.ny) then
+         ierr = -1
+         return
+      end if
+
+****************************************************************
+C Find the highest pixel and get some crude information
+      call crudemax(ix,iy,nx,ny,a,mx,my,peak,crudefw,crudeback)
+
+C      WRITE(DEBUG,*) 'MX, MY, PEAK, CRUDEFW, CRUDEBACK',
+C    $     MX, MY, PEAK, CRUDEFW, CRUDEBACK
+C     CALL F77MSG(DEBUG)
+
+C     Get medians and averages at all radii...
+C      mxr = max(16, min(nint(15*crudefw),MAXRAD))
+      mxr = iskyrad
+      if(mxr .le. 0 .or. mxr .gt. MAXRAD) mxr = MAXRAD
+      call pixmedave(mx,my,nx,ny,a,mxr,npix,ntot,pave,pmed,prms,buf)
+
+C     Get an estimated values for SKY and FWHM
+      call estsky(fwhm,mxr+1,pmed,prms,esky,eskyerr,rms)
+
+C      WRITE(DEBUG,*) 'ESKY, ESKYERR, RMS',
+C     $     ESKY, ESKYERR, RMS
+C      CALL F77MSG(DEBUG)
+
+C     Get a fitted value for SKY and FWHM
+      do 5 i = 1,mxr+1
+         smooth(i) = ((3.*fwhm)/max(1,i-1))**3
+ 5    continue
+      m1 = (mxr+1)/2
+      nfit = mxr+1 - m1 + 1
+
+      call fitsky(nfit,pmed(m1),smooth(m1),ampl,amperr,sky,dsky)
+
+C      WRITE(DEBUG,*) 'AMPL, APERR, SKY, DSKY',
+C     $     AMPL, APERR, SKY, DSKY
+C      CALL F77MSG(DEBUG)
+
+C     Add up flux in annuli of width fwhm/2 or 5
+      iwidth = max(5,nint(fwhm/2))
+      nrad = mxr/iwidth
+      do 6 i = 1,nrad
+         area(i) = 0
+         ring(i) = 0
+         ering(i) = 0
+         avering(i) = 0
+ 6    continue
+      do 7 i = 1,mxr+1
+         idx = (i-1) / iwidth + 1
+*     Get the total flux = AVESUM
+         avesum = (pave(i)-sky) * ntot(i)
+         sum = avesum
+*     Make a more robust estimate of total flux from SUM = MEDIAN * N
+         if(ntot(i).gt.60) sum = (pmed(i)-sky) * ntot(i)
+         area(idx) = area(idx) + ntot(i)
+         ring(idx) = ring(idx) + sum
+         avering(idx) = avering(idx) + avesum
+         ering(idx) = ering(idx) + sum + (sky-esky)*ntot(i)
+ 7    continue
+
+* Add up the total flux
+      call pixsum(mx,my,nx,ny,a,iaprad,ntotal,ave,apflux,peak)
+      apflux = apflux - ntotal*sky
+      dflux = apflux/eadu + (ntotal*dsky)**2 + rms*rms*ntotal
+      if(dflux .ge. 0) then
+         dflux = sqrt(dflux)
+      else
+         dflux = -sqrt(-dflux)
+      end if
+      flux(1) = sky
+      flux(2) = dsky
+      flux(3) = apflux
+      flux(4) = dflux
+      flux(5) = rms
+
+C      WRITE(DEBUG,*) 'SKY, DSKY, APFLUX, DFLUX, RMS', 
+C     $     DSKY, APFLUX, DFLUX, RMS, SKY
+C      CALL F77MSG(DEBUG)
+
+
+************************************************************************
+* Now do a Waussian fit to the data using all we know for initial values
+* How many FWHM do we fit?
+      WRAD = 2.5
+* How many FWHM do we use for evaluating chi/N?
+      WCHI = 2.0
+* Guess at extrasky to meet noise seen by estsky
+      if(rms.ne.0 .and. esky.ne.0) then
+         extrasky = eadu*rms*rms - esky
+      else
+* Disable weighting if something's really wrong with the "sky" level and rms
+         extrasky = -1e10
+      end if
+C WRITE(6,*) EADU, RMS, ESKY, EXTRASKY
+
+* What do we want for a center guess?
+      if(nwpar.ge.7) then
+* Use the positive peak...
+         n = max(3,min(31,max(IGAUSSRAD,nint(WRAD*fwhm))))
+         iwxs = max(0,mx-n)
+         iwys = max(0,my-n)
+      else
+         call domajmin(wpar)
+         n = max(3,min(31,max(IGAUSSRAD,
+     $        nint(WRAD*sqrt(abs(wpar(10)*wpar(11)))))))
+         iwxs = max(0, nint(wpar(1))-n)
+         iwys = max(0, nint(wpar(2))-n)
+      end if
+
+
+* WPAR: X0, Y0, P, SKY, SX2, SXY, SY2, B4, B6, FWX, FWY, PHI
+      if(nwpar.ge.7) then
+         wpar(1) = mx
+         wpar(2) = my
+      end if
+* Waussian fit (WPAR(8) = BETA4 = 1, WPAR(9) = BETA6 = 0.5)
+      wpar(8) = 1.0
+      wpar(9) = 0.5
+* WAUX: NXPATCH, NYPATCH, NX, XOFF, YOFF, EADU, EXTRASKY, IGNORE_VALUE, INIT
+      waux(1) = min(n,nx-1-mx) + n + 1
+      waux(2) = min(n,ny-1-my) + n + 1
+      waux(3) = nx
+      waux(4) = iwxs
+      waux(5) = iwys
+      waux(6) = eadu
+      waux(7) = extrasky
+* Bad data value, by convention 0.0 for JT
+      waux(8) = 0.0
+      waux(9) = 1
+* Don't dare leap to all 9 params at once
+      if(nwpar.gt.7) then
+         niter = 20
+         call waussfit(a(iwxs+1,iwys+1),7,wpar,waux,niter,cov,chisq)
+      end if
+      if(nwpar.gt.2) then
+         niter = 20
+         call waussfit(a(iwxs+1,iwys+1),nwpar,wpar,waux,niter,cov,chisq)
+      else
+         call wausstwo(a(iwxs+1,iwys+1),wpar,waux,chisq)
+      end if
+      wpar(13) = chisq
+
+      if(niter.eq.20 .or. chisq.eq.0) then
+C         ierr = 1
+         ierr = niter
+         return
+      end if
+
+      if(chisq.lt.0) then
+         ierr = nint(chisq)
+         return
+      end if
+
+      ierr = 0
+* Improved estimate of chi^2/N
+      if(rms .gt. 0 .and. wpar(10).gt.0 .and. wpar(11).gt.0) then
+         fw = sqrt(wpar(10)*wpar(11))
+         i0 = max(1,  nint(wpar(1)-WCHI*fw+0.5))
+         i1 = min(nx, nint(wpar(1)+WCHI*fw+0.5))
+         j0 = max(1,  nint(wpar(2)-WCHI*fw+0.5))
+         j1 = min(ny, nint(wpar(2)+WCHI*fw+0.5))
+         chisq = 0
+         npt = 0
+         resid = 0
+         nresid = 0
+         biggie = 0
+         absave = 0
+         do 20 j = j0, j1
+            y = j - 0.5
+            do 21 i = i0, i1
+               if(a(i,j) .eq. waux(8)) then
+                  if((i-wpar(1))*(i-wpar(1))+(j-wpar(2))*(j-wpar(2)) 
+     $                 .le. fw*fw) ierr = ierr + 10
+                  goto 21
+               end if
+               x = i - 0.5
+               diff = a(i,j) - (wauss(x, y, wpar, z2) + wpar(4))
+               chisq = chisq + (diff/rms)**2
+               npt = npt + 1
+               if(z2 .lt. RESIDCUT) then
+                  resid = resid + diff**2
+                  nresid = nresid + 1
+                  if(abs(diff) .gt. abs(biggie)) biggie = diff
+                  absave = absave + abs(diff)
+               end if
+ 21         continue
+ 20      continue
+* Replace wpar(13) with this better chi/N
+         wpar(13) = chisq / max(1,npt-nwpar)
+         wpar(14) = sqrt(resid / max(1,nresid))
+         wpar(15) = absave / max(1,nresid)
+         wpar(16) = biggie
+      end if
+
+      return
+      end
+
+* Compute the value of a Waussian fit at (x,y)  [leaving out the sky]
+      function wauss(x, y, wpar, z2)
+      real wpar(9)
+      x0   = wpar(1)
+      y0   = wpar(2)
+      peak = wpar(3)
+      sky  = wpar(4)
+      sx2  = wpar(5)
+      sxy  = wpar(6)
+      sy2  = wpar(7)
+      b4   = wpar(8)
+      b6   = wpar(9)
+      z2 = sx2*(x-x0)*(x-x0)+sxy*(x-x0)*(y-y0)+sy2*(y-y0)*(y-y0)
+      wauss = peak/(1 + z2*(1 + z2*(0.5*b4 + z2*b6/6)))
+      return
+      end
+
+      subroutine crudemax(ix,iy,nx,ny,a,mx,my,peak,fwhm,back)
+C Find from a rough position (IX,IY), the highest point PEAK at (MX,MY),
+C the rough FWHM, and a rough BACKground of the image in the wings of the star.
+      parameter (pi=3.14159265)
+      real a(nx,ny)
+
+C Find the local maximum
+      maxstep = 30
+      mx = ix
+      my = iy
+      peak = a(mx+1,my+1)
+      do 10 nstep = 1,maxstep
+         peak2 = -1e10
+         do 11 j = my-1,my+1
+            if(j.ge.ny.or.j.lt.0) goto 11
+            do 12 i = mx-1,mx+1
+               if(i.ge.nx.or.i.lt.0) goto 12
+               if(a(i+1,j+1).gt.peak2) then
+                  peak2 = a(i+1,j+1)
+                  im = i
+                  jm = j
+               end if
+ 12         continue
+ 11      continue
+         if(peak2.gt.peak) then
+            mx = im
+            my = jm
+            peak = peak2
+         else
+            goto 15
+         end if
+ 10   continue
+ 15   continue
+
+C Run down the profile in the +/-x and y directions to where it turns up
+      back = 0
+      n = 0
+      do 22 k = 0,3
+         idx = nint(cos(k*pi/2))
+         idy = nint(sin(k*pi/2))
+         do 20 l = 1,maxstep
+            i = mx + idx*l
+            j = my + idy*l
+            if(i.ge.nx.or.i.lt.0.or.j.ge.ny.or.j.lt.0) goto 21
+            if(a(i+1,j+1).gt.a(i+1-idx,j+1-idy)) then
+               n = n + 1
+               back = back + a(i+1,j+1)
+               goto 21
+            end if
+ 20      continue
+ 21      continue
+ 22   continue
+      back = back / max(n,1)
+
+C Find the FWHM using this value for BACK
+      fwhm = 0
+      n = 0
+      do 32 k = 0,3
+         idx = nint(cos(k*pi/2))
+         idy = nint(sin(k*pi/2))
+         do 30 l = 1,maxstep
+            i = mx + idx*l
+            j = my + idy*l
+            if(i.ge.nx.or.i.lt.0.or.j.ge.ny.or.j.lt.0) goto 31
+            if(a(i+1,j+1).lt.peak-(peak-back)/2) then
+               n = n + 1
+               fwhm = fwhm + l
+               goto 31
+            end if
+ 30      continue
+ 31      continue
+ 32   continue
+      fwhm = 2 * fwhm / max(n,1) - 1
+
+      return
+      end
+
+      subroutine pixmedave(mx,my,nx,ny,a,ir,np,ntot,ave,med,rms,buf)
+C Collect average and median of all annuli out to a radius IR
+      parameter (maxpt=512)
+      real a(nx,ny)
+      real ave(1), med(1), rms(1), buf(maxpt,1)
+      integer np(1), ntot(1)
+
+      do 10 i = 1,ir+1
+         np(i) = 0
+         ntot(i) = 0
+         ave(i) = 0
+ 10   continue
+
+C Accumulate pixels from the bottom to top on the right and
+C then top to bottom on the left to get the pixels in azimuthal order
+      do 20 jp = 0,2*(2*ir+1)
+         if(jp.lt.(2*ir+1)) then
+            j = jp - ir
+            ix1 = 0
+            ix2 = ir
+         else
+            j = 3*ir + 1 - jp
+            ix1 = -ir
+            ix2 = -1
+         end if
+         do 21 i = ix1,ix2 
+            r = sqrt(float(i*i+j*j))
+            k = nint(r) + 1
+            if(k.gt.ir+1) goto 21
+            ntot(k) = ntot(k) + 1
+            if(j+my.ge.ny.or.j+my.lt.0) goto 21
+            if(i+mx.ge.nx.or.i+mx.lt.0) goto 21
+            pixel = a(i+mx+1,j+my+1)
+            np(k) = np(k) + 1
+            if(np(k).gt.maxpt) then
+C               write(6,*) 'FONDLE (pixmedave): np exceeded maxpt!'
+*               call f77msg('FONDLE (pixmedave): np exceeded maxpt!')
+               np(k) = maxpt
+            end if
+            ave(k) = ave(k) + pixel
+            buf(np(k),k) = pixel
+ 21      continue
+ 20   continue
+
+C Now compute medians.  If there are sufficient points, correct the median
+C for skewness by assessing the rms, and counting all points around
+C points of greater than 3-sigma which themselves exceed 1-sigma, and
+C throwing out those points from the sorted data.
+
+      do 30 k = 1,ir+1
+         ave(k) = ave(k) / max(np(k),1)
+         do 31 i = 1,np(k)
+            buf(i,1) = buf(i,k)
+ 31      continue
+
+         call qsort4(np(k),buf(1,1))
+         amed = 0.5*(buf((np(k)+1)/2,1)+buf((np(k)+2)/2,1))
+         nsig = max(1,nint(0.1587*np(k)))
+         arms = amed - buf(nsig,1)
+
+C Don't do any funny stuff with radii less than 10 pixels... (N ~ 60)
+         if(np(k).le.60) then
+            med(k) = amed
+            rms(k) = arms
+         else
+            trigger = amed + 3*arms
+C            reset = amed + arms
+            reset = amed
+
+
+C Find a spot which is lower than one-sigma
+            n1 = 1
+C 32         if(buf(n1,k).gt.reset .and. n1.lt.np(k))  then
+ 32         if(buf(n1,k).gt.reset)  then
+               n1 = n1 + 1
+               goto 32
+            end if
+
+
+C Now advance around the circle, counting all pixels higher than RESET
+C which are adjacent to a pixel higher than TRIGGER
+            nuke = 0
+C            n2 = n1 + 1
+* But fed to a mod we want to start at n1+1 - 1
+            n2 = n1
+ 33         if(n2-n1.lt.np(k)) then
+               if(buf(mod(n2,np(k))+1,k).gt.trigger) then
+
+C Back up to find out where the pixels higher than RESET began
+                  i = n2 - 1
+ 34               if(buf(mod(i,np(k))+1,k).gt.reset) then
+                     nuke = nuke + 1
+                     i = i - 1
+                     goto 34
+                  end if
+
+C Advance to find out where the pixels higher than RESET end
+ 35               if(buf(mod(n2,np(k))+1,k).gt.reset) then
+                     nuke = nuke + 1
+                     n2 = n2 + 1
+                     goto 35
+                  end if
+
+               else
+                  n2 = n2 + 1
+               end if
+
+               goto 33
+            end if
+
+C Now recompute the median and rms with NUKE pixels removed off the top
+            n = np(k) - nuke
+            med(k) = 0.5*(buf((n+1)/2,1)+buf((n+2)/2,1))
+            rms(k) = med(k) - buf(nint(0.1587*n),1)
+C            WRITE(6,*) K, MED(K), RMS(K)
+
+         end if
+
+ 30   continue
+
+      return
+      end
+
+      subroutine pixsum(mx,my,nx,ny,a,ir,np,ave,total,peak)
+C Collect average and sum of the flux out to a radius IR
+      real a(nx,ny)
+
+      total = 0
+      np = 0
+      peak = 0
+      do 20 j = -ir,ir
+         iy = j + my + 1
+         if(iy.lt.1.or.iy.gt.ny) goto 20
+         do 21 i = -ir,ir
+            ix = i + mx + 1
+            if(ix.lt.1.or.ix.gt.nx) goto 21
+            ir2 = i*i + j*j
+            if(ir2.gt.ir*ir) goto 21
+            np = np + 1
+            total = total + a(ix,iy)
+            peak = amax1(peak,a(ix,iy))
+ 21      continue
+ 20   continue
+      ave = total / max(1,np)
+
+      return
+      end
+
+      subroutine estsky(fwhm,np,profile,prms,sky,err,rms)
+C Get a decent estimate of SKY and RMS from the PROFILE and PRMS, 
+C and then get a decent estimate of the FWHM
+      real profile(np), prms(np), buf(21)
+
+C First get SKY from a median of the last points in PROFILE
+      n = min(np/2,21)
+      do 10 i = 1,n
+         buf(i) = profile(np-i+1)
+ 10   continue
+      call qsort4(n,buf)
+      sky = 0.5*(buf((n+1)/2)+buf((n+2)/2))
+      err = (sky - buf(max(1,(n+1)/6))) / sqrt(float(n))
+
+C Now get FWHM from the estimated SKY and the central intensity
+      minus = +1
+      if(profile(1).lt.sky) minus = -1
+      half = 0.5*(profile(1) + sky)
+      do 11 i = 1,np
+         if(minus*profile(i).le.minus*half) then
+            ir2 = i
+            goto 12
+         end if
+         if(minus*profile(i).gt.minus*half) ir1 = i
+ 11   continue
+ 12   continue
+
+      budge = 0
+      if(profile(ir1).ne.profile(ir2)) 
+     $     budge = (ir2-ir1)*(profile(ir1)-half) /
+     $     (profile(ir1)-profile(ir2))
+      fwhm = 2*(ir1 - 1 + budge)
+
+C Finally get the RMS as the median of the last several rms points
+      do 20 i = 1,n
+         buf(i) = prms(np-i+1)
+ 20   continue
+      call qsort4(n,buf)
+      rms = 0.5*(buf((n+1)/2)+buf((n+2)/2))
+
+      return
+      end
+
+      subroutine fitsky(n,profile,smooth,ampl,amperr,sky,err)
+C Fit the profile as AMPL * SMOOTH + SKY, and return the error as ERR
+      real profile(n), smooth(n)
+      real*8 v(2), am(3), sum, sum2, det
+
+      v(1) = 0
+      v(2) = 0
+      am(1) = 0
+      am(2) = 0
+      am(3) = 0
+
+C Accumulate sums
+      do 20 j = 1,n
+         v(1) = v(1) + profile(j)
+         v(2) = v(2) + profile(j)*smooth(j)
+         am(1) = am(1) + 1
+         am(2) = am(2) + smooth(j)*smooth(j)
+         am(3) = am(3) + smooth(j)
+ 20   continue
+
+      det = am(1)*am(2) - am(3)*am(3)
+      if(det.eq.0) then
+         sky = 0
+         ampl = 0
+         amperr = 0
+         err = 0
+         return
+      end if
+      tmp = am(2)
+      am(2) = am(1) / det
+      am(1) = tmp / det
+      am(3) = -am(3) / det
+
+      sky = am(1)*v(1) + am(3)*v(2)
+      ampl = am(3)*v(1) + am(2)*v(2)
+
+      if(ampl.lt.0) ampl = 0
+
+      sum = 0
+      sum2 = 0
+      do 30 j = 1,n
+         sum = sum + profile(j)-(sky + ampl*smooth(j))
+         sum2 = sum2 + (profile(j)-(sky + ampl*smooth(j)))**2
+ 30   continue
+
+      sum = sum / n
+      rms = dsqrt(dabs(sum2/n-sum*sum))
+
+      if(ampl.eq.0) sky = sky + sum
+
+      err = sqrt(am(1)) * rms
+      amperr = sqrt(am(2)) * rms
+      cov = am(3) / sqrt(am(1)*am(2))
+
+      return
+      end
+
+
+      SUBROUTINE QSORT4(N,X)
+* Sorting program that uses a quicksort algorithm
+* c. 1978 JT
+      parameter (maxstack=256)
+      REAL X(N)
+      REAL KEY, KL, KR, KM, TEMP
+      INTEGER L, R, M, LSTACK(maxstack+1), RSTACK(maxstack+1), SP
+      INTEGER NSTOP
+      LOGICAL MGTL, LGTR, RGTM
+      DATA NSTOP /15/
+
+      IF(N.LE.NSTOP) GOTO 100
+      SP = 0
+      SP = SP + 1
+      LSTACK(SP) = 1
+      RSTACK(SP) = N
+
+* Sort a subrecord off the stack
+* Set KEY = median of X(L), X(M), X(R)
+1     L = LSTACK(SP)
+      R = RSTACK(SP)
+      SP = SP - 1
+      M = (L + R) / 2
+      KL = X(L)
+      KM = X(M)
+      KR = X(R)
+      MGTL = KM .GT. KL
+      RGTM = KR .GT. KM
+      LGTR = KL .GT. KR
+      IF(MGTL .EQV. RGTM) THEN
+          IF(MGTL .EQV. LGTR) THEN
+              KEY = KR
+          ELSE
+              KEY = KL
+          ENDIF
+      ELSE
+          KEY = KM
+      ENDIF
+
+      I = L
+      J = R
+
+* Find a big record on the left
+10    IF(X(I).GE.KEY) GOTO 11
+      I = I + 1
+      GOTO 10
+11    CONTINUE
+* Find a small record on the right
+20    IF(X(J).LE.KEY) GOTO 21
+      J = J - 1
+      GOTO 20
+21    CONTINUE
+      IF(I.GE.J) GOTO 2
+* Exchange records
+      TEMP = X(I)
+      X(I) = X(J)
+      X(J) = TEMP
+      I = I + 1
+      J = J - 1
+      GOTO 10
+
+* Subfile is partitioned into two halves, left .le. right
+* Push the two halves on the stack
+2     IF(J-L+1 .GT. NSTOP) THEN
+          SP = SP + 1
+          LSTACK(SP) = L
+          RSTACK(SP) = J
+      ENDIF
+      IF(R-J .GT. NSTOP) THEN
+          SP = SP + 1
+          LSTACK(SP) = J+1
+          RSTACK(SP) = R
+      ENDIF
+      IF(SP.GT.MAXSTACK) THEN
+C         WRITE(6,*) 'QSORT4: Fatal error from stack overflow'
+C         WRITE(6,*) 'Fall back on sort by insertion'
+*         call f77msg('QSORT4: Fatal error from stack overflow')
+*         call f77msg('Fall back on sort by insertion')
+         GOTO 100
+      END IF
+
+* Anything left to process?
+      IF(SP.GT.0) GOTO 1
+
+* Sorting routine that sorts the N elements of single precision
+* array X by straight insertion between previously sorted numbers
+100   DO 110 J = N-1,1,-1
+      K = J
+      DO 120 I = J+1,N
+      IF(X(J).LE.X(I)) GOTO 121
+120   K = I
+121   CONTINUE
+      IF(K.EQ.J) GOTO 110
+      TEMP = X(J)
+      DO 130 I = J+1,K
+130   X(I-1) = X(I)
+      X(K) = TEMP
+110   CONTINUE
+      RETURN
+      END
+
+      subroutine waussfit(data,npar,par,aux,niter,cov,chisq)
+*     Program to fit a source with a Wingy Gaussian
+*
+*     Input:	data	Pixel array
+*     NPAR      How many parameters to fit: 4, 7, 9
+*               Note: NPAR=9 wants parameters to be first fitted with NPAR=7!
+*     NITER     Max number of iterations requested
+*     PAR(1)    Initial guess for x0 (includes XOFF)
+*     PAR(2)    Initial guess for y0 (includes YOFF)
+*     PAR(8)    BETA4: r^4 coeff of Waussian (< 0 => Fit Gaussian instead)
+*     PAR(9)    BETA6: r^6 coeff of Waussian
+*
+*     AUX(1)    NX	Number of columns in DATA
+*     AUX(2)    NY	Number of rows in DATA
+*     AUX(3)    NXDIM   Column dimension of DATA
+*     AUX(4)    XOFF	X offset of subarray in entire array
+*     AUX(5)    YOFF	Y offset of subarray in entire array
+*     AUX(6)    EPERADU	E/ADU for calculating sigma
+*     AUX(7)    EXTRA	Added value so that variance = E/ADU*(DATA+EXTRA)
+*     AUX(8)    IGNORE	Pixel value to ignore in fitting
+*     AUX(9)    INIT	Initialize params?
+*                       0, start with what's in PAR already
+*                       1, initialize all but x0,y0 = PAR(1,2)
+*                       2, also find peak to start x0,y0 = PAR(1,2)
+*                       
+*      Output:	PAR(1:12)   (8,9 left alone if NPAR <= 7)
+*  1   XC	x center of Gaussian; first pixel is 0 < x < 1
+*  2   YC	y center of Gaussian; first pixel is 0 < y < 1
+*  3   PEAK	Central intensity of Gaussian
+*  4   SKY	Constant added to Gaussian
+*  5   SX2	Squared Gaussian width in the x direction
+*  6   SXY	Cross term of Gaussian width
+*  7   SY2	Squared Gaussian width in the y direction
+*  8   BETA4	r^4 coefficient in Waussian (< 0 => Fit Gaussian instead)
+*  9   BETA6	r^6 coefficient in Waussian
+* 10   FWMAJ	Gaussian FWHM width - major axis
+* 11   FWMIN	Gaussian FWHM width - minor axis
+* 12   PHI      Angle of major axis
+*      NITER 	Number of iterations carried out
+*
+      parameter (pi=3.14159265, gausshalf=2.3548)
+      real*8 cov(npar,npar)
+      real par(12), aux(9)
+      real data(1)
+      character*1024 blabline
+      external weval
+
+      IBLAB = 0
+
+      nx = nint(aux(1))
+      ny = nint(aux(2))
+      nxdim = nint(aux(3))
+      init = nint(aux(9))
+
+* Set up initial values for parameters...
+      if(init.gt.1) then
+* Find the peak for INIT .GE. 2
+         imax = 1
+         jmax = 1
+         do 10 j = 1,ny
+            do 11 i = 1,nx
+               if(data(i+(j-1)*nxdim).gt.data(imax+(jmax-1)*nxdim)) then
+                  imax = i
+                  jmax = j
+               end if
+ 11         continue
+ 10      continue
+         par(1) = imax - 0.5 + aux(4)
+         par(2) = jmax - 0.5 + aux(5)
+      end if
+
+* Internal to waussfit the position is relative to the subarray...
+      par(1) = par(1) - aux(4)
+      par(2) = par(2) - aux(5)
+
+* Continue initialization for INIT .GE. 1
+      if(init.gt.0) then
+         imax = nint(par(1) + 0.5)
+         jmax = nint(par(2) + 0.5)
+
+         par(4) = amin1(data(1), data(1+(ny-1)*nxdim),
+     $        data(nx), data(nx+(ny-1)*nxdim))
+         par(3) = data(imax+(jmax-1)*nxdim) - par(4)
+         half = 0.5*(par(3)-par(4)) + par(4)
+         if(npar.gt.4) then
+            do 12 i = imax+1,nx
+               if(data(i+(jmax-1)*nxdim).lt.half) then
+                  width = i - imax
+                  goto 13
+               end if
+ 12         continue
+            width = nx / 2
+ 13         continue
+            par(5) = 1 / (width/1.2)**2
+            par(6) = 0.001
+            par(7) = par(5)
+         end if
+         if(npar.gt.7) then
+            par(8) = 1
+            par(9) = 1
+         end if
+      end if
+
+      acc = 0.001
+
+      alamb = -1
+      if(iblab.gt.0) then
+C         WRITE(6,*) 'ATTEMPTING FITMRQ', aux(6), aux(7)
+*         WRITE(blabline,*) 'ATTEMPTING FITMRQ', aux(6), aux(7)
+*         call f77msg(blabline)
+      end if
+
+      nvar = 9
+
+      if(iblab.gt.0) then
+C         WRITE(6,1511) -1,-20,0.0,(PAR(J),J=1,7)
+*         WRITE(blabline,1511) -1,-20,0.0,(PAR(J),J=1,7)
+*         call f77msg(blabline)
+      end if
+      chiold = fitmrq(nx*ny,aux,v,data,nvar,npar,par,cov,alamb,weval)
+      if(chiold .lt. 0) return
+      if(iblab.gt.0) then
+C         WRITE(6,1511) 0,nint(alog10(alamb)),CHIOLD,(PAR(J),J=1,7)
+*         WRITE(blabline,1511) 0, nint(alog10(alamb)), CHIOLD,
+*     $        (PAR(J),J=1,7)
+* 1511    FORMAT(2I4,1pe12.4,0p2F9.3,2F9.1,5F9.4)
+*         call f77msg(blabline)
+      end if
+      miter = 0
+      do 20 i = 1,niter
+         chisq = fitmrq(nx*ny,aux,v,data,nvar,npar,par,cov,alamb,weval)
+         if(chisq .lt. 0) return
+         miter = miter + 1
+         if(iblab.gt.0) then
+C            WRITE(6,1511) MITER,nint(alog10(alamb)),CHISQ,(PAR(J),J=1,7)
+*            WRITE(blabline,1511) MITER, nint(alog10(alamb)), CHISQ,
+*     $           (PAR(J),J=1,7)
+*            call f77msg(blabline)
+         end if
+         if(abs(chisq-chiold) .lt. acc*chiold .and.
+     $        alamb.le.0.001) goto 21
+         chiold = amin1(chiold,chisq)
+ 20   continue
+ 21   alamb = 0
+      chisq = fitmrq(nx*ny,aux,v,data,nvar,npar,par,cov,alamb,weval)
+      if(chisq .lt. 0) return
+      if(iblab.gt.0) then
+C         WRITE(6,1511) miter,-20,CHISQ,(PAR(J),J=1,7)
+*         WRITE(blabline,1511) miter,-20,CHISQ,(PAR(J),J=1,7)
+*         call f77msg(blabline)
+      end if
+      niter = miter
+
+* Patch up and fill in the parameters
+      par(1) = par(1) + aux(4)
+      par(2) = par(2) + aux(5)
+
+* Calculate sigma's and position angles from sx2, sxy, sy2
+      call domajmin(par)
+
+C      WRITE(6,*) PAR
+
+      return
+      end
+
+      subroutine wausstwo(data,par,aux,chisq)
+C Fit a Waussian using only PEAK and SKY; he's linear, Jim.
+      real par(12), aux(9)
+      real data(1)
+      real*8 v(2), am(3), det, dat, fit
+
+      nx = nint(aux(1))
+      ny = nint(aux(2))
+      nxdim = nint(aux(3))
+* Internal to waussfit the position is relative to the subarray...
+      x0 = par(1) - aux(4)
+      y0 = par(2) - aux(5)
+      sx2 = par(5)
+      sxy = par(6)
+      sy2 = par(7)
+      b4 = par(8) / 2
+      b6 = par(9) / 6
+
+      v(1) = 0
+      v(2) = 0
+      am(1) = 0
+      am(2) = 0
+      am(3) = 0
+
+      baddata = aux(8)
+
+C Accumulate sums
+      do 10 j = 0,ny-1
+         do 11 i = 0,nx-1
+            x = i + 0.5
+            y = j + 0.5
+            if(data(i+1+j*nxdim) .eq. baddata) goto 11
+            z2 = sx2*(x-x0)*(x-x0)+sxy*(x-x0)*(y-y0)+sy2*(y-y0)*(y-y0)
+            fit = 1 / (1+z2*(1+z2*(b4+z2*b6)))
+            dat = data(i+1+j*nxdim)
+            v(1) = v(1) + dat
+            v(2) = v(2) + dat*fit
+            am(1) = am(1) + 1
+            am(2) = am(2) + fit*fit
+            am(3) = am(3) + fit
+ 11      continue
+ 10   continue
+
+      det = am(1)*am(2) - am(3)*am(3)
+      if(det.eq.0) then
+         par(3) = 0
+         par(4) = 0
+         chisq = -2
+         return
+      end if
+      tmp = am(2)
+      am(2) = am(1) / det
+      am(1) = tmp / det
+      am(3) = -am(3) / det
+
+      par(3) = am(3)*v(1) + am(2)*v(2)
+      par(4) = am(1)*v(1) + am(3)*v(2)
+
+      call domajmin(par)
+      chisq = 1
+      return
+      end
+
+
+      subroutine domajmin(par)
+* Calculate sigma's and position angles from sx2, sxy, sy2
+      parameter (pi=3.14159265, gausshalf=2.3548)
+      real par(12), aux(9)
+
+      if(par(5).eq.par(7)) then
+         par(12) = pi/4
+         par(10) = par(5) + par(7)
+         par(11) = par(10)
+      else
+         par(12) = 0.5*atan(par(6)/(par(5)-par(7)))
+         par(10) = par(5) + par(7) + (par(5)-par(7))/cos(2*par(12))
+         par(11) = par(5) + par(7) - (par(5)-par(7))/cos(2*par(12))
+         if(par(10).gt.par(11)) then
+            tmp = par(10)
+            par(10) = par(11)
+            par(11) = tmp
+            par(12) = par(12) - pi/2
+         end if
+      end if
+      if(par(12).lt.0) par(12) = par(12) + pi
+
+* Take careful square roots
+      if(par(10).gt.0) then
+         par(10) = gausshalf / sqrt(par(10))
+      else if(par(10).eq.0) then
+         par(10) = 0
+      else
+         par(10) = -gausshalf / sqrt(-par(10))
+      end if
+
+      if(par(11).gt.0) then
+         par(11) = gausshalf / sqrt(par(11))
+      else if(par(11).eq.0) then
+         par(11) = 0
+      else
+         par(11) = -gausshalf / sqrt(-par(11))
+      end if
+      return
+      end
+
+      function weval(k,aux,v,data,ydat,wgt, npar,par,yfit,dyda)
+* Evaluate things for fitmrq
+      parameter (half=0.5, sixth=0.1666666666)
+      real data(1)
+      real dyda(npar), par(9), aux(8)
+      character*1024 blabline
+
+C      WRITE(6,*) 'ENTERED WEVAL', 
+C      WRITE(6,*) PAR
+C      WRITE(6,*) AUX
+      x0 = par(1)
+      y0 = par(2)
+      peak = par(3)
+      sky = par(4)
+      sx2 = par(5)
+      sxy = par(6)
+      sy2 = par(7)
+      b4 = par(8)
+      b6 = par(9)
+
+      nx = nint(aux(1))
+      ny = nint(aux(2))
+      nxdim = nint(aux(3))
+      eperadu = aux(6)
+      extrasky = aux(7)
+      baddata = aux(8)
+
+*      WRITE(blabline, *) 'Entering weval', (par(i),i=1,9),(aux(i),i=1,8)
+*      call f77msg(blabline)
+
+      if(nx.eq.0) then
+C         write(6,*) 'WEVAL: zero dimension???'
+         call f77msg('WEVAL: zero dimension???')
+         weval = -1
+         return
+      end if
+      i = mod(k-1,nx)
+      j = (k-1)/nx
+
+C      WEVAL = DATA(NXDIM*J + I + 1)
+C      WRITE(6,*) 'WEVAL COORDS', I, J
+
+      x = i + 0.5
+      y = j + 0.5
+
+      z2 = sx2*(x-x0)*(x-x0) + sxy*(x-x0)*(y-y0) + sy2*(y-y0)*(y-y0)
+      fn = 0
+      if(z2.lt.85) then
+         if(b4.lt.0 .and. npar.le.7) then
+            fn = exp(-z2)
+            dfdz2 = 1/fn
+         else
+            fn = 1/(1 + z2*(1 + z2*(half*b4 + z2*sixth*b6)))
+            dfdz2 = 1 + z2*(b4 + z2*half*b6)
+         end if
+      end if
+
+      yfit = sky + peak*fn
+
+*      WRITE(blabline, *) 'weval:', sx2,sxy,sy2, z2, fn, sky, peak, yfit
+*      call f77msg(blabline)
+
+      dyda(1) = peak*fn*fn*dfdz2*(2*sx2*(x-x0) + sxy*(y-y0))
+      dyda(2) = peak*fn*fn*dfdz2*(sxy*(x-x0) + 2*sy2*(y-y0))
+      dyda(3) = fn
+      dyda(4) = 1
+      if(npar.gt.4) then
+         dyda(5) = -peak*fn*fn*dfdz2*(x-x0)*(x-x0)
+         dyda(6) = -peak*fn*fn*dfdz2*(x-x0)*(y-y0)
+         dyda(7) = -peak*fn*fn*dfdz2*(y-y0)*(y-y0)
+      end if
+      if(npar.gt.7) then
+         dyda(8) = -peak*fn*fn*half*z2*z2
+         dyda(9) = -peak*fn*fn*sixth*z2*z2*z2
+      end if
+
+      weval = 1
+      ydat = data(nxdim*j + i + 1)
+      if(ydat.eq.baddata) then
+         ydat = yfit
+         weval = 0
+      end if
+
+      if(extrasky.gt.-9e9) then
+         wgt = eperadu/(ydat+extrasky)
+         if(wgt.lt.0) wgt = 1
+      else
+         wgt = 1
+      end if
+
+*      WRITE(blabline, *) 'Leaving weval', weval, yfit, wgt, 
+*     $     (par(i),i=1,9), (dyda(i),i=1,9)
+*      call f77msg(blabline)
+
+      return
+      end
+
+      function fitmrq(ndata,u,v,y,nvar,npar,par,cov,alamb,func)
+* Levenberg-Marquardt method, fitting PAR(NPAR) to data Y(NDATA)
+* In order to provide as much flexibility as possible, the arrays
+* (U,V are convenience arrays) are all passed through FUNC:
+*
+*     FUNC(I,U,V,Y,YDAT,WGT, NPAR,PAR,YFIT,DYDA) 
+*
+*        should return the 0/1 for data value used as well as filling in
+*        YDAT, YFIT, DYDA(NPAR), and WGT.
+*
+* Note that NVAR parameters are maintained, but only NPAR are varied.
+*
+* ALAMB < 0 => initialize; otherwise usual LM parameter; 
+* COV = scratch space (returns slightly messed up covariance matrix)
+* A final call with ALAMB = 0 will fill COV with proper covariance matrix
+* FITMRQ returns Chi^2/NDOF
+*
+      parameter (maxpar=20)
+      real*8 cov(npar,npar)
+      real par(nvar), ptry(maxpar)
+      real*8 alpha(maxpar*maxpar), beta(maxpar), dpar(maxpar)
+      external func
+      character*1024 blabline
+
+* Initialize with first value of Chi^2
+      if(alamb .lt. 0) then
+         alamb = 0.001
+         chisq = chimrq(ndata,u,v,y,npar,par,alpha,beta,func)
+         ochisq = chisq
+         fitmrq = chisq
+         do 13 j=1,nvar
+            ptry(j) = par(j)
+ 13      continue
+         return
+      end if
+*      write(blabline, *) 'frmq1: ', chisq, (par(i),i=1,npar)
+*      call f77msg(blabline)
+
+* Build L-M matrix
+      do 15 j=1,npar
+        do 14 k=1,npar
+          cov(j,k) = alpha(k+(j-1)*npar)
+14      continue
+        cov(j,j) = alpha(j+(j-1)*npar)*(1.+alamb)
+        dpar(j) = beta(j)
+15    continue
+
+* Solve for new DPAR
+      ierr = jordangauss(cov,npar,npar,dpar,1,1)
+      if(ierr .ne. 0) then
+         fitmrq = -1
+         return
+      end if
+
+* ALAMB = 0 implies COV is now covariance matrix, so just return
+      if(alamb .eq. 0.0) then
+        fitmrq = chisq
+        return
+      end if
+
+* Evaluate new Chi^2
+      do 16 j=1,npar
+         ptry(j) = par(j) + dpar(j)
+16    continue
+
+C      WRITE(6,*) 'ABOUT TO TRY NEW DATA'
+C      WRITE(6,*) PTRY
+C      WRITE(6,*) DPAR
+
+      chisq = chimrq(ndata,u,v,y,npar,ptry,cov,dpar,func)
+
+*      write(blabline, *) 'frmq2: ', chisq, (ptry(i),i=1,npar)
+*      call f77msg(blabline)
+
+* Test for improvement and adjust L-M parameter
+      if(chisq.lt.ochisq)then
+         alamb = 0.1*alamb
+         ochisq = chisq
+         do 18 j=1,npar
+            do 17 k=1,npar
+               alpha(k+(j-1)*npar) = cov(j,k)
+ 17         continue
+            beta(j) = dpar(j)
+            par(j) = ptry(j)
+ 18      continue
+      else
+         alamb = 10.*alamb
+         chisq = ochisq
+      end if
+      fitmrq = chisq
+      return
+      end
+
+      function chimrq(ndata,u,v,y,npar,par,alpha,beta,func)
+      parameter (maxpar=20)
+      real*8 alpha(npar,npar), beta(npar)
+      real dyda(maxpar)
+      external func
+      character*1024 blabline
+
+* Zero out second derivative matrix and y vector
+      do 12 j=1,npar
+         do 11 k=1,j
+            alpha(j,k) = 0.0
+ 11      continue
+         beta(j) = 0.0
+ 12   continue
+      chimrq=0.0
+
+* Add up sums 
+      dof = -npar
+      do 15 i = 1,ndata
+         used = func(i,u,v,y,ydata,wgt,npar,par,ymod,dyda)
+*         write(blabline, *) i, ymod, used
+*         call f77msg(blabline)
+         dof = dof + used
+         dy = ydata - ymod
+         do 14 j=1,npar
+            wt = dyda(j) * wgt
+            do 13 k=1,j
+               alpha(j,k) = alpha(j,k) + wt*dyda(k)
+ 13         continue
+            beta(j) = beta(j) + dy*wt
+ 14      continue
+         chimrq = chimrq + dy*dy*wgt
+ 15   continue
+* Convert to Chi^2/N
+      chimrq = chimrq / amax1(1.0, dof)
+
+* Symmetrize
+      do 17 j=2,npar
+         do 16 k=1,j-1
+            alpha(k,j) = alpha(j,k)
+ 16      continue
+ 17   continue
+
+      return
+      end
+
+      function jordangauss(a,n,np,b,m,mp)
+      implicit real*8 (a-h,o-z)
+      parameter (nmax=50)
+      real*8 a(np,np), b(np,mp)
+      integer ipiv(nmax), indxr(nmax), indxc(nmax)
+      do 11 j=1,n
+         ipiv(j)=0
+ 11   continue
+      do 22 i=1,n
+         big=0.
+         do 13 j=1,n
+            if(ipiv(j).ne.1)then
+               do 12 k=1,n
+                  if (ipiv(k).eq.0) then
+                     if (abs(a(j,k)).ge.big)then
+                        big=abs(a(j,k))
+                        irow=j
+                        icol=k
+                     endif
+                  else if (ipiv(k).gt.1) then
+C                     write(6,*) 'singular matrix'
+                     jordangauss = -1
+                     return
+                  endif
+ 12            continue
+            endif
+ 13      continue
+         ipiv(icol)=ipiv(icol)+1
+         if (irow.ne.icol) then
+            do 14 l=1,n
+               dum=a(irow,l)
+               a(irow,l)=a(icol,l)
+               a(icol,l)=dum
+ 14         continue
+            do 15 l=1,m
+               dum=b(irow,l)
+               b(irow,l)=b(icol,l)
+               b(icol,l)=dum
+ 15         continue
+         endif
+         indxr(i)=irow
+         indxc(i)=icol
+         if (a(icol,icol).eq.0.) then
+C            write(6,*) 'singular matrix.'
+            jordangauss = -1
+            return
+         end if
+         pivinv=1./a(icol,icol)
+         a(icol,icol)=1.
+         do 16 l=1,n
+            a(icol,l)=a(icol,l)*pivinv
+ 16      continue
+         do 17 l=1,m
+            b(icol,l)=b(icol,l)*pivinv
+ 17      continue
+         do 21 ll=1,n
+            if(ll.ne.icol)then
+               dum=a(ll,icol)
+               a(ll,icol)=0.
+               do 18 l=1,n
+                  a(ll,l)=a(ll,l)-a(icol,l)*dum
+ 18            continue
+               do 19 l=1,m
+                  b(ll,l)=b(ll,l)-b(icol,l)*dum
+ 19            continue
+            endif
+ 21      continue
+ 22   continue
+      do 24 l=n,1,-1
+         if(indxr(l).ne.indxc(l))then
+            do 23 k=1,n
+               dum=a(k,indxr(l))
+               a(k,indxr(l))=a(k,indxc(l))
+               a(k,indxc(l))=dum
+ 23         continue
+         endif
+ 24   continue
+      jordangauss = 0
+      return
+      end
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfdonut.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfdonut.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfdonut.c	(revision 23490)
@@ -0,0 +1,184 @@
+/* psfdonut.c: find and fit the brightest star in an image; donuts OK */
+
+/* Note: this is not as fast as psf() nor as accurate as jtpsf() for
+ * flux, width, and position, but it is tolerant of donuts and should
+ * provide a pretty good width and center.
+ */
+/* 080815 v1.0 John Tonry */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <math.h>
+#include "psf.h"
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+static unsigned short int *binim=NULL;	/* Storaged for binned images */
+static int binsize=0;			/* How many pixels? */
+#define LOGMAXBIN 4	/* Bin down to 2^LOGMAXBIN, 32=2^5 is a bit much... */
+// #define XBORD 2		/* Disregard this border on the x sides */
+// #define YBORD 1		/* Disregard this border on the y sides */
+
+// #define DONUT_TEST		/* Test output for donut routine? */
+
+/* Find and report on the brightest star; will work with donuts... */
+int psfdonut(int ZFsx, 			/* x offset of pixel 0,0 */
+	     int ZFsy,  		/* y offset of pixel 0,0 */
+	     int ZFbinx,  		/* x anamorphic compression factor */
+	     int ZFbiny,   		/* y anamorphic compression factor */
+/* Note: "anamorphic compression" means that the data received have been
+ * binned down by that factor.  We *do* correct the positions xu,yu
+ * for this factor, and *do* correct the widths for it.  The reasoning, such
+ * as it is, returns unbinned positions, correct for offsets, and
+ * the widths need to be corrected here because roundness is such an important
+ * factor in deciding whether we've got a good fit or not.  Ugh.
+ */
+	     int bordx,  		/* x border */
+	     int bordy,   		/* y border */
+	     int ZFnx,   		/* x size of image */
+	     int ZFny,    		/* y size of image */
+	     int ZFNX,   		/* x stride of image */
+	     unsigned short *ZFdata,	/* ushort image data: 0 = *NO_DATA* */
+	     double *xu,		/* Fitted x position */
+	     double *yu,		/* Fitted y position */
+	     int *fmax,			/* Highest pixel in best bin */
+	     double *fwhm,		/* FWHM of psf (binx,y corrected) */
+	     double *xfwhm,		/* FWHM in x dir (binx corrected) */
+	     double *yfwhm,		/* FWHM in y dir (biny corrected) */
+	     double *bkgnd,		/* Sky level */
+	     double *ftot,		/* Total flux */
+	     double *weight,		/* Composite quality of star: <1 bad,*/
+	     				/*    1-10 so-so, 10-30 OK, >30 fine */
+	     double *snr,		/* S/N of (big-sky)/noise */
+	     int *binfactor)		/* Best bin factor used */
+{
+   int i, j, k;
+   int xmax, ymax, big, bbig=0;
+   double x0, y0, pfwhm, xpfwhm, ypfwhm, bsize;
+   double flux[LOGMAXBIN+1], sky[LOGMAXBIN+1];
+   double xp[LOGMAXBIN+1], yp[LOGMAXBIN+1], sn[LOGMAXBIN+1];
+   double xfwest[LOGMAXBIN+1], yfwest[LOGMAXBIN+1], fwest[LOGMAXBIN+1];
+   double wgt[LOGMAXBIN+1], bestwgt;
+   int bin, bestbin=0, err[LOGMAXBIN+1];
+   unsigned short int *imptr[LOGMAXBIN+1];
+   int sx[LOGMAXBIN+1], sy[LOGMAXBIN+1];
+   int nx[LOGMAXBIN+1], ny[LOGMAXBIN+1], NX[LOGMAXBIN+1];
+#ifdef DONUT_TEST
+   int fd;
+   char fname[2880];
+#endif
+
+#ifdef DONUT_TEST
+   fprintf(stderr, "nx=%d ny=%d sx=%d sy=%d binx=%d biny=%d data=%d\n", 
+	  ZFnx, ZFny, ZFsx, ZFsy, ZFbinx, ZFbiny, ZFdata[0]);
+#endif
+
+/* Allocate some space for the binned down images */
+   if(binsize < (ZFnx*ZFny+2)/3) {
+      if(binim == NULL) free(binim);
+      binim = (unsigned short int *)calloc((ZFnx*ZFny+2)/3, sizeof(short int));
+      binsize = (ZFnx*ZFny+2) / 3;
+   }
+
+/* Bin down the image and update the arrays */
+   imptr[0] = (unsigned short int *)((ushort *)ZFdata+bordx+bordy*ZFNX);
+   sx[0] = ZFsx + bordx;
+   sy[0] = ZFsy + bordy;
+   nx[0] = ZFnx - 2*bordx;
+   ny[0] = ZFny - 2*bordy;
+   NX[0] = ZFNX;
+   for(bin=1; bin<=LOGMAXBIN; bin++) {
+      if(bin == 1) imptr[bin] = binim;
+      else	   imptr[bin] = imptr[bin-1] + NX[bin-1]*ny[bin-1];
+      sx[bin] = sx[bin-1];
+      sy[bin] = sy[bin-1];
+      nx[bin] = nx[bin-1]/2;
+      ny[bin] = ny[bin-1]/2;
+      NX[bin] = nx[bin];
+      for(j=0; j<ny[bin]; j++) {
+	 for(i=0; i<nx[bin]; i++) {
+	    k  = imptr[bin-1][2*i+2*j*NX[bin-1]];
+	    k += imptr[bin-1][2*i+1+2*j*NX[bin-1]];
+	    k += imptr[bin-1][2*i+(2*j+1)*NX[bin-1]];
+	    k += imptr[bin-1][2*i+1+(2*j+1)*NX[bin-1]];
+	    imptr[bin][i+j*NX[bin]] = (k+2)/4;
+	 }
+      }
+   }
+
+/* Analyze each one */
+   bestwgt = 0.0;
+   for(bin=0; bin<=LOGMAXBIN; bin++) {
+      bsize = pow(2.0, (double)bin);
+
+#ifdef DONUT_TEST
+      sprintf(fname, "/tmp/bin%d.fits", bin);
+      fd = creat(fname, 0664);
+      sprintf(fname, "SIMPLE  =                    T                                                  BITPIX  =                   16                                                  NAXIS   =                    2                                                  NAXIS1  =                 %4d                                                  NAXIS2  =                 %4d                                                  END                                                                             ", nx[bin], ny[bin]);
+      for(i=strlen(fname); i<2880; i++) fname[i] = ' ';
+      write(fd, fname, 2880);
+      swab(imptr[bin], imptr[bin], 2*NX[bin]*ny[bin]);
+      for(j=0; j<ny[bin]; j++) write(fd, imptr[bin]+j*NX[bin], 2*nx[bin]);
+      swab(imptr[bin], imptr[bin], 2*NX[bin]*ny[bin]);
+      close(fd);
+#endif
+      err[bin] = psfmargin_guts(1, &xmax,&ymax, &big, &x0,&y0,    
+	  &pfwhm, &xpfwhm, &ypfwhm, &sky[bin], &flux[bin], &sn[bin], 
+	  nx[bin], ny[bin], NX[bin], imptr[bin]);
+      xp[bin] = x0 * bsize * ZFbinx + sx[bin];
+      yp[bin] = y0 * bsize * ZFbiny + sy[bin];
+      xfwest[bin] = sqrt(MAX(0.01,xpfwhm*xpfwhm - 0.46)) * ZFbinx * bsize;
+      yfwest[bin] = sqrt(MAX(0.01,ypfwhm*ypfwhm - 0.46)) * ZFbiny * bsize;
+      fwest[bin] = sqrt(xfwest[bin]*yfwest[bin]);
+      flux[bin] *= bsize*bsize;
+/* Calculate weights for final guesses */
+/* Error is bad, virtually fatal */
+      wgt[bin] = err[bin] == 0 ? 1.0 : 0.01;
+/* Non-round PSF is very bad */
+      wgt[bin] *= pow(xfwest[bin]/yfwest[bin], 
+		     xfwest[bin] < yfwest[bin] ? +2.0 : -2.0);
+/* Ridiculously small or large PSF is bad, ~2.4 is best */
+      wgt[bin] *= exp(-0.5*pow((log(MAX(0.1,xpfwhm))-log(2.4))/log(2.0), 2.0));
+      wgt[bin] *= exp(-0.5*pow((log(MAX(0.1,ypfwhm))-log(2.4))/log(2.0), 2.0));
+/* High S/N is good */
+      wgt[bin] *= MAX(0.0, sn[bin]);
+/* High flux is good (crudely normalize assuming ~1e/ADU) */
+      wgt[bin] *= MAX(0.0, flux[bin]/1e5);
+
+      if(wgt[bin] > bestwgt) {
+	 bestwgt = wgt[bin];
+	 bestbin = bin;
+	 bbig = big;
+      }
+
+#ifdef DONUT_TEST
+      printf("B%d %2d: %5.1f %5.1f %6.1f %5.1f %4.1f %4.1f %4.1f %4.1f %5d %5.0f %7.0f %6.1f %6.1f\n", 
+	     bin, err[bin], x0, y0, xp[bin], yp[bin], pfwhm, xpfwhm, ypfwhm, fwest[bin],
+	     big, sky[bin], flux[bin], sn[bin], wgt[bin]);
+      drawcirc(xp[bin]/ZFbinx, yp[bin]/ZFbiny, 0.5*fwest[bin], sn[bin]>5?0:1);
+#endif
+   }
+
+#ifdef DONUT_TEST
+   printf("\n");
+   drawcirc((xp[bestbin]-sx[bestbin])/ZFbinx+sx[bestbin], 
+	    (yp[bestbin]-sy[bestbin])/ZFbiny+sy[bestbin], 
+	    0.5*fwest[bestbin]-1, sn[bestbin]>5?0:1);
+#endif
+
+/* Return values */
+   *xu = xp[bestbin];
+   *yu = yp[bestbin];
+   *fmax = bbig;
+   *fwhm = fwest[bestbin];
+   *xfwhm = xfwest[bestbin];
+   *yfwhm = yfwest[bestbin];
+   *bkgnd = sky[bestbin];
+   *ftot = flux[bestbin];
+   *weight = wgt[bestbin];
+   *snr = sn[bestbin];
+   *binfactor = bestbin;
+
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfmargin.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfmargin.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfmargin.c	(revision 23490)
@@ -0,0 +1,1037 @@
+/* Basic subroutines for computing psf profiles */
+/*   algo:   1's digit: 0 for parabola fit, 1 for Gaussian fit to posn
+ *          10's digit: 0 for quick, dumb flux sum, 1-3 for wing fit and
+ *                      full flux sum, 1,2,3 = wauss, power law, exponential
+ *         100's digit: 0 for normal operation, 1 to ignore right hand double
+ *			(for calcite operations)
+ *     1000000's digit: 1 for debug output
+ */
+/* 080703 JT - slim down border to BORDER instead of n/8 */
+/* 031026 JT - mess around with better flux estimates ((algo/10)%10 = 1) */
+/* 020420 JT - I'm generated NaNs somehow so test for them and remove them! */
+/* 020322 JT - avoid edge pixels like the plague */
+/* 020128 JT - change args to permit non-filled arrays */
+/* 6/20/96 (JT) to return S/N and only one fwhm */
+/* JT 6/25/93 */
+/* Routine to find the biggest star in an image and return its
+ * pixel center (ix,iy), fit center (x0,y0), width (fwhm) and S/N (sn)
+ * The background level is returned as sky
+ * Assumes unsigned short integers
+ **************************CONVENTION******************************
+ * The first element of the array is taken to be pixel 0.0 to 1.0
+ ******************************************************************
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "psf.h"
+// #define DEBUG	/* Engage debug code? */
+
+#define MAXLINE 4096	/* Maximum storage for various purposes */
+#define MAXDIM	1024	/* Maximum nx or ny */
+#define EDGE  1		/* Number of edge pixels to ignore */
+static int BORDER=2;	/* Closest a high pixel can be to edge */
+
+#define DBLFRAC  0.6	/* Fraction of highest pixel to be a calcite double */
+
+#define NGAUSS  5       /* Number of parameters for a Gaussian fit */
+#define NWING   3       /* Number of parameters for a psf tail fit */
+
+#define NODATA  0	/* Special value for *NO DATA* */
+
+#define XERROR   (0x0001)
+#define YERROR   (0x0002)
+#define GXERROR  (0x0004)
+#define GYERROR  (0x0008)
+#define FWERROR  (0x0010)
+#define WINGERROR  (0x0020)
+#define DATAERROR  (0x0040)
+
+static double strip[MAXLINE];
+static double median(int n, double *key, int *idx);
+int psfmargin_guts(int algo, int *ix, int *iy, int *big, double *x0, double *y0, 
+	       double *fwhm, double *xfwhm, double *yfwhm, 
+	       double *sky, double *flux, double *sn, 
+	       int nx, int ny, int mx, unsigned short *im);
+static int parabola(int nx, double *d, 
+		    double *center, double *height, double *width);
+static int gaussian(int *niter, int n, double *d, double *par);
+static int dgauss(int n, double *d, 
+		  double *par, double *chi, double *deriv, double *curv);
+static int gchi(int n, double *d, double *par, double *chi);
+static int wingfit(int *niter, int func, int n, 
+		   double *d, double *r, double *par);
+static int wingchi(int func, int n, double *r, double *d, 
+	double dmin, double *par, double *chi);
+static int dwingfit(int func, int n, double *r, double *d, double dmin, 
+		    double *par, double *chi, double *deriv, double *curv);
+static int linsolve(int n, double *y, double *a, double *x);
+#ifdef FANCY_STUFF
+static int exponential_bias(double *bias, double *ampl, double *efold, 
+			    int nx,int ny,int mx, unsigned short *im);
+static int video_bias_sub(double bias, double ampl, double efold, 
+			  int nx,int ny,int mx, unsigned short *im);
+#endif
+
+/* Normal, Gaussian fit version */
+int psfmargin(int sx, 			/* x offset of pixel 0,0 */
+	     int sy,  			/* y offset of pixel 0,0 */
+	     int binx,  		/* x bin factor */
+	     int biny,   		/* y bin factor */
+	     int bordx,  		/* x border */
+	     int bordy,   		/* y border */
+	     int nx,   			/* x size of image */
+	     int ny,    		/* y size of image */
+	     int NX,   			/* x stride of image */
+	     unsigned short *data,	/* ushort image data: 0 = *NO_DATA* */
+	     double *xu,		/* Fitted x position */
+	     double *yu,		/* Fitted y position */
+	     int *fmax,			/* Highest pixel in best bin */
+	     double *fwhm,		/* FWHM of psf (binx,y corrected) */
+	     double *xfwhm,		/* FWHM in x dir (binx corrected) */
+	     double *yfwhm,		/* FWHM in y dir (biny corrected) */
+	     double *bkgnd,		/* Sky level */
+	     double *ftot,		/* Total flux */
+	     double *weight,		/* Composite quality of star: <1 bad,*/
+	     				/*    1-10 so-so, 10-30 OK, >30 fine */
+	     double *snr)		/* S/N of (big-sky)/noise */
+{
+   int ix, iy, big, err;
+   BORDER = MAX(bordx, bordy);
+   err = psfmargin_guts(1, &ix,&iy, &big, 
+       xu,yu, fwhm, xfwhm, yfwhm, bkgnd, ftot, snr, nx,ny,NX, data);
+
+   *xu = sx + *xu * binx;
+   *yu = sy + *yu * biny;
+   *fwhm *= sqrt((double)(binx*biny));
+   *xfwhm *= binx;
+   *yfwhm *= biny;
+   *fmax = big;
+   *weight = *snr;
+   return(err);
+}
+
+/* Basic PSF calculation routine */
+int
+psfmargin_guts(algo, ix,iy, big, x0,y0, fwhm, xfwhm, yfwhm, 
+	       sky, flux, sn, nx,ny,mx, im)
+   int algo;			/* What algorithm to use? */
+   int *ix, *iy, *big;		/* Highest pixel */
+   double *x0, *y0;		/* Fitted location of centroid */
+   double *fwhm, *xfwhm, *yfwhm;/* Star fwhm */
+   double *sn;			/* Star signal to noise */
+   double *sky, *flux;		/* Sky level, total flux in star */
+   int nx, ny, mx;		/* Size of image; x size of image storage */
+   unsigned short *im;		/* Data array */
+{
+   int i, j, nsky, iwx, iwy, dblbig=0.0, dblx=0, dbly=0, err=0;
+   int n, k[4];
+   double mean[4], rms[4], var, medsky;
+   double xhgt, yhgt;
+   double gxpar[NGAUSS], gypar[NGAUSS], wingpar[NWING];
+   int niter;
+
+/* Locate the highest pixel in the central 3/4 of the image */
+/* No, avoid pixels closer to the edge than BORDER */
+   *big = -1;
+//   for(j=ny/8; j<(7*ny)/8; j++) {
+//      for(i=nx/8; i<(7*nx)/8; i++) {
+   for(j=BORDER; j<ny-BORDER; j++) {
+      for(i=BORDER; i<nx-BORDER; i++) {
+	 if(im[i+mx*j] != NODATA && (int)im[i+mx*j] > (*big)) {
+	    (*big) = im[i+mx*j];
+	    *ix = i;
+	    *iy = j;
+	 }
+      }
+   }
+/* No pixels found???  (data all *NODATA*) */
+   if(*big == -1) return(DATAERROR);
+
+/* Look in the corners for a sky value */
+   for(i=0; i<4; i++) {
+      mean[i] = rms[i] = 0.0;
+      k[i] = 0;
+   }
+   i = MIN(nx, ny);		/* i = smaller dimension */
+   j = MIN(6, i/8);		/* nsky = dim/8, but 3 <= nsky <= 6 */
+   nsky = MAX(3, j);		/* nsky = dim/8, but 3 <= nsky <= 6 */
+   if(nsky > i/2) nsky = i/3;
+   if(nsky < 1) nsky = 1;
+   for(j=EDGE; j<nsky+EDGE; j++) {
+      for(i=EDGE; i<nsky+EDGE; i++) {
+	 if(im[i+j*mx] != NODATA) {
+	    mean[0] += im[i+j*mx];
+	    rms[0]  += im[i+j*mx] * im[i+j*mx];
+	    k[0] += 1;
+	 }
+	 if(im[nx-1-i+j*mx] != NODATA) {
+	    mean[1] += im[nx-1-i+j*mx];
+	    rms[1]  += im[nx-1-i+j*mx] * im[nx-1-i+j*mx];
+	    k[1] += 1;
+	 }
+	 if(im[nx-1-i+(ny-1-j)*mx] != NODATA) {
+	    mean[2] += im[nx-1-i+(ny-1-j)*mx];
+	    rms[2]  += im[nx-1-i+(ny-1-j)*mx] * im[nx-1-i+(ny-1-j)*mx];
+	    k[2] += 1;
+	 }
+	 if(im[i+(ny-1-j)*mx] != NODATA) {
+	    mean[3] += im[i+(ny-1-j)*mx];
+	    rms[3]  += im[i+(ny-1-j)*mx] * im[i+(ny-1-j)*mx];
+	    k[3] += 1;
+	 }
+      }
+   }
+/* Normalize mean and rms, initialize index array */
+   for(i=0; i<4; i++) {
+      if(k[i] > 0) mean[i] /= k[i];
+      if(k[i] > 0) rms[i] /= k[i];
+      k[i] = i;
+   }
+/* Sort them via index array k[] */
+   if(mean[k[2]] > mean[k[3]]) {i=k[2]; k[2]=k[3]; k[3]=i;}
+   if(mean[k[1]] > mean[k[2]]) {i=k[1]; k[1]=k[2]; k[2]=i;}
+   if(mean[k[2]] > mean[k[3]]) {i=k[2]; k[2]=k[3]; k[3]=i;}
+   if(mean[k[0]] > mean[k[1]]) {i=k[0]; k[0]=k[1]; k[1]=i;}
+   if(mean[k[1]] > mean[k[2]]) {i=k[1]; k[1]=k[2]; k[2]=i;}
+   if(mean[k[2]] > mean[k[3]]) {i=k[2]; k[2]=k[3]; k[3]=i;}
+
+/* Pick the second greatest as the sky level */
+   i = 1;
+   if(mean[k[i]] == NODATA) i = 2;
+   if(mean[k[i]] == NODATA) i = 3;
+   *sky = mean[k[i]];
+   if(nsky > 1) var = rms[k[i]] - (*sky)*(*sky);
+   else var = (mean[k[MIN(i+1,3)]]-mean[k[i]])*(mean[k[MIN(i+1,3)]]-mean[k[i]]);
+   if(var < 1.0) var = 1.0;
+
+/* Check to see whether there is another, nearly equivalent star to the left */
+   if((algo/100)%10 == 1) {
+//      for(j=ny/8; j<(7*ny)/8; j++) {
+//	 for(i=nx/8; i<(7*nx)/8; i++) {
+      for(j=BORDER; j<ny-BORDER; j++) {
+	 for(i=BORDER; i<nx-BORDER; i++) {
+/* Skip first star we found */
+	    if(ABS(i-*ix) < 2 && ABS(j-*iy) < 2) continue;
+/* Is it nearly as tall? */
+	    if(im[i+mx*j] != NODATA &&
+	       (int)im[i+mx*j] > ((*big)-(*sky))*DBLFRAC+(*sky)) {
+/* Must be a local max */
+	       if(im[i+mx*j]>im[i-1+mx*j] && im[i+mx*j]>=im[i+1+mx*j] &&
+		  im[i+mx*j]>im[i+mx*(j-1)] && im[i+mx*j]>=im[i+mx*(j+1)]) {
+		  dblbig = im[i+mx*j];
+		  dblx = i;
+		  dbly = j;
+	       }
+	    }
+	 }
+      }
+/* Does a double star exist and is it to the left? */
+      if(dblbig > 0 && dblx < *ix) {
+	 *big = dblbig;
+	 *ix = dblx;
+	 *iy = dbly;
+      }
+   }
+
+/*  printf("%d %d %d %d %.1f %.1f\n",nsky, i,i0,i1,*sky,sqrt(var)); */
+
+/* "Signal to noise" is the ratio of the brightest pixel to the rms */
+   *sn = ((*big) - *sky) / sqrt(var);
+
+/* Estimate a width for the peak in x */
+   for(i=(*ix)+1; i<nx; i++) 
+      if(im[i+(*iy)*mx] != NODATA && im[i+(*iy)*mx] < ((*big)+(*sky))/2) break;
+   iwx = i - (*ix);
+
+/* Estimate a width for the peak in y */
+   for(i=(*iy)+1; i<ny; i++)
+      if(im[(*ix)+i*mx] != NODATA && im[(*ix)+i*mx] < ((*big)+(*sky))/2) break;
+   iwy = i - (*iy);
+
+/* Extract a strip in x */
+   for(i=EDGE; i<nx-EDGE; i++) {
+      strip[i] = 0.0;
+      n = 0;
+      for(j=MAX(EDGE,(*iy)-iwy); j<= MIN(ny-1-EDGE,(*iy)+iwy); j++) {
+	 if(im[i+j*mx] != NODATA) {
+	    strip[i] += im[i+j*mx];
+	    n++;
+	 }
+      }
+      if(n > 0) strip[i] =  strip[i] / n - (*sky);
+   }
+
+/* Find the peak in x */
+   if((algo%10) == 0) {
+      if(parabola(nx, strip, x0, &xhgt, xfwhm)) err |= XERROR ;
+   } else if((algo%10) == 1) {
+      niter = 20;
+      if(gaussian(&niter, nx-2*EDGE, strip+EDGE, gxpar) == 0) {
+	 *x0 = gxpar[3] + EDGE;
+	 *xfwhm = 2.4*gxpar[4];
+      } else {
+	 err |= GXERROR;
+	 if(parabola(nx, strip, x0, &xhgt, xfwhm)) err |= XERROR;
+      }
+   }
+
+   if((algo/1000000)%10 == 1) {
+      printf("%3d %3d %6.1f %8.3f %8.2f %8.2f %8.2f\n", 
+	     *iy, iwy, gxpar[0], gxpar[1],gxpar[2], gxpar[3],gxpar[4]);
+      for(i=0; i<nx-2*EDGE; i++) printf("%4d %8.1f\n", i, strip[EDGE+i]);
+   }
+
+/* Extract a strip in y */
+   for(j=EDGE; j<ny-EDGE; j++) {
+      strip[j] = 0.0;
+      n = 0;
+      for(i=MAX(EDGE,(*ix)-iwx); i<=MIN(nx-1-EDGE,(*ix)+iwx); i++) {
+	 if(im[i+j*mx] != NODATA) {
+	    strip[j] += im[i+j*mx];
+	    n++;
+	 }
+      }
+      if(n > 0) strip[j] =  strip[j] / n - (*sky);
+   }
+
+/* Find the peak in y */
+   if((algo%10) == 0) {
+      if(parabola(ny, strip, y0, &yhgt, yfwhm)) err |= YERROR;
+   } else if((algo%10) == 1) {
+      niter = 20;
+      if(gaussian(&niter, ny-2*EDGE, strip+EDGE, gypar) == 0) {
+	 *y0 = gypar[3] + EDGE;
+	 *yfwhm = 2.4*gypar[4];
+      } else {
+	 err |= GYERROR;
+	 if(parabola(ny, strip, y0, &yhgt, yfwhm)) err |= YERROR;
+      }
+   }
+
+   if((algo/1000000)%10 == 1) {
+      printf("%3d %3d %6.1f %8.3f %8.2f %8.2f %8.2f\n", 
+	     *ix, iwx, gypar[0], gypar[1],gypar[2], gypar[3],gypar[4]);
+      for(i=0; i<ny-2*EDGE; i++) printf("%4d %8.1f\n", i, strip[EDGE+i]);
+   }
+
+/* net FWHM = sqrt(fwx * fwy) */
+   *fwhm = (*xfwhm) * (*yfwhm);
+
+/* Sanity check on x0, y0 and FWHM, please! */
+   if(*fwhm <= 0 || 
+      *x0 < EDGE || *x0 > nx-1-EDGE || *y0 < EDGE || *y0 > ny-1-EDGE) {
+      *x0 = *ix;
+      *y0 = *iy;
+      *fwhm = *xfwhm = *yfwhm = MIN(nx,ny) / 4;
+      err |= FWERROR;
+   } else {
+      *fwhm = sqrt(*fwhm);
+   }
+
+/* Add up the total flux in excess of sky */
+/* Quick, dumb sum of +/-2.5 FWHM less sky */
+   if(((algo/10)%10) == 0) {
+      for(j=-2.5*(*fwhm), *flux=0.0; j<=2.5*(*fwhm); j++) {
+	 if(j+(*iy) >= EDGE && j+(*iy) <= ny-1-EDGE) {
+	    for(i=-2.5*(*fwhm); i<=2.5*(*fwhm); i++) {
+	       if(i+(*ix) >= EDGE && i+(*ix) <= nx-1-EDGE &&
+		   im[i+(*ix)+mx*(j+(*iy))] != NODATA) {
+		  *flux +=  im[i+(*ix)+mx*(j+(*iy))] - (*sky);
+	       }
+	    }
+	 }
+      }
+
+   } else {
+      int r, rmin, rmax, counts[2*MAXDIM], idx[2*MAXDIM], func;
+
+      func = ((algo/10)%10) - 1;
+
+/* This gets medsky from a square ring of outermost pixels */
+      for(j=EDGE, n=0; j<ny-EDGE; j++) {
+	 if(j >= EDGE+3 && j <= ny-1-EDGE-3) continue;
+	 for(i=EDGE; i<nx-EDGE; i++) {
+	    if(i >= EDGE+3 && i <= nx-1-EDGE-3) continue;
+	    if(im[i+mx*j] != NODATA) {
+	       strip[n++] =  im[i+mx*j];
+	    }
+	 }
+      }
+      medsky = median(n, strip, NULL);
+
+/* Sum up medians as a function of radius */
+      rmax = 0.65 * MIN(nx, ny) - EDGE;
+      rmin = MAX(2, 1.5*(*fwhm));
+      rmin = MIN(rmin, rmax-4);
+      for(r=rmin; r<=rmax; r++) {
+	 counts[r] = 0;
+	 idx[r] = 3.2 * r*r;
+      }
+/* Accumulate the pixels in the skirt of the psf into arrays by radius */
+      for(j=EDGE; j<ny-EDGE; j++) {
+	 for(i=EDGE; i<nx-EDGE; i++) {
+	    r = sqrt((i+0.5-(*x0))*(i+0.5-(*x0))+(j+0.5-(*y0))*(j+0.5-(*y0))) + 0.5;
+	    if(r<rmin || r>rmax) continue;
+	    strip[idx[r]+counts[r]] =  im[i+mx*j];
+	    counts[r] += 1;
+	 }
+      }
+/* Find the median as a function of radius*/
+      for(r=rmin; r<=rmax; r++) {
+	 strip[r] = r;
+	 strip[r+idx[rmin]] = median(counts[r], &strip[idx[r]], NULL);
+	 if((algo/1000000)%10 == 1) printf("%4d %4d %4d %6.1f\n", 
+				       r, counts[r], idx[r], strip[r+idx[rmin]]);
+      }
+
+      niter = 20;
+      if(wingfit(&niter, func, rmax-rmin+1, strip+idx[rmin]+rmin, strip+rmin, 
+		 wingpar)) err |= WINGERROR;
+#ifdef DEBUG
+      printf("wing %3d %7.2f %7.2f %7.2f\n", 
+	     niter, wingpar[0], wingpar[1], wingpar[2]);
+#endif
+/* power law fit sky */
+      *sky = wingpar[0];
+/* outermost circular ring */
+//      *sky = strip[rmax+idx[rmin]];
+/* outermost square pixels */
+//      *sky = medsky;
+/* Fixed sky at bias plus a bit */
+//	      *sky = 202;
+
+      for(j=EDGE, *flux=0.0; j<ny-EDGE; j++) {
+	 for(i=EDGE; i<nx-EDGE; i++) {
+	    *flux +=  im[i+mx*j] - *sky;
+	 }
+      }
+/* Add in a bit more from extrapolation of the extended wings */
+/*
+      rpow = 0.65*nx;
+      wing = -wingpar[1]*(2*3.14159) /(2+wingpar[2]) * pow(rpow,wingpar[2]+2);
+      *big = wing / (*flux) * 10000;
+      *flux +=  wing;
+      *flux -= 0.61 * wing;
+*/
+   }
+
+/*
+  printf("(%d,%d) (%.1f,%.1f) (%.1f,%.1f) %.1f %.1f %.1f %.1f %.1f %.0f %d\n",
+  *ix,*iy,*x0,*y0,x1,y1,*fwhm,r2,*sky,*sn,f0,*flux,MAX(iwx,iwy));
+  */
+   return(err);
+}
+
+/* Subroutine to fit a parabola to some data (fast)
+ * N         = n, where 2n+1 points are fitted
+ * CENTER    = center of fit parabola
+ * HEIGHT    = height of fit parabola
+ * WIDTH     = width of fit parabola
+ **************************CONVENTION******************************
+ The first element of the array is taken to be pixel 0.0 to 1.0
+ ******************************************************************
+ */
+
+static int
+parabola(nx, d, center, height, width)
+   int nx;
+   double *center, *height, *width, *d;
+{
+   double sum0=0.0, sum1=0.0, sum2=0.0, big;
+   float a, b, c;
+   int i, j, k, n;
+
+/* Find the center and estimate a width for the peak */
+   for(i=EDGE, big=d[EDGE], k=0; i<nx-EDGE; i++) {
+      if(d[i] > big) {
+	 big = d[i];
+	 k = i;
+      }
+   }
+  
+   for(i=k+1;  i<nx-EDGE; i++) if(d[i] < big/2) break;
+   for(j=k-1; j>=EDGE; j--) if(d[j] < big/2) break;
+   n = (i-j) / 2;
+   if(k-n < EDGE || k+n > nx-1-EDGE) n = MIN(k-EDGE, nx-1-EDGE-k);
+
+   if(n < 1) {
+      *center = k + 0.5;
+      *width = 0.0;
+      *height = big;
+      return(-1);
+   }
+
+   for(i=(-n); i<=n; i++) {
+      sum0 = sum0 + d[k+i];
+      sum1 = sum1 + i*d[k+i];
+      sum2 = sum2 + i*i*d[k+i];
+   }
+
+   a = 45.*(sum2 - n*(n+1)/3.*sum0) / (n*(n+1)*(2*n-1)*(2*n+1)*(2*n+3));
+   b = -3.*sum1 / (n*(n+1)*(2*n+1));
+   c = sum0 / (2*n+1);
+
+   if(a >= 0.0) {
+      *center = k + 0.5;
+      *width = 0.0;
+      *height = big;
+      return(-2);
+   }
+   *center = k + 0.5 + b/(2*a);
+   *height = c - a * (n*(n+1)/3. + b*b/(4*a*a));
+   *width = -2 * (*height) / a;
+
+/*
+  printf("\n");
+  for(i=k-4; i<=k+4; i++)
+  printf(" %8d", (int)d[i]);
+  printf("\n%4d %10.3f %10.3f %10.3f %10.3f %10.3f %10.3f\n",
+  k,a,b,c,*center,*width,*height);
+*/
+   if( *width > 0) *width = sqrt(*width);
+   else *width = 0.0;
+
+/* NaN sanity checks */
+   if( !(*center < 0.0 || *center >= 0.0) ||
+       !(*width  < 0.0 || *width  >= 0.0) ||
+       !(*height < 0.0 || *height >= 0.0) ) {
+      fprintf(stderr, "\nCorrecting a ctr NaN, nx = %d, k = %d, n = %d, max = %f\n", 
+	      nx, k, n, big);
+      *center = k + 0.5;
+      *width = 0.0;
+      *height = big;
+   }
+
+   return(0);
+}
+
+#define SKY 0
+#define SLP 1
+#define HGT 2
+#define CTR 3
+#define SIG 4
+
+#define TOL 0.1
+
+static int
+gaussian(int *niter, int n, double *d, double *par)
+/* par[0-4] = sky, slope, height, center, width */
+{
+   double *dfit, deriv[NGAUSS], curv[NGAUSS*NGAUSS];
+   double b[NGAUSS], delta[NGAUSS], a[NGAUSS*NGAUSS];
+   double lambda, chi, chinew, sqrt10;
+   int i, j, max, nfit, iter;
+
+#ifdef DEBUG
+   printf("%d", n);
+   for(i=0; i<n; i++) printf(" %4.0f", d[i]);
+   printf("\n");
+#endif
+
+/* Get some parameter estimates */
+   par[SKY] = 0.5*(d[0] + d[1]);
+   par[SLP] = (0.5*(d[n-1] + d[n-2]) - par[SKY]) / (n-2);
+   for(i=1, max=0, par[HGT]=d[0]; i<n; i++) {
+      if(d[i] > par[HGT]) {
+	 max = i;
+	 par[HGT] = d[i];
+      }
+   }
+   par[HGT] -= par[SKY] + (max+0.5)*par[SLP];
+
+   for(j=max+1; j<n; j++) {
+      if(d[j] < par[SKY] + (j+0.5)*par[SLP] + 0.5*par[HGT]) break;
+   }
+   for(i=max-1; i>=0; i--) {
+      if(d[i] < par[SKY] + (i+0.5)*par[SLP] + 0.5*par[HGT]) break;
+   }
+   par[SIG] = 0.25 * (j-i);
+/* Restrict fit to just the peak; Gaussians suck otherwise */
+   nfit = MAX(9, 2*(j-i)+1);
+   if(max - (nfit-1)/2 < 0 || max + (nfit-1)/2 > n-1)
+      nfit = MIN(2*max+1, 2*(n-1-max)+1);
+   dfit = d + max - (nfit-1)/2;
+   par[SKY] += (max-(nfit-1)/2) * par[SLP];
+   par[CTR] = (nfit-1)/2;
+
+   sqrt10 = sqrt(10.0);
+
+/* Do some Marquardt iterations */
+/*
+   printf("\nnfit = %4d\n", nfit);
+*/
+   for(iter=0, lambda=0.1; iter<*niter; iter++) {
+      dgauss(nfit, dfit, par, &chi, deriv, curv);
+#ifdef DEBUG
+      printf("%4d %7.4f %7.1f %7.1f %7.1f %7.2f %7.3f %7.1f\n", iter, lambda, 
+	     par[SKY], par[SLP], par[HGT], par[CTR], par[SIG], chi);
+#endif
+      for(j=0; j<NGAUSS; j++) {
+	 b[j] = deriv[j];
+	 for(i=0; i<NGAUSS; i++) {
+	    a[i+j*NGAUSS] = curv[i+j*NGAUSS];
+	 }
+	 a[j+j*NGAUSS] *= (1+lambda);
+      }
+      if(linsolve(NGAUSS, b, a, delta) != 0) { /* probably in very bad shape */
+/* 2 means singular matrix -- these should be understood and debugged */
+	 return(-1);
+      }
+      for(j=0; j<NGAUSS; j++) par[j] -= delta[j];
+      gchi(nfit, dfit, par, &chinew);
+      if(chi-chinew < TOL) {
+	 par[CTR] += max - (nfit-1)/2;
+	 *niter = iter;
+/*	 printf("n = %d", *niter); */
+	 return(0);
+      } else if(chinew < chi) {
+	 lambda /= sqrt10;
+      } else {
+	 lambda *= sqrt10;
+	 for(j=0; j<NGAUSS; j++) par[j] += delta[j];
+      }
+   }
+   *niter = iter;
+   return(1);
+}
+
+static int
+gchi(int n, double *d, double *par, double *chi)
+/* par[0-4] = sky, slope, height, center, width */
+{
+   double z, expo, diff;
+   int i;
+   for(i=0, *chi = 0.0; i<n; i++) {
+      z = i + 0.5;
+      expo = exp(-0.5*(z-par[CTR])*(z-par[CTR])/(par[SIG]*par[SIG]));
+      diff = par[SKY] + par[SLP]*z + par[HGT]*expo - d[i];
+      *chi += diff * diff;
+   }
+   return(0);
+}
+
+static int
+dgauss(int n, double *d, double *par, double *chi, double *deriv, double *curv)
+/* par[0-4] = sky, slope, height, center, width */
+{
+   double z, expo, diff, df[NGAUSS];
+   int i, j, k;
+   *chi = 0.0;
+   for(i=0; i<NGAUSS; i++) deriv[i] = 0.0;
+   for(i=0; i<NGAUSS*NGAUSS; i++) curv[i] = 0.0;
+   df[SKY] = 1.0;
+   for(i=0; i<n; i++) {
+      z = i + 0.5;
+      expo = exp(-0.5*(z-par[CTR])*(z-par[CTR])/(par[SIG]*par[SIG]));
+      diff = par[SKY] + par[SLP]*z + par[HGT]*expo - d[i];
+      *chi += diff * diff;
+      df[SLP] = z;
+      df[HGT] = expo;
+      df[CTR] = par[HGT] * expo * (z-par[CTR]) / (par[SIG]*par[SIG]);
+      df[SIG] = par[HGT] * expo * (z-par[CTR])*(z-par[CTR]) / 
+	 (par[SIG]*par[SIG]*par[SIG]);
+      for(j=0; j<NGAUSS; j++) {
+	 deriv[j] += diff * df[j];
+	 for(k=j; k<NGAUSS; k++) {
+	    curv[j+k*NGAUSS] += df[j] * df[k];
+	 }
+      }
+   }
+   for(j=1; j<NGAUSS; j++) {
+      for(k=0; k<j; k++) {
+	 curv[j+k*NGAUSS] = curv[k+j*NGAUSS];
+      }
+   }
+   return(0);
+}
+
+#define SKY 0
+#define AMP 1
+#define XPO 2
+#define PWRTOL 0.0001
+#define B4 1.0
+#define B6 0.5
+
+static int
+wingfit(int *niter, int func, int n, double *d, double *r, double *par)
+/* func = 0,1,2 for waussian, power law, exponential */
+/* par[0-2] = sky, amplitude, exponent */
+{
+   double deriv[NWING], curv[NWING*NWING];
+   double b[NWING], delta[NWING], a[NWING*NWING];
+   double lambda, chi, chinew, sqrt10, dmin;
+   int i, j, iter;
+
+#ifdef DEBUG
+   printf("%d\n", n);
+   for(i=0; i<n; i++) printf(" %4.0f", r[i]);
+   printf("\n");
+   for(i=0; i<n; i++) printf(" %4.0f", d[i]);
+   printf("\n");
+#endif
+
+/* Get some parameter estimates */
+   par[SKY] = d[n-1];
+   if(func == 0) {		/* Waussian */
+      par[XPO] = 5;
+      par[AMP] = (d[0]-d[n-1]) / exp(-0.5*r[0]*r[0]/(par[XPO]*par[XPO]));
+   } else if(func == 1) {	/* power law */
+      par[XPO] = -3.0;
+      par[AMP] = (d[0]-d[n-1]) / pow(r[0], par[XPO]);
+   } else if(func == 2) {	/* exponential */
+      par[XPO] = -0.1;
+      par[AMP] = (d[0]-d[n-1]) / exp(r[0]*par[XPO]);
+   }
+
+   for(i=1, dmin=d[0]; i<n; i++) dmin = MIN(dmin, d[i]);
+   dmin = 0.5 * dmin;
+
+   sqrt10 = sqrt(10.0);
+
+/* Do some Marquardt iterations */
+   for(iter=0, lambda=0.1; iter<*niter; iter++) {
+      dwingfit(func, n, r, d, dmin, par, &chi, deriv, curv);
+#ifdef DEBUG
+      printf("%4d %7.4f %7.1f %7.1f %7.3f %7.1f\n", iter, lambda, 
+	     par[SKY], par[AMP], par[XPO], chi);
+#endif
+      for(j=0; j<NWING; j++) {
+	 b[j] = deriv[j];
+	 for(i=0; i<NWING; i++) {
+	    a[i+j*NWING] = curv[i+j*NWING];
+	 }
+	 a[j+j*NWING] *= (1+lambda);
+      }
+      if(linsolve(NWING, b, a, delta) != 0) return(-1);
+      for(j=0; j<NWING; j++) par[j] -= delta[j];
+      wingchi(func, n, r, d, dmin, par, &chinew);
+
+      if(chi < chinew) {
+	 lambda *= sqrt10;
+	 for(j=0; j<NWING; j++) par[j] += delta[j];
+      } else if(chi-chinew < PWRTOL) {
+	 *niter = iter;
+	 return(0);
+      } else if(chinew < chi) {
+	 lambda /= sqrt10;
+      }
+   }
+   *niter = iter;
+   return(1);
+}
+
+static int
+wingchi(int func, int n, double *r, double *d, 
+	double dmin, double *par, double *chi)
+/* par[0-2] = sky, amplitude, exponent */
+{
+   double diff, z2, expo=0.0;
+   int i;
+   for(i=0, *chi = 0.0; i<n; i++) {
+      if(func == 0) {		/* Waussian */
+	 z2 = 0.5 * r[i]*r[i] / (par[XPO]*par[XPO]);
+	 expo = 1/(1+z2*(1+z2*(B4/2+z2*B6/6)));
+      } else if(func == 1) {	/* power law */
+	 expo = pow(r[i], par[XPO]);
+      } else if(func == 2) {	/* exponential */
+	 expo = exp(r[i]*par[XPO]);
+      }
+      diff = par[SKY] + par[AMP]*expo - d[i];
+      *chi += diff * diff / ((d[i]-dmin)*(d[i]-dmin));
+   }
+   return(0);
+}
+
+static int
+dwingfit(int func, int n, double *r, double *d, double dmin, double *par, 
+	  double *chi, double *deriv, double *curv)
+/* par[0-2] = sky, amplitude, exponent */
+{
+   double expo=0.0, diff, df[NWING], z2;
+   int i, j, k;
+   *chi = 0.0;
+   for(i=0; i<NWING; i++) deriv[i] = 0.0;
+   for(i=0; i<NWING*NWING; i++) curv[i] = 0.0;
+   df[SKY] = 1.0;
+   for(i=0; i<n; i++) {
+      if(func == 0) {	/* Waussian */
+	 z2 = 0.5 * r[i]*r[i] / (par[XPO]*par[XPO]);
+	 expo = 1 / (1+z2*(1+z2*(B4/2+z2*B6/6)));
+	 df[XPO] = par[AMP] * expo*expo * (1+z2*(B4+z2*B6/2)) * 
+	    r[i]*r[i] / (par[XPO]*par[XPO]*par[XPO]);
+      } else if(func == 1) {	/* power law */
+	 expo = pow(r[i], par[XPO]);
+	 df[XPO] = par[AMP] * log(r[i]) * expo;
+      } else if(func == 2) {	/* exponential */
+	 expo = exp(par[XPO]*r[i]);
+	 df[XPO] = par[AMP] * r[i] * expo;
+      }
+      diff = par[SKY] + par[AMP]*expo - d[i];
+      *chi += diff * diff / ((d[i]-dmin)*(d[i]-dmin));
+      df[AMP] = expo;
+      for(j=0; j<NWING; j++) {
+	 deriv[j] += diff * df[j] / ((d[i]-dmin)*(d[i]-dmin));
+	 for(k=j; k<NWING; k++) {
+	    curv[j+k*NWING] += df[j] * df[k] / ((d[i]-dmin)*(d[i]-dmin));
+	    if(j==XPO && k==XPO) { /* second deriv, probably not nec */
+	       if(func == 1) {		/* power law */
+		  curv[j+k*NWING] += diff * df[XPO] * log(r[i]) / 
+		     ((d[i]-dmin)*(d[i]-dmin)); 
+	       } else if(func == 2) {	/* exponential */
+		  curv[j+k*NWING] += diff * df[XPO] * r[i] / 
+		     ((d[i]-dmin)*(d[i]-dmin)); 
+	       }
+	    }
+	    if(j==AMP && k==XPO) { /* second deriv, probably not nec */
+	       if(func == 1) {		/* power law */
+		  curv[j+k*NWING] += diff * expo * log(r[i]) / 
+		     ((d[i]-dmin)*(d[i]-dmin)); 
+	       } else if(func == 2) {	/* exponential */
+		  curv[j+k*NWING] += diff * expo * r[i] / 
+		     ((d[i]-dmin)*(d[i]-dmin)); 
+	       }
+	    }
+	 }
+      }
+   }
+   for(j=1; j<NWING; j++) {
+      for(k=0; k<j; k++) {
+	 curv[j+k*NWING] = curv[k+j*NWING];
+      }
+   }
+   return(0);
+}
+
+#ifdef FANCY_STUFF
+static int
+exponential_bias(bias, ampl, efold, nx,ny,mx, im)
+   double *bias;
+   double *ampl, *efold;	/* Sky level at bottom * exp(efold*y) */
+   int nx, ny, mx;		/* Size of image; x size of image storage */
+   unsigned short *im;		/* Data array */
+{
+   int i, j, k, nsort, n;
+   double a, b, c, yave, eave, yeave, e2ave, chimin=0.0;
+
+/* Assemble medians in x as a function of y, fit exponential + constant */
+   for(j=EDGE, n=0; j<ny-EDGE; j++, n++) {
+      for(i=EDGE, nsort=0; i<=nx-1-EDGE; i++) {
+	 strip[ny+nsort++] = im[i+j*mx];
+      }
+      strip[n] = median(nsort, strip+ny, NULL);
+/*
+      fprintf(stderr,"%2d %6.2f\n",j, strip[n]);
+*/
+   }
+
+/* Evaluate chi^2 as a function of exponential arg */
+   for(k=0; k<100; k++) {
+      b = 0.002 * (k-50);	/* b = -0.1:+0.1 efold test */
+      for(i=0, j=EDGE, yave=eave=yeave=e2ave=0.0; i<n; i++, j++) {
+	 yave += strip[i];
+	 eave += exp(b*j);
+	 yeave += strip[i] * exp(b*j);
+	 e2ave += exp(2*b*j);
+      }
+      a = (yeave - yave*eave/n) / MAX(1e-10,e2ave-eave*eave/n);
+      c = (yave - a*eave)/n;
+/* Stash chi^2 off end of strip array */
+      for(i=0, j=EDGE, strip[k+n]=0.0; i<n; i++, j++) {
+	 strip[k+n] += (strip[i]-c-a*exp(b*j)) * (strip[i]-c-a*exp(b*j));
+      }
+/*
+      fprintf(stderr,"%.3f %6.2f ",b, strip[n+k]);
+*/
+/* Find the best fit as a function of k */
+      if(k == 0 || strip[n+k] <= chimin) {
+	 *ampl = a;
+	 *efold = b;
+	 *bias = c;
+	 chimin = strip[n+k];
+      }
+   }
+/*
+   fprintf(stderr,"\n");
+   fprintf(stderr,"%.3f %.3f %.3f\n", *ampl, *efold, *bias);
+*/
+   return(0);
+}
+
+static int
+video_bias_sub(bias, ampl, efold, nx,ny,mx, im)
+   double bias;
+   double ampl, efold;		/* Sky level at bottom * exp(efold*y) */
+   int nx, ny, mx;		/* Size of image; x size of image storage */
+   unsigned short *im;		/* Data array */
+{
+   int i, j;
+   double t;
+   for(j=EDGE; j<ny-EDGE; j++) {
+      for(i=EDGE; i<nx-EDGE; i++) {
+	 t = im[i+j*mx] - bias - ampl * exp(efold*j);
+	 if(t >= 0)  im[i+j*mx] = (int)(t+0.5);
+	 else	     im[i+j*mx] = 0;
+/*
+	 if(j<EDGE || j>=ny-EDGE || i<EDGE || i>=nx-EDGE) im[i+j*mx] = 0;
+*/
+      }
+   }
+   return(0);
+}
+#endif
+
+#if 0
+static int
+old_video_bias_sub(bias, ampl, efold, nx,ny,mx, im)
+   double bias;
+   double ampl, efold;		/* Sky level at bottom * exp(efold*y) */
+   int nx, ny, mx;		/* Size of image; x size of image storage */
+   unsigned short *im;		/* Data array */
+{
+   int i, j;
+   double median;
+/*
+   for(j=EDGE; j<ny-EDGE; j++) {
+      for(i=EDGE; i<=nx-1-EDGE; i++) {
+*/
+   for(j=0; j<ny; j++) {
+      for(i=0; i<nx; i++) {
+	 median = exp(ampl + efold*j);
+	 im[i+j*mx] -= median + bias;
+      }
+   }
+   return(0);
+}
+
+static int
+old_exponential_bias(bias, ampl, efold, nx,ny,mx, im)
+   double *bias;
+   double *ampl, *efold;	/* Sky level at bottom * exp(efold*y) */
+   int nx, ny, mx;		/* Size of image; x size of image storage */
+   unsigned short *im;		/* Data array */
+{
+   int i, j, nsort, n;
+   double sx, sx2, sy, sy2, sxy, med;
+   double delx, dely, delxy;
+
+/* Assemble medians in x as a function of y, fit linear function */
+   sx = sx2 = sy = sy2 = sxy = 0;
+   for(j=EDGE, n=0; j<ny-EDGE; j++) {
+      for(i=EDGE, nsort=0; i<=nx-1-EDGE; i++) {
+	 strip[nsort++] = log(MAX(1.0, im[i+j*mx]-*bias));
+      }
+      med = median(nsort, strip, NULL);
+      n++;
+      sx += j;
+      sx2 += j*j;
+      sy += med;
+      sy2 += med*med;
+      sxy += j*med;
+/*      fprintf(stderr,"%2d %6.2f",n, med); */
+   }
+/*   fprintf(stderr,"\n"); */
+
+/* Fit the profile now with a linear (i.e. exponential) function */
+   delx = n*sx2 - sx*sx;
+   dely = n*sy2 - sy*sy;
+   delxy = n*sxy - sx*sy;
+   if(delx != 0.0) {
+      *ampl = (sx2*sy - sx*sxy) / delx;
+      *efold = delxy / delx;
+   } else {
+      *ampl = *bias;
+      *efold = 0.0;
+   }
+
+   return(0);
+}
+#endif
+
+/* median.c : simple bubble sort, carry another array, return median
+ *
+ * 020130 John Tonry
+ */
+static
+double median(int n, double *key, int *idx)
+{
+   int i, j, k, itmp=0;
+   double tmp;
+
+   for(j=n-2; j>=0; j--) {
+      for(i=j+1, k=j; i<n; i++) {
+	 if(key[j] <= key[i]) break;
+	 k = i;
+      }
+      if(k == j) continue;
+      tmp = key[j];
+      if(idx != NULL) itmp = idx[j];
+      for(i=j+1; i<=k; i++) {
+	 key[i-1] = key[i];
+	 if(idx != NULL) idx[i-1] = idx[i];
+      }
+      key[k] = tmp;
+      if(idx != NULL) idx[k] = itmp;
+   }
+   tmp = 0.5 * (key[n/2]+key[(n-1)/2]);		/* Median */
+   return(tmp);
+}
+
+/* linsolve.c - solve a set of linear equations */
+/*
+ * Solves the matrix equation   Y = A X,   returns X.
+ *        where y[j=0,n-1], x[i=0,n-1], a[i+j*n].
+ */
+/* 020211 - John Tonry */
+#define MAXEQ 100
+
+static int
+linsolve(int n, double *y, double *a, double *x)
+{
+   int i, j, k;
+   int rowstatus[MAXEQ], row[MAXEQ];
+   double rat;
+
+   if(n > MAXEQ) {
+      fprintf(stderr, "error: too many equations %d req %d max\n", n, MAXEQ);
+      return(1);
+   }
+
+   for(i=k=0; i<n; i++) rowstatus[i] = 0;
+
+/* Solve matrix by Gaussian elimination */
+   for(j=0; j<n; j++) {		/* j = column to be zero'ed out */
+
+/* Find a good equation to work on (pivot row) */
+      for(i=0, rat=0.0; i<n; i++) {
+	 if(rowstatus[i]) continue;
+	 if(ABS(a[j+i*n]) > rat) {
+	    k = i;
+	    rat = ABS(a[j+k*n]);
+	 }
+      }
+      rowstatus[k] = 1;
+      row[j] = k;
+      if(rat == 0.0) {
+/*
+	 fprintf(stderr, "WHOA: singular matrix, col %d, row %d\n", j, k);
+*/
+	 return(2);
+      }
+/* Subtract away matrix below diagonal */
+      for(i=0; i<n; i++) {	/* i = subsequent equations */
+	 if(rowstatus[i]) continue;
+	 rat = a[j+i*n] / a[j+row[j]*n];
+	 y[i] -= rat*y[row[j]];
+ 	 for(k=j+1; k<n; k++) a[k+i*n] -= rat*a[k+row[j]*n];
+      }
+   }
+
+/* Back substitute into upper diagonal matrix to solve for parameters */
+   for(j=n-1; j>=0; j--) {
+      x[j] = y[row[j]];
+      for(k=j+1; k<n; k++) x[j] -= a[k+row[j]*n]*x[k];
+      x[j] = x[j] / a[j+row[j]*n];
+   }
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfmoment.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfmoment.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/analysis/libpsf/psfmoment.c	(revision 23490)
@@ -0,0 +1,233 @@
+/* psfmoment.c: find and fit the brightest star in an image; donuts OK */
+
+/* Note: this is not as fast as psf() nor as accurate as jtpsf() for
+ * flux, width, and position, but it is tolerant of donuts and should
+ * provide a pretty good width and center.
+ */
+/* 080815 v1.0 John Tonry */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <string.h>
+#include <math.h>
+#include "psf.h"
+
+//#define TEST
+
+// #define XBORD 4		/* Disregard this border on the x sides */
+// #define YBORD 2		/* Disregard this border on the y sides */
+#define SIGCLIP 5.0	/* Sky clip level */
+#define FWRMS 2.3548	/* Conversion factor: FWHM/RMS */
+#define CTRTOL 1.0	/* Tolerance for centroid to move between passes */
+
+/* Find and report on the brightest star; will work with donuts... */
+int psfmoment(int sx, 		/* x offset of pixel 0,0 */
+	     int sy,  		/* y offset of pixel 0,0 */
+	     int binx,  		/* x bin factor */
+	     int biny,   		/* y bin factor */
+/* The "world coords" and FWHM are derived from pixel coords off of the data by
+ *    x_world = *xu = sx + x_data*binx
+ *    y_world = *yu = sy + y_data*binx
+ * Center of the first pixel is (0.5,0.5)
+ */
+	     int bordx,  		/* x border */
+	     int bordy,   		/* y border */
+	     int nx,   			/* x size of image */
+	     int ny,    		/* y size of image */
+	     int NX,   			/* x size of image */
+	     unsigned short *data,	/* ushort image data: 0 = *NO_DATA* */
+	     double *xu,		/* Fitted x position */
+	     double *yu,		/* Fitted y position */
+	     int *fmax,			/* Highest pixel in best bin */
+	     double *fwhm,		/* FWHM of psf (binx,y corrected) */
+	     double *xfwhm,		/* FWHM in x dir (binx corrected) */
+	     double *yfwhm,		/* FWHM in y dir (biny corrected) */
+	     double *bkgnd,		/* Sky level */
+	     double *ftot,		/* Total flux */
+	     double *weight,		/* Composite quality of star: <1 bad,*/
+	     				/*    1-10 so-so, 10-30 OK, >30 fine */
+	     double *snr,		/* S/N of (big-sky)/noise */
+	     int *extra)		/* More return stuff? */
+{
+   int i, j, k, med=0, lq=0, uq=0, bright=0, bright2=0, flim1, flim2;
+   int i0, i1, i2, npix, nbig, pass, biggie, ibig=0, jbig=0;
+   double x0=0.0, y0=0.0, xc=0.0, yc=0.0, a4, a5, a6, mxmy_14, fluxsum, sky;
+   double x1, y1, x2, y2, mx, my, mxy, flux1, flux2, nearlow, r2;
+   double theta, a=0.0;
+   double rms, kappa, kappa2, rcut, flux;
+   int count[65536];
+
+/* Determine the sky level */
+   kappa = 0.99;		/* Fraction of pixels dim enough to ignore */
+   kappa2 = 0.75;		/* Fraction of pixels dim enough to ignore */
+   bzero(count, 65536*sizeof(int));
+   for(j=bordy, flux=0.0; j<ny-bordy; j++) {
+      for(i=bordx; i<nx-bordx; i++) {
+	 (count[data[i+j*NX]])++;
+/* Where's the biggest pixel? */
+	 if(data[i+j*NX] > flux) {
+	    flux = data[i+j*NX];
+	    x0 = i;
+	    y0 = j;
+	 }
+      }
+   }
+   i0 = 0.5*(nx-2*bordx)*(ny-2*bordy);
+   i1 = kappa*(nx-2*bordx)*(ny-2*bordy);
+   i2 = kappa2*(nx-2*bordx)*(ny-2*bordy);
+   for(i=1, j=0; i<65536; i++) {
+      j += count[i];
+      if(j < i0/2) lq = i;
+      if(j < i0) med = i;
+      if(j < (3*i0)/2) uq = i;
+      if(j < i2) bright2 = i;
+      if(j < i1) bright = i;
+   }
+/* Get sky as median between median +/- SIGCLIP*quartile */
+   i0 = MAX(0,med-SIGCLIP*(med-lq));
+   i1 = MIN(65535,med+SIGCLIP*(med-lq));
+   for(i=i0, k=0; i<=i1; i++) k += count[i];
+   if(k == 0) {
+      fprintf(stderr, "psfmoment: No sky pixels at all?\n");
+      return(-1);
+   }
+   for(i=i0, j=0; i<=i1; i++) {
+      j += count[i];
+      if(j >= k/2) break;
+   }
+   sky = i;
+   if(count[i] > 0) sky += ((double)(j-k/2))/count[i] - 1.0;
+
+   rms = (uq-med) / 0.7;
+   if(rms < 0.5) rms = 0.5;
+
+/* subtract sky, clip noise and sum flux and first and moments */
+   flim2 = bright - sky;	/* Flux limit for RMS calculation */
+   flim1 = MIN(2*rms, flim2);	/* Flux limit for centroid calculation */
+   rcut = MAX(binx*nx,biny*ny);	/* Radius limit */
+
+#ifdef TEST
+   printf("i0,i1,lq,med,uq,bright= %d %d %d %d %d %d sky=%.1f rms=%.1f flim1=%d flim2=%d\n", 
+	  i0,i1,lq,med,uq,bright,sky,rms,flim1,flim2);
+#endif
+
+/* Three passes: find center, get decent FWHM, tune it up (if necessary) */
+   for(pass=0; pass<3; pass++) {
+      fluxsum = 0.0;
+      x1 = y1 = flux1 = 0.0;
+      x2 = y2 = mx = my = mxy = flux2 = 0.0;
+      npix = nbig = biggie = 0;
+      nearlow = MAX(nx*nx, ny*ny);
+      for(j=bordy; j<ny-bordy; j++) {
+	 for(i=bordx; i<nx-bordx; i++) {
+	    flux = data[i+j*NX] - sky;
+	    r2 = binx*binx*(i+0.5-x0)*(i+0.5-x0) +
+	         biny*biny*(j+0.5-y0)*(j+0.5-y0);
+/* Where's the nearest pixel which is near sky? */
+	    if(flux < rms && r2 < nearlow) nearlow = r2;
+/* Sum up moments within a radius of rcut */
+	    if(r2 < rcut*rcut) {
+/* Very low flux cut to get total flux */
+	       if(flux > -2*rms) fluxsum += flux;
+/* Modest flux cut to get center */
+	       if(flux > flim1) {
+		  npix++;
+		  flux1 += flux;
+		  x1 += (i+0.5) * flux;
+		  y1 += (j+0.5) * flux;
+	       }
+/* Higher flux cut to get moment */
+	       if(flux > flim2) {
+		  nbig++;
+		  flux2 += flux;
+		  x2 += (i+0.5) * flux;
+		  y2 += (j+0.5) * flux;
+		  mx += (i+0.5)*(i+0.5) * flux;
+		  my += (j+0.5)*(j+0.5) * flux;
+		  mxy += (i+0.5)*(j+0.5) * flux;
+		  if(flux > biggie) {
+		     ibig = i;
+		     jbig = j;
+		     biggie = flux;
+		  }
+	       }
+	    }
+	 }
+      }
+//      printf("npix,xc,yc,mx,my,mxy,fluxsum = %d %.1f %.1f %.1f %.1f %.1f %.1f\n", 
+//	     npix, xc, yc, mx, my, mxy, fluxsum);
+/* Is first moment OK for centroid? */
+      if(flux1 > rms*npix) {
+	 xc = x1 / flux1;
+	 yc = y1 / flux1;
+      } else {
+	 xc = x0;
+	 yc = y0;
+      }
+
+/* Is second moment OK for RMS?  Calculate variances about the mean. */
+      if(flux2 > rms*nbig) {
+	 mx = (mx - x2*x2/flux2) * (binx*binx/flux2);
+	 my = (my - y2*y2/flux2) * (biny*biny/flux2);
+	 mxy = (mxy - x2*y2/flux2) * (binx*biny/flux2);
+      } else {
+	 mx = my = mxy = 0.0;
+      }
+/* Radius from previous center to nearest pixel which is close to sky */
+      nearlow = sqrt(nearlow);
+#ifdef TEST
+      printf("npix,nbig,xc,yc,mx,my,mxy,fluxsum,rcut,nearlow,flim2 = %d %d %5.1f %5.1f %6.1f %6.1f %6.2f %7.0f %5.1f %5.1f %d\n", 
+	     npix, nbig, xc, yc, mx, my, mxy, fluxsum, rcut, nearlow, flim2);
+#endif
+
+      if(mx > 0 && my > 0) {
+	 a4 = sqrt((mx+my)/2.0);
+//	 mxmy_14 = sqrt(sqrt(mx*my));
+//	 a5 = mxy / mxmy_14 ;
+//	 a6 = (mx-my) * mxmy_14 / 2.0 ;
+      } else {
+	 a4 = mxmy_14 = a5 = a6 = 0.0;
+      }
+
+      if(pass > 0 && ABS(x0-xc) < CTRTOL && ABS(y0-yc) < CTRTOL && 
+	 a4 > rcut/5) break;
+
+      x0 = xc;
+      y0 = yc;
+/* Squeeze down rcut to max of 3*RMS or nearlow */
+      rcut = MAX(3*a4, 6.0);
+      rcut = MAX(rcut, nearlow);
+/* Lower flim2 to kappa2 */
+      flim2 = bright2 - sky;
+   }
+
+/* Ellipse variables: major/minor ~ (1+a) */
+   if(a4 > 0) a = sqrt(mxy*mxy+(mx-my)*(mx-my)/4) / ((mx+my)/2);
+   theta = 0.5 * atan2(mxy, (mx-my)/2);
+#ifdef TEST
+   printf("mx,my,mx-my/2,mxy,a, theta = %8.2f %8.2f  %8.2f %8.2f %8.2f %8.2f\n", 
+	  mx,my,(mx-my)/2,mxy,a, theta/0.0174533);
+#endif
+
+/* Return values */
+   *xu = sx + xc*binx;
+   *yu = sy + yc*biny;
+   *fmax = biggie;
+   *fwhm = FWRMS * a4;
+   *xfwhm = FWRMS * sqrt(MAX(0.0, mx));
+   *yfwhm = FWRMS * sqrt(MAX(0.0, my));
+   *bkgnd = sky;
+   *ftot = fluxsum;
+   *snr = a4 > 0 ? fluxsum / sqrt(k*rms*rms) : 0.0;
+/* This could in principle have extra info, e.g. higher order moments */
+   *weight = *snr;
+
+#ifdef TEST
+   printf("xu,yu,FWHM,snr,x,y,max= %.1f %.1f %.2f %.1f %d %d %d\n", 
+	  *xu, *yu, *fwhm, *snr, ibig, jbig, biggie);
+#endif
+
+
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/Make.Common
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/Make.Common	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/Make.Common	(revision 23490)
@@ -0,0 +1,1 @@
+link ../Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/Make.Common
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/Make.Common	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/Make.Common	(revision 23490)
@@ -0,0 +1,1 @@
+link ../Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/Makefile
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/Makefile	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/Makefile	(revision 23490)
@@ -0,0 +1,36 @@
+include ../Make.Common
+
+VERSION=0.00
+# CCWARN+=$(WERROR)
+CCDEFS+=$(VERSIONDEFS)
+CCLINK += -lm
+$(EXECNAME): $(OBJS) libfh.a libpsf.a libpscoords.a
+
+include ../Make.Common
+
+# Dependencies by Make.Common $Revision: 2.17 $
+
+$(OBJ)/basement.o: basement.c
+
+$(OBJ)/burnfix.o: burnfix.c burntool.h burnparams.h
+
+$(OBJ)/burntool.o: burntool.c fh/fh.h fhreg/general.h \
+  fhreg/macros.h fhreg/gpc_detector.h \
+  burntool.h burnparams.h
+
+$(OBJ)/burnutils.o: burnutils.c burntool.h burnparams.h
+
+$(OBJ)/cheapfits.o: cheapfits.c
+
+$(OBJ)/persistfix.o: persistfix.c burntool.h burnparams.h
+
+$(OBJ)/persistio.o: persistio.c burntool.h burnparams.h
+
+$(OBJ)/psfstamp.o: psfstamp.c burntool.h burnparams.h \
+  pscoords/pscoords.h
+
+$(OBJ)/psfstats.o: psfstats.c burntool.h psf/psf.h
+
+$(OBJ)/stardetect.o: stardetect.c burntool.h burnparams.h
+
+$(OBJ)/trailfit.o: trailfit.c burntool.h burnparams.h
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnfix.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnfix.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnfix.c	(revision 23490)
@@ -0,0 +1,265 @@
+/* burnfix.c - various functions to identify and fix burn trails */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "math.h"
+
+#include "burntool.h"
+#include "burnparams.h"
+
+/****************************************************************/
+/* burn_fix(): Find and fix all the burned patches in a cell */
+STATIC int burn_fix(int nx, int ny, int NX, int NY, IMTYPE *buf, 
+		    CELL *cell, int cellnum)
+{
+   int k, err;
+
+/* Find all the burned patches and bright stars */
+   err = star_detect(nx, ny, NX, NY, imbuf, mbuf, msbuf, cell, cellnum);
+   err = burn_check(nx, ny, NX, NY, imbuf, mbuf, cell);
+
+/* Expand the masks; burns asymmetrically, stars symmetrically */
+//   err = grow_mask(nx, ny, NX, mbuf, YMASK_GROW, YMASK_GROW, cell->nstar, cell->star);
+//   err = grow_mask(nx, ny, NX, mbuf, XMASK_GROW, YMASK_GROW, cell->nburn, cell->burn);
+   err = grow_mask(nx, ny, NX, mbuf, BMASK_GROW, RMASK_GROW, 
+		   MASK_SAT_HALO, cell->nburn, cell->burn);
+   err = grow_mask(nx, ny, NX, mbuf, BMASK_GROW, RMASK_GROW, 
+		   MASK_STAR_HALO, cell->nstar, cell->star);
+
+/* Fix up all the burns */
+   for(k=0; k<cell->nburn; k++) {
+      if(!cell->burn[k].burned) continue;
+/* Fit the trail */
+      fit_trail(nx, ny, NX, imbuf, mbuf, cell->burn+k, 1, 
+	     cell->sky+cell->bias, cell->rms, BURN_PWR);
+/* Subtract the fit from the image */
+      if(!cell->burn[k].fiterr) sub_fit(nx, ny, NX, buf, cell->burn+k, 1);
+   }
+
+/* For testing, blow away the data in favor of the mask */
+   if(VERBOSE & VERB_MASK) {
+      for(k=0; k<NX*ny; k++) buf[k] = mbuf[k] - BZERO;
+   }
+   return(err);
+}
+
+/****************************************************************/
+/* burn_blab(): Tell us about all the objects found in this cell */
+STATIC int burn_blab(CELL *cell)
+{
+   int i, k, ymid;
+
+/* Tell us about it? */
+   printf("Cell: %d  sky= %d   rms= %d   bias= %d\n", 
+	  cell->cell, cell->sky, cell->rms, cell->bias);
+
+/* The burns */
+   printf("Burns:\n");
+   printf("  #    cx  cy  max     sx  sy    ex  ey  midy  diff  S/B/E  slope     zero\n");
+   for(k=0; k<cell->nburn; k++) {
+      ymid = (cell->burn[k].y0m + cell->burn[k].y1m +
+	      cell->burn[k].y0p + cell->burn[k].y1p + 2) / 4;
+      i = cell->burn[k].nfit / 2;
+      printf("%3d %5d %3d %5d %5d %3d %5d %3d %5d %5d %2d %1d %1d %6.3f %8d\n", 
+	     k, 
+	     cell->burn[k].cx, cell->burn[k].cy,  cell->burn[k].max,
+	     cell->burn[k].sx, cell->burn[k].sy, 
+	     cell->burn[k].ex, cell->burn[k].ey, ymid,
+	     cell->burn[k].diff, cell->burn[k].sat, 
+	     cell->burn[k].burned, cell->burn[k].fiterr,
+	     cell->burn[k].slope, 
+	     cell->burn[k].zero != NULL ? NINT((cell->burn[k]).zero[i]) : 0);
+   }
+
+/* The stars */
+   printf("Stars:\n");
+   printf("  #    cx  cy  max     sx  sy    ex  ey  midy  S/P\n");
+   for(k=0; k<cell->nstar; k++) {
+      ymid = (cell->star[k].y0m + cell->star[k].y1m +
+	      cell->star[k].y0p + cell->star[k].y1p + 2) / 4;
+
+      printf("%3d %5d %3d %5d %5d %3d %5d %3d %5d %2d %1d\n", 
+	     k, cell->star[k].cx, cell->star[k].cy, 
+	     cell->star[k].max, 
+	     cell->star[k].sx, cell->star[k].sy, 
+	     cell->star[k].ex, cell->star[k].ey, ymid,
+	     cell->star[k].sat, cell->star[k].func);
+   }
+   return(0);
+}
+
+/****************************************************************/
+/* burn_restore(): Restore the fitted trails back to the image */
+STATIC int burn_restore(int nx, int ny, int NX, IMTYPE *buf, CELL *cell)
+{
+   int k;
+
+/* Restore all the burns */
+   for(k=0; k<cell->npersist; k++) {
+      if(!cell->persist[k].fiterr) 
+	 sub_fit(nx, ny, NX, buf, &(cell->persist[k]), -1);
+   }
+   return(0);
+}
+
+
+/****************************************************************/
+/* burn_check(): Find all the burned patches in a cell */
+STATIC int burn_check(int nx, int ny, int NX, int NY, DTYPE *data,
+		       MTYPE *mask, CELL *cell)
+{
+   int err, k;
+
+/* Given these big stars, identify which ones really have a burn */
+   for(k=0; k<cell->nburn; k++) {
+      if(!cell->burn[k].burned) {
+	 cell->burn[k].diff = -1;
+	 continue;
+      }
+      err = burn_test(nx, ny, NX, data, cell->rms, mask, cell->burn+k);
+   }
+
+#ifdef TEST
+   printf("Boxes:  sky= %d  rms= %d  bias= %d\n", 
+	  cell->sky, cell->rms, cell->bias);
+   for(k=0; k<cell->nburn; k++) {
+      printf("%5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", 
+	     k, cell->burn[k].sx, cell->burn[k].sy, 
+	     cell->burn[k].ex, cell->burn[k].ey, 
+	     cell->burn[k].y0m, cell->burn[k].y1m, cell->burn[k].y0p, cell->burn[k].y0p,
+	     cell->burn[k].diff, cell->burn[k].burned);
+   }
+#endif
+
+/* Make Vista decorations for selected boxes? */
+   if(VERBOSE & VERB_VISTA) vista_marker(cell, VISTAMARKER);
+   return(0);
+}
+
+/****************************************************************/
+/* vista_marker(): Put out Vista commands to mark stars */
+STATIC int vista_marker(CELL *cell, char *fname)
+{
+   int k;
+   FILE *fp;
+
+/* Make Vista decorations for selected boxes? */
+   if(fname != NULL) {
+      if( (fp=fopen(fname, "w")) == NULL) {
+	 fprintf(stderr, "error: cannot open '%s' for writing\n", fname);
+	 return(-1);
+      }
+/* Saturated objects are red (burned) or green (not burned) */
+      for(k=0; k<cell->nburn; k++) {
+	 if(cell->burn[k].burned) fprintf(fp, "itv action=v color=1\n");/*red*/
+	 fprintf(fp, "itv action=b corners=(%d,%d,%d,%d)\n", 
+		 cell->burn[k].sx, cell->burn[k].sy, 
+		 cell->burn[k].ex, cell->burn[k].ey);
+	 fprintf(fp, "itv action=l corners=(%d,%d,%d,%d)\n", 
+		 cell->burn[k].sx, cell->burn[k].y0m, 
+		 cell->burn[k].x0m, cell->burn[k].sy);
+	 fprintf(fp, "itv action=l corners=(%d,%d,%d,%d)\n", 
+		 cell->burn[k].x0p, cell->burn[k].sy, 
+		 cell->burn[k].ex, cell->burn[k].y1m);
+	 fprintf(fp, "itv action=l corners=(%d,%d,%d,%d)\n", 
+		 cell->burn[k].ex, cell->burn[k].y1p, 
+		 cell->burn[k].x1p, cell->burn[k].ey);
+	 fprintf(fp, "itv action=l corners=(%d,%d,%d,%d)\n", 
+		 cell->burn[k].x1m, cell->burn[k].ey, 
+		 cell->burn[k].sx, cell->burn[k].y0p);
+	 fprintf(fp, "itv action=v color=0\n");/*green*/
+      }
+/* Stars are white */
+      fprintf(fp, "itv action=v color=3\n");/*white*/
+      for(k=0; k<cell->nstar; k++) {
+	 fprintf(fp, "itv action=b corners=(%d,%d,%d,%d)\n", 
+		 cell->star[k].sx, cell->star[k].sy, 
+		 cell->star[k].ex, cell->star[k].ey);
+	 fprintf(fp, "itv action=l corners=(%d,%d,%d,%d)\n", 
+		 cell->star[k].sx, cell->star[k].y0m, 
+		 cell->star[k].x0m, cell->star[k].sy);
+	 fprintf(fp, "itv action=l corners=(%d,%d,%d,%d)\n", 
+		 cell->star[k].x0p, cell->star[k].sy, 
+		 cell->star[k].ex, cell->star[k].y1m);
+	 fprintf(fp, "itv action=l corners=(%d,%d,%d,%d)\n", 
+		 cell->star[k].ex, cell->star[k].y1p, 
+		 cell->star[k].x1p, cell->star[k].ey);
+	 fprintf(fp, "itv action=l corners=(%d,%d,%d,%d)\n", 
+		 cell->star[k].x1m, cell->star[k].ey, 
+		 cell->star[k].sx, cell->star[k].y0p);
+      }
+      fprintf(fp, "itv action=v color=0\n");/*green*/
+      fclose(fp);
+   }
+   return(0);
+}
+
+/****************************************************************/
+/* burn_test() tests whether a box is burned or not */
+STATIC int burn_test(int nx, int ny, int NX, DTYPE *data, int rms,
+		       MTYPE *mask, OBJBOX *box)
+{
+   int i, j, n, nrow, nmed;
+   int y0, y1, ymid, xsum, dx=0;
+
+/* FIXME: needs a test for flat-toppedness as well as trail... */
+/* FIXME: needs a test for pure, massive saturation */
+
+/* Center line */
+   ymid = (box->y0m + box->y0p + box->y1m + box->y1p + 2) / 4;
+/* Starting point offset */
+   y0 = MAX(ymid-box->sy, box->ey-ymid);
+   if(y0 < FIT_EDGE) y0 = FIT_EDGE;
+
+/* Irrelevant, too near the top */
+   if(box->ey > ny-FIT_EDGE-3) {
+      box->diff = -1;
+      box->burned = -1;
+/* But looks like a bad one which will leave behind persistence */
+      if(box->ey-box->sy+1 > 4) box->burned = 1;
+      return(0);
+
+/* Need a one-sided test */
+   } else if(box->sy < FIT_EDGE+3) {
+/* Ending point offset */
+      y1 = ny;
+      dx = box->ex - box->sx;
+      if(box->sx > nx-1-box->ex) dx *= -1;
+
+   } else {
+/* Ending point offset */
+      y1 = MIN(ny-2-ymid, ymid-1);
+   }
+   n = MIN(100, y1-y0);
+
+   nmed = 0;
+   for(j=0; j<n; j++) {
+      xsum = 0;
+      nrow = 0;
+      for(i=box->sx; i<=box->ex; i++) {
+	 xsum += data[i+(ymid+y0+j)*NX]*(mask[i+(ymid+y0+j)*NX] == MASK_NONE);
+	 if(y1 < ny) {
+	    xsum -= data[i+(ymid-y0-j)*NX] * 
+	       (mask[i+(ymid-y0-j)*NX] == MASK_NONE);
+	    nrow += (mask[i+(ymid-y0-j)*NX] == MASK_NONE) * 
+	       (mask[i+(ymid+y0+j)*NX] == MASK_NONE);
+	 } else {
+	    xsum -= data[i+dx+(ymid+y0+j)*NX] * 
+	       (mask[i+dx+(ymid+y0+j)*NX] == MASK_NONE);
+	    nrow += (mask[i+dx+(ymid+y0+j)*NX] == MASK_NONE) * 
+	       (mask[i+(ymid+y0+j)*NX] == MASK_NONE);
+	 }
+      }
+      if(nrow > 0) median_buf[nmed++] = xsum / nrow;
+   }
+   box->diff = int_median(nmed, median_buf);
+   box->burned = 0;
+   if(box->diff > 0.3*rms) box->burned = 1;
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnparams.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnparams.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnparams.h	(revision 23490)
@@ -0,0 +1,51 @@
+/* A global buffer into which routines can accumulate detections */
+
+/* '#define EXTERN' in just one file, burntool.c, to declare variables */
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define MAXBURN 10000
+EXTERN OBJBOX boxbuf[MAXBURN];
+
+EXTERN int *median_buf;		/* Generic buffer for integer medians */
+EXTERN int nmedian_buf;
+
+EXTERN MTYPE *mbuf;		/* Buffer for object mask */
+EXTERN int nmbuf;
+
+EXTERN MTYPE *msbuf;		/* Buffer for vetoed star mask */
+EXTERN int nmsbuf;
+
+EXTERN DTYPE *imbuf;		/* Copy of cell data w/o BZERO */
+EXTERN int nimbuf;
+
+EXTERN int VERBOSE;		/* Verbosity level */
+
+EXTERN int BZERO;
+EXTERN int USHORT_BIAS;		/* Bias level restored to ushort stamps */
+
+EXTERN int MAX_READ_NOISE;	/* Maximum believable read noise (ADU) */
+EXTERN double MIN_EADU;		/* Minimum believable e/ADU */
+
+EXTERN int BURN_THRESH  ;	/* Threshold for onset of burning */
+EXTERN int TRAIL_THRESH ;	/* Trailing might go this low */
+EXTERN int MAX_THRESH   ;	/* Possibly trailing stars? */
+EXTERN int STAR_THRESH  ;	/* Threshold for star above sky */
+EXTERN double STAR_FRAC ;	/* Fraction to follow star profile */
+EXTERN int PSF_THRESH   ;	/* Threshold for a star to be a PSF */
+
+//EXTERN double XMASK_GROW ;	/* Growth of burned boxes in x dir */
+//EXTERN double YMASK_GROW ;	/* Growth of burn/star in y dir */
+
+EXTERN double BMASK_GROW ;	/* Growth of burned boxes in size */
+EXTERN double RMASK_GROW ;	/* Growth of burn/star in diameter */
+
+EXTERN int MIN_PSF_SIZE  ;	/* Min box size for stamp selection */
+EXTERN int PSF_CTR_TOL   ;	/* Choose max or box ctr for stamp */
+EXTERN int CONCAT_FITS;		/* Write concat FITS for PSF? (else 3D) */
+EXTERN int MAX_PSF_PER_CELL ; 	/* Max number of PSF stars accepted per cell */
+
+EXTERN double NEGLIGIBLE_TRAIL;	/* Don't sweat less than this * sigma */
+
+
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.c	(revision 23490)
@@ -0,0 +1,625 @@
+/*
+ * burntool.c - identify and remove persistance streaks from a MEF.
+ * Syntax: burntool mef_file [options]
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "math.h"
+#include "fh/fh.h"
+#include "fhreg/general.h"
+#include "fhreg/gpc_detector.h"
+
+#include "burntool.h"
+#define EXTERN  /* Define EXTERN to declare variables in params.h */
+#include "burnparams.h"
+
+int
+main(int argc, const char* argv[])
+{
+   int i, j, k, nx, ny, err;
+   HeaderUnit ihu = fh_create();
+   HeaderUnit ehu;
+   const char* ifilename = "-";
+   char extname[FH_MAX_STRLEN+1], otaposn[FH_MAX_STRLEN+1];
+   int cellmask[MAXCELL];
+   int otanum;
+   int nextend, cellxy, cell, cellcode;
+   int ext, update, restore, psfsize, psfavg;
+   IMTYPE *buf;
+   const char *burnfile=NULL,  *persistfile=NULL;
+   const char *psffile=NULL, *psfstatfile=NULL;
+   CELL OTA[MAXCELL];	/* Cell structure for entire OTA */
+
+   if(argc > 1 && strncmp(argv[1], "help", 4) == 0) {
+      syntax(argv[0]);
+      exit(EXIT_SUCCESS);
+   }
+
+   if(argv[1]) ifilename = argv[1];
+
+   if(fh_file(ihu, ifilename, FH_FILE_RDWR) != FH_SUCCESS) {
+      fprintf(stderr, "\rerror: burntool could not open file `%s'\n",
+	      ifilename);
+      exit(EXIT_FAILURE);
+   }
+   nextend = fh_extensions(ihu);
+   if (nextend < 1) {
+      fprintf(stderr, "\rerror: `%s' is not a multi-extension FITS\n",
+	      ifilename);
+      exit(EXIT_FAILURE);
+   }
+
+/* Initialize the globals */
+   VERBOSE = 0;			/* Verbosity level */
+
+   median_buf=NULL;		/* Buffer for medians */
+   nmedian_buf=0;
+
+   mbuf=NULL;			/* Mask buffer */
+   nmbuf=0;
+
+   imbuf=NULL;			/* Image copy buffer */
+   nimbuf=0;
+
+   BZERO = 32768;		/* BZERO for input data */
+   USHORT_BIAS = 1000;		/* Bias level restored to ushort stamps */
+
+   MAX_READ_NOISE = 20;		/* Maximum believable read noise (ADU) */
+   MIN_EADU = 0.3;		/* Minimum believable e/ADU */
+
+   BURN_THRESH  = 30000;	/* Threshold for onset of burning */
+   TRAIL_THRESH = 10000;	/* Trailing might go this low */
+   MAX_THRESH   = 20000;	/* Possibly trailing stars? */
+   STAR_THRESH  =  1000;	/* Threshold for star above sky */
+   STAR_FRAC =  0.3;		/* Fraction to follow star profile */
+   PSF_THRESH   =  5000;	/* Threshold for a star to be a PSF */
+
+   BMASK_GROW =  5.0;		/* Growth of burned boxes in size */
+   RMASK_GROW =  3.0;		/* Growth of burn/star in diameter */
+
+   MIN_PSF_SIZE  =    3;	/* Min box size for stamp selection */
+   PSF_CTR_TOL   =    8;	/* Choose max or box ctr for stamp */
+   CONCAT_FITS = 1;		/* Write concat FITS for PSF? (else 3D) */
+   MAX_PSF_PER_CELL = 20; 	/* Max number of PSF stars accepted per cell */
+
+   NEGLIGIBLE_TRAIL = 0.5;	/* Don't sweat less than this * sigma */
+
+
+/* Parse the args */
+   cellxy = -1;
+   update = 1;
+   restore = 0;
+   psfsize = 32;
+   psfavg = 0;
+   for(i=0; i<MAXCELL; i++) cellmask[i] = 1;
+   for(i=2; i<argc; i++) {
+
+/* Work on just one cell?  xy ID mode. */
+      if(strncmp(argv[i], "xy=", 3) == 0) {		/* xy=CELL_ID */
+	 if(sscanf(argv[i]+3, "%d", &cellxy) != 1) {
+	    fprintf(stderr, "\rerror: cannot get cell ID from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* Work on just one cell? Cell count [0:63] mode. */
+      } else if(strncmp(argv[i], "cell=", 5) == 0) {	/* cell=0:63 */
+	 if(sscanf(argv[i]+5, "%d", &cellxy) != 1) {
+	    fprintf(stderr, "\rerror: cannot get cell ID from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+	 cellxy = cellxy/8 + 10*(cellxy%8);
+
+/* Veto cells by a 64 digit mask (0/1 for cells 0-63) */
+      } else if(strncmp(argv[i], "mask=", 5) == 0) {	/* mask=64_digits */
+	 if(strlen(argv[i]) < 5+MAXCELL) {
+	    fprintf(stderr, "\rerror: cannot get mask from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 } else {
+	    for(j=0; j<MAXCELL; j++) cellmask[j] = argv[i][5+j] != '0';
+	 }
+
+/* Modify the input MEF by subtracting fits? */
+      } else if(strncmp(argv[i], "update=", 7) == 0) {	/* update={t|f} */
+	 update = argv[i][7] == 'y' || argv[i][7] == '1' || argv[i][7] == 't';
+
+/* Modify the input MEF by subtracting fits? */
+      } else if(strncmp(argv[i], "restore=", 8) == 0) {	/* restore={t|f} */
+	 restore = argv[i][8] == 'y' || argv[i][8] == '1' || argv[i][8] == 't';
+
+/* Output file for burn streaks */
+      } else if(strncmp(argv[i], "trailout=", 9) == 0) {/* trailout=fname */
+	 burnfile = argv[i] + 9;
+
+/* Output file for burn streaks */
+      } else if(strncmp(argv[i], "out=", 4) == 0) {	/* out=fname */
+	 burnfile = argv[i] + 4;
+
+/* Input file for previous burn persistence streaks */
+      } else if(strncmp(argv[i], "trailin=", 8) == 0) {	/* trailin=fname */
+	 persistfile = argv[i] + 8;
+
+/* Input file for previous burn persistence streaks */
+      } else if(strncmp(argv[i], "in=", 3) == 0) {	/* in=fname */
+	 persistfile = argv[i] + 3;
+
+/* Output file for PSF gallery */
+      } else if(strncmp(argv[i], "psf=", 4) == 0) {	/* psf=fname */
+	 psffile = argv[i] + 4;
+
+/* Output file for PSF stats on each cell */
+      } else if(strncmp(argv[i], "psfstat=", 8) == 0) {	/* psfstat=fname */
+	 psfstatfile = argv[i] + 8;
+
+/* How many cells to average PSF stats over? (2^N) */
+      } else if(strncmp(argv[i], "psfavg=", 7) == 0) {	/* psfavg=N */
+	 if(sscanf(argv[i]+7, "%d", &psfavg) != 1) {
+	    fprintf(stderr, "\rerror: cannot get psf avg from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* How big a box to use for PSF extraction? */
+      } else if(strncmp(argv[i], "psfsize=", 8) == 0) {	/* psfsize=size */
+	 if(sscanf(argv[i]+8, "%d", &psfsize) != 1) {
+	    fprintf(stderr, "\rerror: cannot get psf size from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* How big a box to use for PSF extraction? */
+      } else if(strncmp(argv[i], "psfctr=", 7) == 0) {	/* psfsize=size */
+	 if(sscanf(argv[i]+7, "%d", &PSF_CTR_TOL) != 1) {
+	    fprintf(stderr, "\rerror: cannot get psf decenter from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* How big must a box be to qualify for PSF extraction? */
+      } else if(strncmp(argv[i], "psfmin=", 7) == 0) {	/* psfmin=size */
+	 if(sscanf(argv[i]+7, "%d", &MIN_PSF_SIZE) != 1) {
+	    fprintf(stderr, "\rerror: cannot get psf size from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* How big must a box be to qualify for PSF extraction? */
+      } else if(strncmp(argv[i], "psfmaxn=", 8) == 0) {	/* psfmaxn=N */
+	 if(sscanf(argv[i]+8, "%d", &MAX_PSF_PER_CELL) != 1) {
+	    fprintf(stderr, "\rerror: cannot get psf limit from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* Thresholds */
+      } else if(strncmp(argv[i], "thrburn=", 8) == 0) {	/* thrburn=thresh */
+	 if(sscanf(argv[i]+8, "%d", &BURN_THRESH) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+      } else if(strncmp(argv[i], "thrtrail=", 9) == 0) {/* thrtrail=thresh */
+	 if(sscanf(argv[i]+9, "%d", &TRAIL_THRESH) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+      } else if(strncmp(argv[i], "thrmax=", 7) == 0) {	/* thrmax=thresh */
+	 if(sscanf(argv[i]+7, "%d", &MAX_THRESH) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+      } else if(strncmp(argv[i], "thrstar=", 8) == 0) {	/* thrstar=thresh */
+	 if(sscanf(argv[i]+8, "%d", &STAR_THRESH) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+      } else if(strncmp(argv[i], "thrpsf=", 7) == 0) {	/* thrpsf=thresh */
+	 if(sscanf(argv[i]+7, "%d", &PSF_THRESH) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* Star skirt fraction */
+      } else if(strncmp(argv[i], "fracstar=", 9) == 0) {/* fracstar=skirt */
+	 if(sscanf(argv[i]+9, "%lf", &STAR_FRAC) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* Mask growth fraction in diameter */
+///* Mask growth fraction in x direction */
+//      } else if(strncmp(argv[i], "xmask=", 6) == 0) {	/* xmask=factor */
+//	 if(sscanf(argv[i]+6, "%lf", &XMASK_GROW) != 1) {
+      } else if(strncmp(argv[i], "rmask=", 6) == 0) {	/* rmask=factor */
+	 if(sscanf(argv[i]+6, "%lf", &RMASK_GROW) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+///* Mask growth fraction in y direction */
+//      } else if(strncmp(argv[i], "ymask=", 6) == 0) {	/* ymask=factor */
+//	 if(sscanf(argv[i]+6, "%lf", &YMASK_GROW) != 1) {
+/* Mask growth fraction in box size */
+      } else if(strncmp(argv[i], "bmask=", 6) == 0) {	/* bmask=factor */
+	 if(sscanf(argv[i]+6, "%lf", &BMASK_GROW) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* Concatenated FITS? */
+      } else if(strncmp(argv[i], "psf3dfits=", 10) == 0) {/* concat FITS? */
+	 CONCAT_FITS = argv[i][10] == 'n' || argv[i][10] == '0' || 
+	    argv[i][10] == 'f';
+
+/* Quiet? */
+      } else if(strncmp(argv[i], "quiet=", 6) == 0) {	/* quiet={t|f} */
+	 if(argv[i][6] == 'y' || argv[i][6] == '1' || argv[i][6] == 't') {
+	    VERBOSE = 0;
+	 } else {
+	    VERBOSE = 1;
+	 }
+
+/* Verbosity level? */
+      } else if(strncmp(argv[i], "verbose=", 8) == 0) {	/* verbose=N */
+	 if(sscanf(argv[i]+8, "%i", &VERBOSE) != 1) {
+	    fprintf(stderr, "\rerror: cannot get value from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+      } else if(strncmp(argv[i], "help", 4) == 0) {	/* help output */
+	 syntax(argv[0]);
+	 exit(EXIT_SUCCESS);
+
+      } else {
+	 fprintf(stderr, "\rerror: unrecognized option `%s'\n", argv[i]);
+	 syntax(argv[0]);
+	 exit(EXIT_FAILURE);
+      }
+   }
+
+   if(restore && persistfile == NULL) {
+      fprintf(stderr, "\rerror: must specify an input file for restore\n");
+      exit(EXIT_FAILURE);
+   }
+
+/* Inititialize cell structure */
+   for(cell=0; cell<MAXCELL; cell++) {
+      OTA[cell].cell = cell;
+      OTA[cell].nburn = OTA[cell].nstar = OTA[cell].npersist = 0;
+      OTA[cell].bias = OTA[cell].sky = OTA[cell].rms = OTA[cell].time = 0;
+   }
+
+/* Read the persistence data for this OTA */
+   if(persistfile != NULL) {
+      if(persist_read(OTA, persistfile)) exit(EXIT_FAILURE);
+   }
+
+/* Which OTA is this??? */
+   if(fh_get_str(ihu, "FPPOS", otaposn, sizeof(otaposn)) != FH_SUCCESS || 
+      strlen(otaposn) != 4) {
+      fprintf(stderr, "logonly: unrecognized fppos\n");
+      otanum = -1;
+
+   } else {
+      otanum = (otaposn[2] - '0') + 8*(otaposn[3] - '0');
+   }
+
+/* Look at all the MEF's extensions */
+   for (ext = 1; ext <= nextend; ext++) {
+      int naxis, naxis1, naxis2, naxis3;
+      int prescan1, ovrscan1, ovrscan2, pontime;
+      double bzero_d;
+      char xtension[FH_MAX_STRLEN + 1];
+
+      if (!(ehu = fh_ehu(ihu, ext)) || 
+	  fh_get_str(ehu, "EXTNAME", extname, sizeof(extname)) != FH_SUCCESS) {
+	 fprintf(stderr,
+                 "\rerror: Cannot read EXTNAME from `%s' for extension #%d\n",
+                 ifilename, ext);
+         exit(EXIT_FAILURE);
+      }
+      if(fh_get_str(ehu, "XTENSION", xtension, sizeof(xtension)) != FH_SUCCESS) {
+	 fprintf(stderr,
+		 "\rerror: Cannot read XTENSION from `%s' for extension #%d\n",
+		 ifilename, ext);
+	 exit(EXIT_FAILURE);	 
+      }
+      if(!strcmp("TABLE", xtension)) {
+	 if(VERBOSE > 0) {
+	    fprintf(stderr,
+		    "logonly: burntool skipping table extension %s\n", extname); 
+	 }
+	 continue;
+      }
+      if ((extname[0] != 'x' || extname[1] != 'y') &&
+          (extname[0] != 'x' || extname[2] != 'y')) {
+         fprintf(stderr,
+                 "warning: Skipping non-image extension %s\n", extname);
+/*
+ * %%% When reading from a pipe, does the data still need
+ * to get read in?
+ */
+         continue;
+      }
+      cellcode = -1;
+      sscanf(extname+2, "%d", &cellcode);
+      cell = (cellcode / 10) + 8*(cellcode % 10);
+      if(cell < 0 || cell > MAXCELL-1) {
+         fprintf(stderr,
+                 "\rerror: Illegal cell number %d from '%s'\n", cell, extname);
+	 exit(EXIT_FAILURE);
+      }
+
+      if((cellxy >= 0 && cellcode != cellxy) || !cellmask[cell]) {
+	 if(VERBOSE > 0) {
+	    fprintf(stderr,
+		    "logonly: Skipping non-requested extension %s\n", extname);
+	 }
+	 continue;
+      }
+
+/* Get PONTIME as a counter for any burn's persistence */
+      if(fh_get_int(ehu, "PONTIME", &pontime) != FH_SUCCESS) {
+	 fprintf(stderr, "logonly: cannot read PONTIME\n");
+      }
+      OTA[cell].time = pontime;
+
+      naxis3 = 1;
+      if (fh_get_PRESCAN1(ehu, &prescan1) != FH_SUCCESS ||
+	  fh_get_OVRSCAN1(ehu, &ovrscan1) != FH_SUCCESS ||
+	  fh_get_OVRSCAN2(ehu, &ovrscan2) != FH_SUCCESS ||
+	  fh_get_NAXIS(ehu, &naxis) != FH_SUCCESS ||
+          fh_get_NAXIS1(ehu, &naxis1) != FH_SUCCESS ||
+          fh_get_NAXIS2(ehu, &naxis2) != FH_SUCCESS ||
+          (naxis >= 3 && fh_get_NAXIS3(ehu, &naxis3) != FH_SUCCESS)) {
+         fprintf(stderr, "\rerror: Cannot get NAXIS*'\n");
+         exit(EXIT_FAILURE);
+      }
+      if (naxis != 2) {
+
+/* If this extension looks like video, just skip over it
+ * with a little mention that it was ignored and allow all 
+ * of the other extensions to be processed. This will get 
+ * faked out if we ever provide a MEF with a 2-frame video
+ * extension in it, but that should be pretty unlikely. */
+	 if((naxis == 3) && (naxis3 > 2)) {
+	    if(VERBOSE > 0) {
+	       fprintf(stderr, "logonly: burntool skipping 3D, %d frame (video?) extension %s.\n", naxis3, extname);
+	    }
+	    continue;
+	 }
+	 fprintf(stderr, "\rerror: 32bpp support not yet implemented in burntool.\n");
+	 exit(EXIT_FAILURE);
+      }
+/* Check BSCALE and warn if it is anything other than 1.0.
+ * This program does not handle applying a BSCALE, nor
+ * does it handle anything other than 16-bit input at the
+ * moment.  (It is intended only to manipulate raw OTA data. */
+      {
+	 double bscale_d;
+	 if (fh_get_BSCALE(ehu, &bscale_d) == FH_SUCCESS &&
+	     bscale_d != 1.0)
+	 {
+	    fprintf(stderr, "warning: Ignoring BSCALE value of %f!\n", bscale_d);
+	 }
+      }
+/* Trust whatever is in the FITS header for BZERO. */
+      if (fh_get_BZERO(ehu, &bzero_d) == FH_SUCCESS) BZERO = bzero_d;
+
+      buf = (IMTYPE*)malloc(naxis1*naxis2*naxis3*sizeof(short));
+      if (fh_read_padded_image(ehu, fh_file_desc(ehu), buf,
+			       naxis1*naxis2*naxis3*sizeof(short),
+			       FH_TYPESIZE_16) != FH_SUCCESS) {
+	 fprintf(stderr, "\rerror: failed to read image data for extension `%s'.\n",
+		 extname);
+	 free(buf);
+	 exit(EXIT_FAILURE);
+      }
+
+      {
+
+	 nx = naxis1 - ovrscan1;
+	 ny = naxis2 - ovrscan2;
+
+/* Check for space... */
+	 mem_init(nx, ny, naxis1, naxis2);
+
+/* Copy this cell's data */
+	 for(k=0; k<naxis1*naxis2; k++) imbuf[k] = buf[k] + BZERO;
+
+/* Get bias and sky levels */
+	 err = cell_stats(nx, ny, naxis1, naxis2, imbuf, OTA+cell);
+
+/* Does this cell look kosher? */
+	 if(OTA[cell].rms*OTA[cell].rms > 
+	    OTA[cell].sky/MIN_EADU + MAX_READ_NOISE*MAX_READ_NOISE) {
+	    if(VERBOSE > 0) {
+	       fprintf(stderr, "logonly: cell %d is unreasonably noisy, skipping...\n", cell);
+	    }
+	    continue;
+	 }
+
+
+	 if(!restore) {
+
+/* Fix up the burns */
+	    burn_fix(naxis1-ovrscan1, naxis2-ovrscan2, naxis1, naxis2, buf, 
+		     OTA+cell, cell);
+
+/* Collect up a good star list */
+	    if(psffile != NULL || psfstatfile != NULL) {
+	       psf_select(naxis1-ovrscan1, naxis2-ovrscan2, naxis1, 
+			  mbuf, imbuf, OTA[cell].nstar, OTA[cell].star, 
+			  psfsize, OTA[cell].sky+OTA[cell].bias);
+	    }
+
+/* Tell us about it? */
+	    if(VERBOSE & VERB_NORM) burn_blab(OTA+cell);
+
+/* Fix up the streaks */
+	    persist_fix(naxis1-ovrscan1, naxis2-ovrscan2, naxis1, buf, 
+			OTA+cell);
+
+/* Tell us about it? */
+	    if(VERBOSE & VERB_NORM) persist_blab(OTA+cell);
+
+	 } else {
+
+/* Restore the old burns */
+	    burn_restore(naxis1-ovrscan1, naxis2-ovrscan2, naxis1, 
+			 buf, OTA+cell);
+	 }
+
+/* Write the corrected data back to the FITS. */
+	 if(update) {
+	    fh_ehu(ehu, 0);	/* Seek back to the start of data */
+	    if (fh_write_padded_image(ehu, fh_file_desc(ehu), buf,
+				      naxis1*naxis2*naxis3*sizeof(short),
+				      FH_TYPESIZE_16) != FH_SUCCESS) {
+	       fprintf(stderr, "\rerror: failed to re-write image data for extension `%s'.\n",
+		       extname);
+	       free(buf);
+	       exit(EXIT_FAILURE);
+	    }
+	 }
+      }
+
+      free(buf);
+   }
+
+/* Dump out the postage stamp file */
+   if(psffile != NULL) {
+      psf_write(psfsize, psfsize, OTA, otanum, psffile);
+   }
+
+/* Dump out the PSF stats */
+   if(psfstatfile != NULL) {
+      psf_write_stats(psfsize, psfsize, OTA, otanum, psfstatfile, psfavg);
+   }
+
+   fh_destroy(ihu);
+
+/* Write the persistence data for the next image */
+   if(burnfile != NULL) persist_write(OTA, burnfile);
+
+   exit(EXIT_SUCCESS);
+}
+
+/****************************************************************/
+/* mem_init(): Allocate space for various functions */
+STATIC int mem_init(int nx, int ny, int NX, int NY)
+{
+/* Make some space for medians */
+   if(2*SKY_MARG*ny > nmedian_buf) {
+      if(median_buf != NULL) free(median_buf);
+      median_buf = (int *)calloc(2*SKY_MARG*ny, sizeof(int));
+      nmedian_buf = 2*SKY_MARG*ny;
+   }
+
+/* Make some space for cell copy */
+   if(NX*NY > nimbuf) {
+      if(imbuf != NULL) free(imbuf);
+      imbuf = (int *)calloc(NX*NY, sizeof(DTYPE));
+      nimbuf = NX*NY;
+   }
+
+/* Make some space for masks */
+   if(NX*NY > nmbuf) {
+      if(mbuf != NULL) free(mbuf);
+      mbuf = (int *)calloc(NX*NY, sizeof(MTYPE));
+      nmbuf = NX*NY;
+   }
+
+/* Make some space for star veto masks */
+   if(NX*NY > nmsbuf) {
+      if(msbuf != NULL) free(msbuf);
+      msbuf = (int *)calloc(NX*NY, sizeof(MTYPE));
+      nmsbuf = NX*NY;
+   }
+   return(0);
+}
+
+
+#define Q_CLIP 3.0
+/****************************************************************/
+/* cell_stats(): Get bias, sky and noise levels */
+STATIC int cell_stats(int nx, int ny, int NX, int NY, DTYPE *data,
+		      CELL *cell)
+{
+   int i, j, k, n;
+
+/* Get bias stats */
+   if(nx == NX) {
+      cell->bias = 0;
+   } else {
+      for(j=1; j<ny-1; j++) median_buf[j-1] = data[nx+(NX-nx)/2+j*NX];
+      cell->bias = int_median(ny-2, median_buf);
+   }
+
+/* Get sky stats */
+   for(k=n=0; k<nx*ny; k+=((617*nx)/1000)) {
+      i = k % nx;
+      j = k / nx;
+      median_buf[n++] = data[i+NX*j];
+   }
+/* First pass at sky and quartile */
+   cell->sky = int_median(n, median_buf);
+   cell->rms = 1.33*(cell->sky - median_buf[n/4]);
+
+/* Clip at 3 sigma */
+   for(j=0; median_buf[j] < cell->sky - Q_CLIP*cell->rms && j<n/2; j++);
+   for(k=n-1; median_buf[k] > cell->sky + Q_CLIP*cell->rms && k>n/2; k--);
+//   printf("%5d %5d %5d %5d %5d", cell->sky, cell->rms, n, j, k);
+   cell->sky = median_buf[(j+k)/2];
+   cell->rms = 1.33 * (cell->sky - median_buf[(3*j+k)/4]);
+//   printf("%5d %5d\n", cell->sky, cell->rms);
+   cell->sky -= cell->bias;
+
+   return(0);
+}
+
+
+STATIC void syntax(const char *prog)
+{
+   printf("Syntax: %s mef_file [options]\n", prog);
+   printf("   where options include:\n");
+   printf(" xy=xy          Work on just one cell?  xy ID mode.\n");
+   printf(" cell=N         Work on just one cell? Cell count [0:63] mode.\n");
+   printf(" mask=0101...   64 digits to work on cells 0:63.\n");
+   printf(" update={t|f}   Modify the input MEF by subtracting fits?\n");
+   printf(" restore={t|f}  Restore the input MEF by adding input fits?\n");
+   printf(" in=fname       Input file for previous burn persistence streaks\n");
+   printf(" out=fname      Output file for burn streaks\n");
+//   printf(" trailin=fname  Input file for previous burn persistence streaks\n");
+//   printf(" trailout=fname Output file for burn streaks\n");
+   printf(" psf=fname      Output file for PSF FITS stamp gallery\n");
+   printf(" psfstat=fname  Output file for PSF statistics listing\n");
+   printf(" psfavg=N       List PSF statistics averaged over 2^N cells (N=0:3)\n");
+   printf(" psfsize=size   How big a box to use for PSF extraction?\n");
+   printf(" psfmin=size    How big must a box be to use for PSF extraction?\n");
+   printf(" psfmaxn=N      Max number of PSF stars per cell\n");
+   printf(" psfctr=N       Max distance for max centering\n");
+   printf(" psf3dfits={t|f} Write 3D FITS for PSF instead of Concat (default)?\n");
+   printf(" thrburn=X      Threshold for onset of burning\n");
+   printf(" thrtrail=X     Trailing might go this low\n");
+   printf(" thrmax=X       Possibly trailing stars?\n");
+   printf(" thrstar=X      Threshold for star above sky\n");
+   printf(" fracstar=X     Fraction of peak to follow star profile\n");
+   printf(" thrpsf=X       Threshold for a star to be a PSF\n");
+   printf(" rmask=X        Diameter growth factor of burned spots\n");
+   printf(" bmask=X        Box size growth of burn/star boxes\n");
+   printf(" quiet={t|f}    Quiet?\n");
+   printf(" verbose=N      Set verbosity bits:\n");
+   printf("    0x0001         Normal, verbose output\n");
+   printf("    0x0002         Dump detection process\n");
+   printf("    0x0004         Dump out PSF selection process\n");
+   printf("    0x0008         Dump fit progress\n");
+   printf("    0x0010         Dump fit profiles\n");
+   printf("    0x0020         Write Vista marker procedure to /tmp/markem.pro\n");
+   printf("    0x0040         Dump box growth diagnostics\n");
+   printf("    0x0080         Write mask in place of corrected image\n");
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.h	(revision 23490)
@@ -0,0 +1,213 @@
+/* Burn correction routines:
+   -------------------------  
+ *  1. Identify burned spots from saturation threshold
+ ?  2. Identify burns and trails morphologically?
+ ?    2.1 Look for flat-topped stars
+ ?    2.2 Look for asymmetric, smooth, declining trails?
+ ?    2.3 Use y overscan?
+ ?    2.4 Bin in x?
+ *  3. Mask stars and other cruft?
+ *  4. Fit up and down row functions
+ *  5. Read burn time list
+ *  6. Write updated burn time list
+ *  8. Undo subtraction
+    7. Create and save burn correction FITS table
+*/
+/* Algorithm:
+   ----------
+    1. Find new burned spots
+    2. Create new burn entries: x1,x2,y,time=now
+    3. For each burn:
+        if t = now  detrail up
+              else  deburn down
+        if fit negligible  delete burn 
+                     else  save burn fits
+ */
+/* ToDo:
+   -----
+ *  clean up fit start points, esp for persistence
+ *  change burn= and persist= to trailin= and trailout=
+ *  trim edges of fits
+ *  implement MASK_SAT
+ >  test for garbage fits (positive slope, etc)
+ *  test nearly saturated stars for burn.
+ *  undo subtraction (almost perfect -- occasional pixels and baddies)
+ *  star gather into 3D FITS
+ *  test on donuts
+ *  stamp extraction center on box, not max
+ *  Add back nominal bias; output as ushort   
+ *  man page... ongoing...
+ *  Scale uses peak/sum?
+ *  Change psf coords to center; save in header not pixels
+ x  better trail function?  A tuned ln(x+A) is better, but too hard.
+ *  why various restorations imperfect?  edge of cell?
+ *  cell mask argument
+... why the honker star not ID'ed as a burn?  various other gotchas...
+ *  age away old persistence streaks; merge persistence streaks
+ *  PSF info on median psf
+ *  clean up sky/rms calculation with 5*quartile clipping
+ *  change VERBOSE to a bitmask for access to various portions of the code
+ *  add access to a lot of the tuning variables...
+ *  update man page
+    tuning, tuning, tuning...
+    add correction FITS table to MEF
+*/
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define NINT(x) (x<0?(int)((x)-0.5):(int)((x)+0.5))
+#define ABS(a) (((a) > 0) ? (a) : -(a))
+
+// #define STATIC static	/* To make function declarations static */
+#define STATIC			/* To make function declarations global */
+
+#define MAXCELL	64		/* Max cells in an OTA */
+#define MAXSIZE 700		/* Maximum vertical cell size */
+
+#define STAR_RADIUS  4		/* Radius over which a star ctr must be max */
+#define SKY_MARG 3		/* Horiz offset from burn area for sky */
+#define FIT_EDGE 10		/* How far beyond saturation to start fit? */
+#define Y_SCALE 0.01		/* Scale factor for y in fits */
+
+typedef signed short int IMTYPE;/* Data type of image */
+
+typedef int DTYPE;		/* Data type of data copy */
+#define NODATA 0		/* Marker for *No Data */
+
+/* Mask codes: keep in order of severity for psf_select()! */
+typedef int MTYPE;		/* Data type of mask */
+#define MASK_NONE      0	/* Unmasked pixel (MUST be 0) */
+#define MASK_STAR_HALO 1	/* Extended halo box from star */
+#define MASK_SAT_HALO  2	/* Extended halo box from grow_mask() */
+#define MASK_CTR       3	/* Center mask from star_detect() */
+#define MASK_SAT       4	/* Center mask of saturated pixels */
+
+/* Enumeration of function choices */
+#define FUNC_NONE 0		/* No associated function */
+#define BURN_PWR  1		/* Power law */
+#define BURN_EXP  2		/* Exponential */
+#define PSF_STAR  3		/* Unfitted: good psf star */
+
+/* Fit error codes */
+#define FIT_ERROR  1		/* linearfit failed */
+#define FIT_TOP_ERROR  2	/* Saturation extends to top: no points */
+#define FIT_SLOPE_ERROR  3	/* Unreasonable fit */
+
+/* Fit parameters */
+#define FIT_MIN_SLOPE  -5.0	/* minimum slope which is a credible fit */
+#define FIT_MAX_SLOPE   0.0	/* maximum slope which is a credible fit */
+
+/* Verbosity bits */
+#define VISTAMARKER "/tmp/markem.pro"	/* Write Vista pro to mark stars?*/
+#define VERB_NORM     0x0001	/* Normal, verbose output */
+#define VERB_DETECT   0x0002	/* Dump detection process */
+#define VERB_PSFSEL   0x0004	/* Dump out PSF selection process */
+#define VERB_FIT      0x0008	/* Dump fit progress */
+#define VERB_FITPROF  0x0010	/* Dump fit profiles */
+#define VERB_VISTA    0x0020	/* Write vista markers as /tmp/markem.pro */
+#define VERB_BOXGROW  0x0040	/* Dump box growth diagnostics */
+#define VERB_MASK     0x0080	/* Write mask in place of corrected image */
+
+/* Description of a potentially burned trail */
+typedef struct obj_box {
+      int cell;		/* what cell is this one in? */
+      int time;		/* PON time when it was created */
+      int sx;		/* left corner */
+      int sy;		/* bottom corner */
+      int ex;		/* right corner */
+      int ey;		/* top corner */
+      int cx;		/* center x (position of max) */
+      int cy;		/* center y (position of max) */
+      int max;		/* max data value (above sky) */
+      int y0m;		/* min y value at sx */
+      int y0p;		/* max y value at sx */
+      int y1m;		/* min y value at ex */
+      int y1p;		/* max y value at ex */
+      int x0m;		/* min x value at sy */
+      int x0p;		/* max x value at sy */
+      int x1m;		/* min x value at ey */
+      int x1p;		/* max x value at ey */
+      int sat;		/* saturated (i.e. bigger than BURNTHRESH)? */
+      int func;		/* what are we going to do about it? */
+      int diff;		/* median diff of up minus down (sum for stars) */
+      int up;		/* does it trail up or down? (stamp sx for stars) */
+      int y0;		/* y origin for the fit (stamp sy for stars) */
+      int burned;	/* do we think it's left a burn trail? */
+      int fiterr;	/* error fitting the trail? */
+      int sxfit;	/* starting column for fits */
+      int exfit;	/* ending column for fits */
+      int nfit;		/* how many columns were corrected? */
+      IMTYPE *stamp;	/* postage stamp of this object */
+      int *xfit;	/* x of each value of the start of correction */
+      int *yfit;	/* y value of the start of correction */
+      double slope;	/* slope of fit (stamp sum/max) */
+      double *zero;	/* zero of fit for each of the columns */
+} OBJBOX;
+
+/* Info for an entire cell */
+typedef struct cell_info {
+      int cell;			/* Cell number */
+      int bias;			/* Bias level */
+      int sky;			/* Sky level */
+      int rms;			/* RMS in the sky */
+      int time;			/* PON time of this cell */
+      int nburn;		/* Number of trails left by sat stars */
+      OBJBOX *burn;		/* Stars which we think left a trail */
+      int npersist;		/* Number of old persistence streaks */
+      OBJBOX *persist;		/* Persistent streaks */
+      int nstar;		/* Number of stars */
+      OBJBOX *star;		/* Stars, harmless we think */
+} CELL;
+
+/* Prototypes */
+STATIC int mem_init(int nx, int ny, int NX, int NY);
+STATIC int burn_fix(int nx, int ny, int stride, int NY, IMTYPE *buf, 
+		    CELL *cell, int cellnum);
+STATIC int burn_test(int nx, int ny, int NX, DTYPE *data, int rms,
+		     MTYPE *mask, OBJBOX *box);
+STATIC int burn_restore(int nx, int ny, int NX, IMTYPE *buf, CELL *cell);
+STATIC int persist_read(CELL *cell, const char *infile);
+STATIC int persist_write(CELL *cell, const char *outfile);
+STATIC int persist_fix(int nx, int ny, int stride, IMTYPE *buf, CELL *cell);
+STATIC int persist_merge(CELL *cell);
+
+STATIC int star_detect(int nx, int ny, int NX, int NY, DTYPE *data,
+		       MTYPE *mask, MTYPE *veto, CELL *cell, int cellnum);
+STATIC int burn_check(int nx, int ny, int stride, int NY, DTYPE *buf,
+		       MTYPE *mask, CELL *cell);
+
+STATIC int cell_stats(int nx, int ny, int NX, int NY, DTYPE *data, CELL *cell);
+STATIC int burn_blab(CELL *cell);
+STATIC int persist_blab(CELL *cell);
+STATIC int vista_marker(CELL *cell, char *fname);
+
+STATIC int fit_trail(int nx, int ny, int NX, DTYPE *data, MTYPE *mask, 
+		    OBJBOX *box, int up, int sky, int rms, int fitfunc);
+STATIC int sub_fit(int nx, int ny, int NX, IMTYPE *buf, OBJBOX *box, int sign);
+
+STATIC int psf_select(int nx, int ny, int NX, MTYPE *mask, DTYPE *buf,
+		      int nbox, OBJBOX *box, int size, int sky);
+STATIC int psf_write(int nx, int ny, CELL *OTA, int otanum, const char *psffile);
+STATIC int psf_write_stats(int nx, int ny, CELL *OTA, int otanum, const char *statfile, int psfavg);
+STATIC int psf_stats(int nx, int ny, IMTYPE *data, int bias, 
+		     double *fwhm, double *q);
+
+STATIC int grow_box(int nx, int ny, int NX, DTYPE *data, int thr, OBJBOX *box);
+STATIC int grow_mask(int nx, int ny, int NX, DTYPE *mask, double xfac, 
+		     double yfac, int maskval, int nbox, OBJBOX *box);
+STATIC int local_max(int i, int j, int r, int nx, int ny, int NX, DTYPE *data);
+
+STATIC int wlinearfit(int npt, double *x, double *y, 
+		      double *w, double *a, double *b);
+STATIC int int_median(int n, int *key);
+STATIC double double_median(int n, double *key);
+
+STATIC int qsort_int(int n, int *key);
+STATIC double qsort_dbl(int n, double *key);
+
+STATIC void syntax(const char *prog);
+
+int write_2dfits(int nx, int ny, int sx, int sy, IMTYPE *data, int fd);
+int write_3dhdr(int nx, int ny, int nz, int ncmt, char *cmt[], int fd);
+int write_2ddata(int nx, int ny, int *ntot, IMTYPE *data, int fd);
+int write_3dend(int *ntot, int fd);
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnutils.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnutils.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/burnutils.c	(revision 23490)
@@ -0,0 +1,290 @@
+/* burnutils.c - various utility functions */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "math.h"
+
+#include "burntool.h"
+#include "burnparams.h"
+
+/****************************************************************/
+/* Slide out the walls of a box until they fall below thresh; bottom fixed */
+STATIC int grow_box(int nx, int ny, int NX, DTYPE *data, int thr, OBJBOX *box)
+{
+   int i, j, is, ie, left, right;
+
+   left = right = 1;
+
+   if(VERBOSE & VERB_BOXGROW) {
+      printf("box: %d %d %d %d\n", box->sx, box->sy, box->ex, box->ey);
+   }
+
+   do {
+/* Push the right wall until it's clear */
+      if(right) {
+	 for(i=box->ex+1; i<nx; i++) {
+	    for(j=box->sy; j<=box->ey; j++) if(data[i+j*NX] >= thr) break;
+	    if(j > box->ey) break;
+	    if(VERBOSE & VERB_BOXGROW) {
+	       printf("right: %8d %8d\n", i, j);
+	    }
+	 }
+	 box->ex = i - 1;
+	 right = 0;
+      }
+
+/* Push the left wall until it's clear */
+      if(left) {
+	 for(i=box->sx-1; i>=0; i--) {
+	    for(j=box->sy; j<=box->ey; j++) if(data[i+j*NX] >= thr) break;
+	    if(j > box->ey) break;
+	    if(VERBOSE & VERB_BOXGROW) {
+	       printf("left: %8d %8d\n", i, j);
+	    }
+	 }
+	 box->sx = i + 1;
+	 left = 0;
+      }
+
+/* Push the top wall until it's clear, catching corners! */
+      is = MAX(0, box->sx-1);
+      ie = MIN(nx-1, box->ex+1);
+      for(j=box->ey+1; j<ny; j++) {
+	 for(i=is; i<=ie; i++) if(data[i+j*NX] >= thr) break;
+	 if(i == is && box->sx>0) left = 1;	/* Need to redo left */
+	 if(data[ie+j*NX] >= thr && box->ex<nx-1) right = 1;  /* Redo right */
+	 if(i > ie) break;			/* All clear */
+	 if(VERBOSE & VERB_BOXGROW) {
+	    printf("top: %8d %8d\n", i, j);
+	 }
+      }
+      box->ey = j - 1;
+
+/* Push the bottom wall until it's clear, catching corners! */
+      is = MAX(0,box->sx-1);
+      ie = MIN(nx-1,box->ex+1);
+      for(j=box->sy-1; j>=0; j--) {
+	 for(i=is; i<=ie; i++) if(data[i+j*NX] >= thr) break;
+	 if(i == is && box->sx>0) left = 1;	/* Need to redo left */
+	 if(data[is+1+j*NX] >= thr) box->y0m = j;
+	 if(data[ie+j*NX] >= thr && box->ex<nx-1) right = 1;  /* Redo right */
+	 if(data[ie-1+j*NX] >= thr) box->y1m = j;
+	 if(i > ie) break;			/* All clear */
+	 if(VERBOSE & VERB_BOXGROW) {
+	    printf("bottom: %8d %8d %8d %8d\n", i, j, box->y0m, box->y1m);
+	 }
+      }
+      box->sy = j + 1;
+
+      if(left) box->sx -= 1;
+      if(right) box->ex += 1;
+
+   } while(left || right);
+
+/* Find the side saturation points */
+   for(j=box->sy; j<box->ey; j++) if(data[box->sx+j*NX] >= thr) break;
+   box->y0m = j;
+
+   for(j=box->ey; j>box->sy; j--) if(data[box->sx+j*NX] >= thr) break;
+   box->y0p = j;
+
+   for(j=box->sy; j<box->ey; j++) if(data[box->ex+j*NX] >= thr) break;
+   box->y1m = j;
+
+   for(j=box->ey; j>box->sy; j--) if(data[box->ex+j*NX] >= thr) break;
+   box->y1p = j;
+
+   for(i=box->sx; i<box->ex; i++) if(data[i+box->ey*NX] >= thr) break;
+   box->x1m = i;
+
+   for(i=box->ex; i>box->sx; i--) if(data[i+box->ey*NX] >= thr) break;
+   box->x1p = i;
+
+   for(i=box->sx; i<box->ex; i++) if(data[i+box->sy*NX] >= thr) break;
+   box->x0m = i;
+
+   for(i=box->ex; i>box->sx; i--) if(data[i+box->sy*NX] >= thr) break;
+   box->x0p = i;
+
+   if(VERBOSE & VERB_BOXGROW) {
+      printf("box: %d %d %d %d\n", box->sx, box->sy, box->ex, box->ey);
+   }
+
+   return(0);
+}
+
+/****************************************************************/
+/* Expand the mask by pushing out boxes by a factor */
+STATIC int grow_mask(int nx, int ny, int NX, DTYPE *mask, double bfac, 
+		     double rfac, int maskval, int nbox, OBJBOX *box)
+{
+   int i, j, k, x0, y0, db, dr, r2, i0, i1, j0, j1;
+
+   for(k=0; k<nbox; k++) {
+/* Push out the box by a distance bfac */
+      db = NINT(bfac);
+      j0 = MAX(0, box[k].sy-db);
+      j1 = MIN(ny-1, box[k].ey+db);
+      i0 = MAX(0, box[k].sx-db);
+      i1 = MIN(nx-1, box[k].ex+db);
+
+      for(j=j0; j<=j1; j++) {
+	 for(i=i0+1; i<i1; i++) {
+	    if(mask[i+j*NX] == MASK_NONE) mask[i+j*NX] = maskval;
+	    if(mask[i+j*NX] == MASK_NONE) mask[i+j*NX] = maskval;
+	 }
+      }
+
+/* Push out the center to a diameter rfac*xsize */
+      x0 = (box[k].sx + box[k].ex + 1) / 2;
+      y0 = (box[k].y0p + box[k].y1p + box[k].y0m + box[k].y1m + 2) / 4;
+      dr = NINT((box[k].ex - box[k].sx + 1) * 0.5 * rfac);
+      for(j=MAX(0,y0-dr); j<=MIN(ny-1, y0+dr); j++) {
+	 for(i=MAX(0,x0-dr); i<=MIN(nx-1, x0+dr); i++) {
+	    r2 = (i-x0)*(i-x0) + (j-y0)*(j-y0);
+	    if(r2 < dr*dr && mask[i+j*NX] == MASK_NONE)
+	       mask[i+j*NX] = maskval;
+	 }
+      }
+   }
+   return(0);
+}
+
+#if 0
+/****************************************************************/
+/* Expand the mask by pushing out boxes by a factor */
+STATIC int grow_mask(int nx, int ny, int NX, DTYPE *mask, 
+		     double xfac, double yfac, int nbox, OBJBOX *box)
+{
+   int i, j, k, x0, y0, dx, dy;
+
+   for(k=0; k<nbox; k++) {
+      x0 = (box[k].sx + box[k].ex + 1) / 2;
+      y0 = (box[k].sy + box[k].ey + 1) / 2;
+      dx = NINT((box[k].ex - box[k].sx + 1) * 0.5 * xfac);
+      dy = NINT((box[k].ey - box[k].sy + 1) * 0.5 * yfac);
+      for(j=MAX(0,y0-dy); j<MIN(ny, y0+dy); j++) {
+	 for(i=MAX(0,x0-dx); i<MIN(nx, x0+dx); i++) {
+	    if(mask[i+j*NX] == MASK_NONE) mask[i+j*NX] = MASK_HALO;
+	 }
+      }
+   }
+   return(0);
+}
+#endif
+
+/****************************************************************/
+/* Test to see whether a spot is a not-so-local maximum */
+STATIC int local_max(int i, int j, int r, int nx, int ny, int NX, DTYPE *data)
+{
+   int k, l;
+   if(i < r || i > nx-1-r || j < r || j > ny-1-r) return(0);
+   if(data[i+j*NX] <= data[i+1+j*NX] || 
+      data[i+j*NX] <  data[i-1+j*NX] ||
+      data[i+j*NX] <= data[i+(j+1)*NX] ||
+      data[i+j*NX] <  data[i+(j-1)*NX]) return(0);
+   for(l=-r; l<=r; l++) {
+      for(k=-r; k<=r; k++) {
+	 if(data[i+j*NX] < data[i+k+(j+l)*NX]) return(0);
+      }
+   }
+   return(1);
+}
+
+#ifndef INSERT_MEDIAN	/* Faster quick sort */
+/****************************************************************/
+STATIC int int_median(int n, int *key)
+{
+   if(n == 0) return(0);
+   qsort_int(n, key);
+   return((key[n/2]+key[(n-1)/2]) / 2);
+}
+
+/****************************************************************/
+STATIC double double_median(int n, double *key)
+{
+   if(n == 0) return(0.0);
+   qsort_dbl(n, key);
+   return( 0.5*(key[n/2]+key[(n-1)/2]) );
+}
+
+#else	/* Slower sort by insertion */
+/****************************************************************/
+STATIC int int_median(int n, int *key)
+{
+   int i, j, k;
+   int tmp;
+
+   if(n == 0) return(0);
+   for(j=n-2; j>=0; j--) {
+      for(i=j+1, k=j; i<n; i++) {
+	 if(key[j] <= key[i]) break;
+	 k = i;
+      }
+      if(k == j) continue;
+      tmp = key[j];
+      for(i=j+1; i<=k; i++) {
+	 key[i-1] = key[i];
+      }
+      key[k] = tmp;
+   }
+   i = (key[n/2]+key[(n-1)/2]) / 2;
+   return(i);
+}
+
+/****************************************************************/
+STATIC double double_median(int n, double *key)
+{
+   int i, j, k;
+   double tmp;
+
+   if(n == 0) return(0.0);
+   for(j=n-2; j>=0; j--) {
+      for(i=j+1, k=j; i<n; i++) {
+	 if(key[j] <= key[i]) break;
+	 k = i;
+      }
+      if(k == j) continue;
+      tmp = key[j];
+      for(i=j+1; i<=k; i++) {
+	 key[i-1] = key[i];
+      }
+      key[k] = tmp;
+   }
+   return( 0.5*(key[n/2]+key[(n-1)/2]) );
+}
+#endif
+
+/****************************************************************/
+/* Fit y = ax + b */
+STATIC int wlinearfit(int npt, double *x, double *y, double *w, 
+		      double *a, double *b)
+{
+   int i;
+   double v0=0.0, v1=0.0, m00=0.0, m01=0.0, m11=0.0, det;
+
+/* Accumulate sums for least squares fit */
+   for(i=0; i<npt; i++) {
+      v0 += y[i] * w[i];
+      v1 += y[i] * x[i] * w[i];
+      m00 += w[i];
+      m01 += x[i] * w[i];
+      m11 += x[i] * x[i] * w[i];
+   }
+
+/* And solve the matrix */
+   det = m00 * m11 - m01 * m01;
+   if(det == 0.0) {
+      *a = *b = 0.0;
+      return(-1);
+   }
+   *b = (v0*m11-v1*m01) / det;
+   *a = (v1*m00-v0*m01) / det;
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/cheapfits.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/cheapfits.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/cheapfits.c	(revision 23490)
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#define BZERO 32768
+#define NFITS 2880
+typedef signed short int IMTYPE;	/* Data type of image */
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+char fitsbuf[NFITS];
+static int _ENDIAN_TEST = 1;
+#define LOWENDIAN() (*(char*)&_ENDIAN_TEST)
+
+void swab(const void *from, void *to, ssize_t n);
+
+/****************************************************************/
+/* write_2dfits() writes a single 2D FITS file */
+int write_2dfits(int nx, int ny, int sx, int sy, IMTYPE *data, int fd)
+{
+   int i, n;
+   for(n=0; n<NFITS; n++) fitsbuf[n] = ' ';
+   n = 0;
+   sprintf(fitsbuf+80*n++, "%-8s= %20s", "SIMPLE", "T");
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "BITPIX", 16);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "NAXIS", 2);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "NAXIS1", nx);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "NAXIS2", ny);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "CNPIX1", sx);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "CNPIX2", sy);
+   sprintf(fitsbuf+80*n++, "%-8s= %20.1f", "BSCALE", 1.0);
+   sprintf(fitsbuf+80*n++, "%-8s= %20.1f", "BZERO", (double)BZERO);
+   sprintf(fitsbuf+80*n++, "%-8s",       "END");
+   for(n=0; n<NFITS; n++) if(fitsbuf[n]=='\0') fitsbuf[n] = ' ';
+   if(write(fd, fitsbuf, NFITS) < 0) return(-1);
+   for(i=0; i<nx*ny; i+=NFITS/sizeof(IMTYPE)) {
+      n = MIN(NFITS, (nx*ny-i) * sizeof(IMTYPE));
+      if(LOWENDIAN()) swab(data+i, fitsbuf, n);
+      else            memcpy(fitsbuf, data+i, n);
+      if(n < NFITS) bzero(fitsbuf+n, NFITS-n);
+      if(write(fd, fitsbuf, NFITS) < 0) return(-1);
+   }
+   return(0);
+}
+
+/****************************************************************/
+/* write_3dhdr() writes a bare 3D FITS header */
+int write_3dhdr(int nx, int ny, int nz, int ncmt, char *cmt[], int fd)
+{
+   int i, n;
+   for(n=0; n<NFITS; n++) fitsbuf[n] = ' ';
+   n = 0;
+   sprintf(fitsbuf+80*n++, "%-8s= %20s", "SIMPLE", "T");
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "BITPIX", 16);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "NAXIS", 3);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "NAXIS1", nx);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "NAXIS2", ny);
+   sprintf(fitsbuf+80*n++, "%-8s= %20d", "NAXIS3", nz);
+   sprintf(fitsbuf+80*n++, "%-8s= %20.1f", "BSCALE", 1.0);
+   sprintf(fitsbuf+80*n++, "%-8s= %20.1f", "BZERO", (double)BZERO);
+   for(i=0; i<ncmt; i++) sprintf(fitsbuf+80*n++, "COMMENT %s", cmt[i]);
+   sprintf(fitsbuf+80*n++, "%-8s",       "END");
+   for(n=0; n<NFITS; n++) if(fitsbuf[n]=='\0') fitsbuf[n] = ' ';
+   if(write(fd, fitsbuf, NFITS) < 0) return(-1);
+   return(0);
+}
+
+/****************************************************************/
+/* write_2ddata() writes a single data chunk as part of a 3D fits file */
+int write_2ddata(int nx, int ny, int *ntot, IMTYPE *data, int fd)
+{
+   int i, n=0;
+   for(i=0; i<nx*ny; i+=NFITS/sizeof(IMTYPE)) {
+      n = MIN(NFITS, (nx*ny-i) * sizeof(IMTYPE));
+      if(LOWENDIAN()) swab(data+i, fitsbuf, n);
+      else            memcpy(fitsbuf, data+i, n);
+      if(write(fd, fitsbuf, n) < 0) return(-1);
+   }
+   *ntot = *ntot + n;
+   return(0);
+}
+
+/****************************************************************/
+/* write_3dend() writes a single data chunk as part of a 3D fits file */
+int write_3dend(int *ntot, int fd)
+{
+   if((*ntot%NFITS) != 0) {
+      bzero(fitsbuf, NFITS-(*ntot%NFITS));
+      if(write(fd, fitsbuf, NFITS-(*ntot%NFITS)) < 0) return(-1);
+   }
+
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/fitstable.spec
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/fitstable.spec	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/fitstable.spec	(revision 23490)
@@ -0,0 +1,64 @@
+We need two FITS tables to describe the burn corrections.  Each
+correction area is basically a rectangle within a cell and there are a
+bunch of parameters which describe the size and other properties of
+the rectangle.
+
+Then, for each column in each rectangle there are three parameters
+which describe the burn fit: the start x,y and one fit parameter (the
+amplitude; all fits share the same shape).  The rows in this table
+need to have a pointer back to the first table of generic rectangle info.
+
+There is also data calculated for each cell: bias, sky, and
+background, which are probably not worth keeping.
+
+The persist_read() routine reads the tabulated quantities and stuffs
+them into an array of OBJBOX structures, and these are then copied to
+an array of CELL structures, one for each of the 64 cells, using the
+OBJBOX pointer and count.  The persist_write() routine writes this
+information to a text file.  (The structures are in burntool.h; the
+read/write routines are in persistio.c.)
+
+Here are the entries for the first table, listed as entries in an
+OBJBOX structure:
+
+  int cell;      /* what cell is this one in? */
+  int time;      /* PON time when it was created */
+  int cx;        /* center x (position of max) */
+  int cy;        /* center y (position of max) */
+  int max;       /* max data value (above sky) */
+  int y0;        /* y origin for the fit (stamp sy for stars) */
+  int sx;        /* left corner */
+  int sy;        /* bottom corner */
+  int ex;        /* right corner */
+  int ey;        /* top corner */
+  int y0m;       /* min y value at sx */
+  int y0p;       /* max y value at sx */
+  int y1m;       /* min y value at ex */
+  int y1p;       /* max y value at ex */
+  int x0m;       /* min x value at sy */
+  int x0p;       /* max x value at sy */
+  int x1m;       /* min x value at ey */
+  int x1p;       /* max x value at ey */
+  int func;      /* what are we going to do about it? */
+  int up;        /* does it trail up or down? */
+  int nfit;      /* how many columns were corrected? */
+  int sxfit;     /* starting column for fits */
+  int exfit;     /* ending column for fits */
+  double slope;  /* slope of fit */
+
+Here are the entries in the second table, listed as entries in three
+arrays which are part of the OBJBOX structure.  In addition each entry
+in the second pointer requires a pointer back to its burn rectangle in
+the first table, which can be an integer coding the (cell,cx,cy)
+parameters because they will be unique.
+
+  int objptr;    /* Cell,cx,cy coded as ccxxxyyy */
+  int xfit;	 /* x of each value of the start of correction */
+  int yfit;	 /* y value of the start of correction */
+  double zero;	 /* zero of fit for each of the columns */
+
+The CELL structure only needs to have the following two entries filled
+in for each of the 64 structures in the array describing the entire OTA:
+
+  int npersist;	    /* Number of old persistence streaks */
+  OBJBOX *persist;  /* Persistent streaks */
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/man/burntool.1
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/man/burntool.1	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/man/burntool.1	(revision 23490)
@@ -0,0 +1,250 @@
+.nf
+NAME:
+	burntool - repair saturation trails and burns; extract PSF stamps
+
+SYNOPSIS:
+	burntool MEF_image [options]
+
+DESCRIPTION: 
+	Burntool reads an OTA's MEF, cell by cell, looking for and correcting
+	trails left above saturated stars and persistence burns below stars
+	from previous images.  It rewrites the MEF in place.  In addition,
+	burntool identifies bright stars which are not saturated and can write
+	a concatenated or 3D FITS image of postage stamps and a median of 
+	the scaled star images.  Burntool also writes a table of the fits to
+	trails and persistence burns which can serve as input for the next
+	image to be corrected.
+	
+	Because the profile of saturated stars can be complex, burntool
+	identifies objects by noting when the images passes a threshold
+	(BURN_THRESH, default 30000 ADU) and then pushing out a bounding box
+	which encompasses all adjoining pixels which exceed a lower
+	TRAIL_THRESH (default 10000 ADU).  The pixels comprising the octagon
+	exceeding TRAIL_THRESH on this bounding box are noted, as is the pixel
+	and value of the maximum.
+	
+	In addition, burntool performs the same action on pixels which pass a
+	(much lower) STAR_THRESH above sky (default 1000 ADU) and which are
+	also the local maximum over all pixels within STAR_RADIUS (default 4)
+	distance.  These pixels are boxed down to a fraction STAR_FRAC
+	(default 0.3) of this maximum above sky.
+	
+	Once all objects are boxed, all saturated and non-saturated stars
+	whose maximum exceeds MAX_THRESH (default 20000 ADU) are tested for
+	trailing by comparing the flux beyond the bounding box above and below
+	the star.  Those whose median difference exceeds 0.3 times the rms of
+	the sky are designated as "trailed" and are nominated for a trail fit.
+	
+	The list of boxes is used to create a mask and it is expanded by a
+	factor of RMASK_GROW (default 3.0) in diameter and BMASK_GROW (default
+	5) pixels in the bounding box "burns" and "stars".  This mask is used
+	to veto pixels from participating in fits and is also used to select
+	isolated objects for postage stamps.
+	
+	Burntool also can read an input file which lists burns which may exist
+	because of readout of saturated stares from previous exposures.  This
+	forms the third category of boxes that burntool processes: "burns".
+	
+	Burntool proceeds to fit and remove each trail and burn, by forming a
+	median across the box's width in x to create an average profile in y,
+	fitting this profile either as an exponential or a power law,
+	refitting in each column for an individual scale factor and starting
+	point, and then subtracting the fit.  Upward trails are fitted as
+	power laws; downward burns as exponentials.
+	
+	Burntool finishes by rewriting the modified MEF and all of the fits in
+	an output file ("out=file_name").  If desired, burntool can be run
+	with "restore=t" and this output table as input ("in=file_name") to
+	restore the MEF to its pre-subtraction state.  Burntool can also be
+	inhibited from subtracting the fits by "update=f".
+	
+	The identification of significant (but unsaturated) stars is an
+	important component of burntool's mask generation, and if requested
+	burntool can assemble a gallery of postage stamps of suitable stars.
+	
+	Any star whose maximum exceeds PSF_THRESH above sky but is not deemed
+	to be saturated or trailed can contribute if its box does not overlap
+	the mask (other than its own contribution) or impinge on the edge of
+	the cell.  If the maximum pixel is less than PSF_CTR_TOL (default 8)
+	pixels from the center of its box, the stamp is centered on that
+	pixel; otherwise the stamp is centered on the bounding box. If the box
+	is smaller than MIN_PSF_SIZE (default 3) the star is not used for a
+	stamp.  The maximum number of stars which can be so designated as
+	PSF stars from a single cell is MAX_PSF_PER_CELL (default 20).  The
+	selection proceeds from bottom to top, so the lowest 20 are used.
+	(Note that it is extremely uncommon for any 2.5 arcmin cell to have
+	as many as 20 stars bright enough for PSF consideration.)
+	
+	This gallery is written as a concatenated or 3D FITS file whose name
+	is designated by "psf=file_name" and the size of the stamps is
+	governed by "psfsize=N" (default 32).  The first entry in the 3D FITS
+	file is the median of all the individual stamps, scaled to bring the
+	peak to approximately 10000 ADU.  The stamps all have sky subtracted
+	and an artificial bias of USHORT_BIAS (default 1000) added back in.
+
+	Note that the first two pixels in the individual stamps might be the 
+	OTA coordinates of the origin of the stamp, not flux data.
+
+	If PSF stamp output is requested, burntool will measure statistics
+	of the median PSF image and report a single line on stdout.  The
+	entries in this line are (for example):
+
+	   N= 199	   Number of PSF stars (median means N+1 are written)
+	   PSFmaj= 6.93	   Major axis FWHM [pix] (0.0 if fit fails)
+	   min= 3.96	   Minor axis FWHM [pix] (0.0 if fit fails)
+	   theta= 5.3	   Angle of FWHM from x [deg] (0.0 if fit fails)
+	   m2= 12.11	   Second moment of distribution [pix^2]
+	   q+= 5.577	   Plus quadrupole qxx-qyy [pix^2]
+	   qx= 0.710	   Cross quadrupole 2*qxy [pix^2]
+	   qt= -5.562      Tangential quadrupole [pix^2] 
+				q+ * cos(2*phi) + qx * sin(2*phi)
+
+	The argument "psfstat=file_name" requests burntool to assemble the
+	PSF stamps and calculate statistics on them on a cell-by-cell basis.
+	While noisier than the median PSF for the entire OTA, it provides
+	intra-OTA resolution of PSF changes.  This entries in this file
+	are (for example):
+
+	   ext=xy13        Cell xy ID
+	   bias=7940       Cell bias level [ADU]
+	   sky=206         Cell sky level [ADU]
+	   rmssky=15       Cell sky RMS [ADU]
+	   npsf=3          Number of contributing PSF stars
+	   fwhm=5.38       PSF FWHM [pix] (0.0 if fit fails)
+	   m2=11.08        Second moment of distribution [pix^2] 
+	   qp=5.154        Plus quadrupole qxx-qyy [pix^2]	 
+	   qc=0.560        Cross quadrupole 2*qxy [pix^2]	 
+	   qt=-5.201       Tangential quadrupole [pix^2] 	  
+			   	q+ * cos(2*phi) + qx * sin(2*phi)
+
+	Helpful utilities include:
+
+	  Make a mosaic out of the cells of the MEF
+
+	    fitstile \!o4803g0054o30.mos +0-0:o4803g0054o30.fits
+	    fitstile \!o4881g0049o44.mos -0+0:o4881g0049o44.fits
+
+	  Make a mosaic of the 3D FITS postage stamp file
+
+	    optic_fitstile test54.psf test54.tile
+
+OPTIONS:
+	xy=xy          
+		Work on just one cell?  xy ID mode.
+
+	cell=N         
+		Work on just one cell?  Cell count [0:63] mode.
+
+	mask=0101...
+		64 digits to designate which cells [0:63] to work on.
+
+	update={t|f}   
+		Modify the input MEF by subtracting fits (default t)?
+
+	restore={t|f}  
+		Restore the input MEF by adding input fits (default f)?
+
+	in=fname       
+		Input file for previous burn persistence streaks
+
+	out=fname      
+		Output file for burn streaks
+
+	psf=fname      
+		Output file for PSF gallery of postage stamps
+
+	psfsize=size   
+		How big a box to use for PSF extraction?
+
+	psfmin=size   
+		How big must a box be to use for PSF extraction? (PSF_MIN_SIZE)
+
+	psfctr=N
+		Max distance of peak from box center for peak centering
+		(PSF_CTR_TOL)
+
+	psfmaxn=N   
+		Maximum number of PSF stars allowed per cell (MAX_PSF_PER_CELL)
+
+	psf3dfits={t|f}
+		Write 3D FITS for PSF instead of (default) concatenated FITS?
+
+	psfstat=fname      
+		Output file for PSF statistics listing
+
+	psfavg=N
+		List PSF statistics averaged over 2^N cells (N=0:3)
+
+	thrburn=X      
+		Threshold for onset of burning (BURN_THRESH)
+
+	thrtrail=X     
+		Trailing might result from fluxes this low (TRAIL_THRESH)
+
+	thrmax=X       
+		Stars at this peak level might trail (MAX_THRESH)
+
+	thrstar=X      
+		Threshold above sky for star designation (STAR_THRESH)
+
+	fracstar=X     
+		Fraction of peak to follow star profile (STAR_FRAC)
+
+	thrpsf=X       
+		Threshold above sky for a star to be a PSF (PSF_THRESH)
+
+	rmask=X        
+		Diameter growth factor of burned spots (RMASK_GROW)
+
+	bmask=X        
+		Box size growth of burn/star (BMASK_GROW)
+
+	quiet={t|f}    
+		Quiet?
+
+	verbose=N
+		Set verbosity level bitmask:
+		   0x0001   Normal, verbose output
+		   0x0002   Dump detection process
+		   0x0004   Dump out PSF selection process
+		   0x0008   Dump fit progress
+		   0x0010   Dump fit profiles
+		   0x0020   Write Vista marker procedure to /tmp/markem.pro
+		   0x0040   Dump box growth diagnostics
+		   0x0080   Write mask in place of corrected image
+
+
+EXAMPLES:
+	Normal usage:
+
+		burntool o4803g0054o30.fits out=burn.54
+		burntool o4803g0055o30.fits in=burn.54 out=burn.55
+		burntool o4803g0056o30.fits in=burn.55 out=burn.56
+
+	Normal usage and write a PSF file:
+
+		burntool o4803g0054o30.fits out=burn.54 psf=o4803g0054o30.psf
+
+	Just generate a PSF file but don't change the original:
+
+		burntool o4803g0054o30.fits update=f psf=o4803g0054o30.psf
+
+	Restore the subtracted fits:
+
+		burntool o4803g0055o30.fits in=burn.55 restore=t
+
+	Process an out of focus image to get donut stamps:
+
+		burntool o4881g0049q44.fits update=f thrpsf=1000 rmask=0 \
+		psfsize=128 psf=o4881g0049q44_psf.fits
+
+BUGS:
+	090224: Still in development
+
+SEE ALSO:
+	biastool
+
+AUTHORS:
+	John Tonry
+
+VERSION:
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/persistfix.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/persistfix.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/persistfix.c	(revision 23490)
@@ -0,0 +1,65 @@
+/* persistfix.c - fix up persistence streaks */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "math.h"
+
+#include "burntool.h"
+#include "burnparams.h"
+
+/****************************************************************/
+/* persist_fix(): Repair the persistence trails in a cell */
+/* burn_fix must have been run first! */
+STATIC int persist_fix(int nx, int ny, int NX, IMTYPE *buf, 
+		    CELL *cell)
+{
+   int k, err=0;
+
+/* Merge all overlapping streaks */
+   persist_merge(cell);
+
+/* Fix up all the persistence streaks */
+   for(k=0; k<cell->npersist; k++) {
+
+/* Fit the trail */
+      err = fit_trail(nx, ny, NX, imbuf, mbuf, cell->persist+k, 0, 
+	     cell->sky+cell->bias, cell->rms, BURN_EXP);
+
+/* Subtract out the fit */
+      if(!cell->persist[k].fiterr) 
+	 err = sub_fit(nx, ny, NX, buf, cell->persist+k, 1);
+   }
+
+   return(err);
+}
+
+/****************************************************************/
+/* persist_blab(): Tell us about the persistence trails in a cell */
+STATIC int persist_blab(CELL *cell)
+{
+   int i, k, ymid;
+
+/* The persistent streaks */
+   printf("Persistence streaks:\n");
+   printf("  #    cx  cy  max     sx  sy    ex  ey  midy  F   slope  zero\n");
+
+   for(k=0; k<cell->npersist; k++) {
+      i = (cell->persist[k].ex - cell->persist[k].sx + 1) / 2;
+      ymid = (cell->persist[k].y0m + cell->persist[k].y1m +
+	      cell->persist[k].y0p + cell->persist[k].y1p + 2) / 4;
+      printf("%3d %5d %3d %5d %5d %3d %5d %3d %5d %2d %8.5f %4d\n", 
+	     k, cell->persist[k].cx, cell->persist[k].cy,
+	     cell->persist[k].max, 
+	     cell->persist[k].sx, cell->persist[k].sy, 
+	     cell->persist[k].ex, cell->persist[k].ey, ymid,
+	     cell->persist[k].func, 
+	     cell->persist[k].slope, NINT((cell->persist[k]).zero[i]));
+   }
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c	(revision 23490)
@@ -0,0 +1,291 @@
+/* persistio.c - read and write persistence info */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "math.h"
+
+#include "burntool.h"
+#include "burnparams.h"
+
+/****************************************************************/
+/* persist_read(): Read all the persistence trails from a file */
+STATIC int persist_read(CELL *cell, const char *infile)
+{
+   int i, k, nbox=0;
+   char line[1024];
+   FILE *fp;
+
+/* Initialize the counts */
+   for(k=0; k<MAXCELL; k++) {
+      cell[k].npersist = 0;
+      cell[k].persist = NULL;
+   }
+
+   if(infile == NULL) return(0);
+
+   if( (fp=fopen(infile, "r")) == NULL) {
+      fprintf(stderr, "\rerror: cannot open '%s' for reading\n", infile);
+      return(-1);
+   }
+/* Read in all the burns */
+   nbox = 0;
+   while(fgets(line, 1024, fp) != NULL) {
+      if(line[0] == '#') continue;
+      sscanf(line, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %lf %d %d %d",
+	     &boxbuf[nbox].cell, &boxbuf[nbox].time,
+	     &boxbuf[nbox].cx, &boxbuf[nbox].cy,
+	     &boxbuf[nbox].max, &boxbuf[nbox].y0,
+	     &boxbuf[nbox].sx, &boxbuf[nbox].sy, 
+	     &boxbuf[nbox].ex, &boxbuf[nbox].ey,
+	     &boxbuf[nbox].y0m, &boxbuf[nbox].y0p,
+	     &boxbuf[nbox].y1m, &boxbuf[nbox].y1p,
+	     &boxbuf[nbox].x0m, &boxbuf[nbox].x0p,
+	     &boxbuf[nbox].x1m, &boxbuf[nbox].x1p,
+	     &boxbuf[nbox].func, &boxbuf[nbox].up,
+	     &boxbuf[nbox].slope, &boxbuf[nbox].nfit,
+	     &boxbuf[nbox].sxfit, &boxbuf[nbox].exfit);
+      if(boxbuf[nbox].nfit <= 0) continue;
+      boxbuf[nbox].zero = (double *)calloc(boxbuf[nbox].nfit, sizeof(double));
+      boxbuf[nbox].xfit = (int *)calloc(boxbuf[nbox].nfit, sizeof(int));
+      boxbuf[nbox].yfit = (int *)calloc(boxbuf[nbox].nfit, sizeof(int));
+      for(i=0; i<boxbuf[nbox].nfit; i++) {
+	 if(fgets(line, 1024, fp) == NULL) {
+	    fprintf(stderr, "\rerror: short read of burn lines\n");
+	    return(-1);
+	 }
+	 sscanf(line, "%d %d %lf\n", &boxbuf[nbox].xfit[i], 
+		&boxbuf[nbox].yfit[i], &boxbuf[nbox].zero[i]);
+      }
+      boxbuf[nbox].fiterr = 0;
+/* Augment counts */
+      k = boxbuf[nbox].cell;
+      if(k < 0 || k >= MAXCELL) {
+	 fprintf(stderr, "\rerror: illegal cell %d at %d from '%s'\n", 
+		 k, nbox, line);
+	 fclose(fp);
+	 return(-1);
+      }
+      cell[k].npersist += 1;
+
+      if(++nbox >= MAXBURN) {
+	 fprintf(stderr, "\rerror: persist_read overflowed MAXBURN\n");
+	 fclose(fp);
+	 return(-1);
+      }
+   }
+
+/* Allocate some space for them */
+   for(k=0; k<MAXCELL; k++) {
+      if( (i=cell[k].npersist) > 0) {
+	 cell[k].persist = (OBJBOX *)calloc(i, sizeof(OBJBOX));
+	 cell[k].npersist = 0;
+      }
+   }
+/* Copy the results to the cells */
+   for(i=0; i<nbox; i++) {
+      k = boxbuf[i].cell;
+      memcpy(cell[k].persist+cell[k].npersist, boxbuf+i, sizeof(OBJBOX));
+      cell[k].npersist += 1;
+   }
+
+   fclose(fp);
+   return(0);
+}
+
+
+#define DIFFERENT_STREAK 20	/* Proximity for union versus intersection */
+
+/****************************************************************/
+/* persist_merge(): Disentangle overlapping persistence streaks */
+STATIC int persist_merge(CELL *cell)
+{
+   int i, j, k, n, nbox, xs, xe;
+   int jp, kp;
+   int lapmax;
+   OBJBOX *box;
+   int xusage[MAXSIZE], yctr[MAXSIZE], boxid[MAXSIZE];
+   double zk, zj;
+
+/* Look at all the boxes -- if not isolated then merge or sever */
+   nbox = cell->npersist;
+   box = cell->persist;
+
+/* Assess the clustering of all the streaks */
+   for(i=0; i<MAXSIZE; i++) xusage[i] = 0;
+   for(k=0; k<nbox; k++) {
+      if(box[k].exfit >= MAXSIZE-1) continue;
+      for(i=box[k].sxfit; i<=box[k].exfit; i++) xusage[i] += 1;
+   }
+
+/* Identify clusters */
+   for(xs=0; xs<MAXSIZE-1; xs++) {
+      if(xusage[xs] == 0) continue;
+      for(xe=xs, lapmax=0; xe<MAXSIZE-1; xe++) {
+	 if(xusage[xe+1] == 0) break;
+	 lapmax = MAX(lapmax, xusage[xe]);
+      }
+      if(lapmax == 1) {	/* No overlap?  No problem. */
+	 xs = xe + 1;	/* Hop to next gap */
+	 continue;
+      }
+
+/* Which boxes overlap this cluster? */
+      for(k=n=0; k<nbox; k++) {
+	 if(box[k].sxfit > xe || box[k].exfit < xs) continue;
+	 boxid[n] = k;
+	 yctr[n] = (box[k].y0m+box[k].y1m+box[k].y0p+box[k].y0p+2) / 4;
+	 n++;
+      }
+
+/* Case 1: different y start => sever */
+      for(kp=0; kp<n; kp++) {
+	 k = boxid[kp];
+	 zk = box[k].zero[box[k].nfit/2];
+	 for(jp=kp+1; jp<n; jp++) {
+	    j = boxid[jp];
+	    zj = box[j].zero[box[j].nfit/2];
+	    if(ABS(yctr[jp]-yctr[kp]) > DIFFERENT_STREAK) {
+/* Trim back the feebler streak */
+	       if(zk > zj) {
+		  if(box[j].sxfit >= box[k].sxfit) 
+		     box[j].sxfit = MAX(box[j].sxfit, box[k].exfit+1);
+		  if(box[j].exfit <= box[k].exfit) 
+		     box[j].exfit = MIN(box[j].exfit, box[k].sxfit-1);
+	       } else {
+		  if(box[k].sxfit >= box[j].sxfit) 
+		     box[k].sxfit = MAX(box[k].sxfit, box[j].exfit+1);
+		  if(box[k].exfit <= box[j].exfit) 
+		     box[k].exfit = MIN(box[k].exfit, box[j].sxfit-1);
+	       }
+	    }
+	 }
+      }
+
+/* Case 2: pretty much the same y start => union */
+      for(kp=0; kp<n; kp++) {
+	 k = boxid[kp];
+	 for(jp=kp+1; jp<n; jp++) {
+	    j = boxid[jp];
+	    if(ABS(yctr[jp]-yctr[kp]) <= DIFFERENT_STREAK) {
+/* Merge k into j, trash k from further consideration */
+	       box[j].time = MAX(box[j].time, box[k].time);
+	       box[j].sx = MIN(box[j].sx, box[k].sx);
+	       box[j].ex = MAX(box[j].ex, box[k].ex);
+	       box[j].sy = MIN(box[j].sy, box[k].sy);
+	       box[j].ey = MAX(box[j].ey, box[k].ey);
+	       box[j].y0m = MIN(box[j].y0m, box[k].y0m);
+	       box[j].y0p = MAX(box[j].y0p, box[k].y0p);
+	       box[j].x0m = MIN(box[j].x0m, box[k].x0m);
+	       box[j].x0p = MAX(box[j].x0p, box[k].x0p);
+	       box[j].y1m = MIN(box[j].y1m, box[k].y1m);
+	       box[j].y1p = MAX(box[j].y1p, box[k].y1p);
+	       box[j].x1m = MIN(box[j].x1m, box[k].x1m);
+	       box[j].x1p = MAX(box[j].x1p, box[k].x1p);
+	       box[j].sxfit = MIN(box[j].sxfit, box[k].sxfit);
+	       box[j].exfit = MAX(box[j].exfit, box[k].exfit);
+
+	       box[k].exfit = box[k].sxfit - 1;
+	       yctr[kp] = -2 * DIFFERENT_STREAK;
+	    }
+	 }
+      }
+
+      xs = xe + 1;	/* Hop to next gap */
+
+   } /* Cluster loop */
+
+/* Excise the boxes which have been eradicated (sxfit > exfit) */
+   for(k=0; k<nbox; k++) {
+      if(box[k].sxfit > box[k].exfit) {
+	 for(j=k; j<nbox-1; j++) memcpy(box+j, box+j+1, sizeof(OBJBOX));
+	 nbox--;
+	 k--;
+      }
+   }
+   cell->npersist = nbox;
+
+
+   return(0);
+}
+
+
+/****************************************************************/
+/* persist_write(): Write all the persistence data for the next image */
+STATIC int persist_write(CELL *cell, const char *outfile)
+{
+   int i, k, j, err=0;
+   FILE *fp;
+
+   if(outfile == NULL) return(0);
+   if( (fp=fopen(outfile, "w")) == NULL) {
+      fprintf(stderr, "\rerror: cannot open '%s' for writing\n", outfile);
+      return(-1);
+   }
+
+/* Dump out all the burns for the next image... */
+/* FIXME: what to do about generic cell info? */
+   fprintf(fp,  "# Cell: %d  sky= %d   rms= %d   bias= %d\n", 
+	   cell[0].cell, cell[0].sky, cell[0].rms, cell[0].bias);
+   fprintf(fp, "#Cell time    cx  cy  max   sx  sy   ex  ey  y0m y0p y1m y1p x0m x0p x1m x1p     slope    zero\n");
+
+   for(j=0; j<MAXCELL; j++) {
+/* First: patched up persists */
+      for(k=0; k<cell[j].npersist; k++) {
+	 if(cell[j].persist[k].fiterr) continue;
+	 if(cell[j].persist[k].nfit <= 0) continue;
+	 fprintf(fp, "%3d %7d  %3d %3d %5d %3d  %3d %3d  %3d %3d  %3d %3d %3d %3d %3d %3d %3d %3d  %1d %1d %9.6f %3d %3d %3d\n",
+		 j, cell[j].persist[k].time, 
+		 cell[j].persist[k].cx, cell[j].persist[k].cy, 
+		 cell[j].persist[k].max, cell[j].persist[k].y0,
+		 cell[j].persist[k].sx, cell[j].persist[k].sy, 
+		 cell[j].persist[k].ex, cell[j].persist[k].ey,
+		 cell[j].persist[k].y0m, cell[j].persist[k].y0p,
+		 cell[j].persist[k].y1m, cell[j].persist[k].y1p,
+		 cell[j].persist[k].x0m, cell[j].persist[k].x0p,
+		 cell[j].persist[k].x1m, cell[j].persist[k].x1p,
+		 cell[j].persist[k].func, cell[j].persist[k].up, 
+		 cell[j].persist[k].slope, cell[j].persist[k].nfit,
+		 cell[j].persist[k].sxfit, cell[j].persist[k].exfit);
+	 for(i=0; i<cell[j].persist[k].nfit; i++) {
+	    fprintf(fp, "%3d %3d %8.4f\n", cell[j].persist[k].xfit[i], 
+		    cell[j].persist[k].yfit[i], cell[j].persist[k].zero[i]);
+	 }
+      }
+
+/* Second: new burns */
+      for(k=0; k<cell[j].nburn; k++) {
+	 if(!cell[j].burn[k].burned) continue;
+	 if(cell[j].burn[k].fiterr && 
+	    cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	 if(cell[j].burn[k].nfit <= 0) continue;
+
+	 i = (cell[j].burn[k].ex - cell[j].burn[k].sx + 1) / 2;
+	 fprintf(fp, "%3d %7d  %3d %3d %5d %3d  %3d %3d  %3d %3d  %3d %3d %3d %3d %3d %3d %3d %3d  %1d %1d %9.6f %3d %3d %3d\n", 
+		 j, cell[j].burn[k].time, 
+		 cell[j].burn[k].cx, cell[j].burn[k].cy,
+		 cell[j].burn[k].max, cell[j].burn[k].y0,
+		 cell[j].burn[k].sx, cell[j].burn[k].sy, 
+		 cell[j].burn[k].ex, cell[j].burn[k].ey,
+		 cell[j].burn[k].y0m, cell[j].burn[k].y0p,
+		 cell[j].burn[k].y1m, cell[j].burn[k].y1p,
+		 cell[j].burn[k].x0m, cell[j].burn[k].x0p,
+		 cell[j].burn[k].x1m, cell[j].burn[k].x1p,
+		 cell[j].burn[k].func, cell[j].burn[k].up, 
+		 cell[j].burn[k].slope, cell[j].burn[k].nfit,
+		 cell[j].burn[k].sxfit, cell[j].burn[k].exfit);
+	 for(i=0; i<cell[j].burn[k].nfit; i++) {
+	    fprintf(fp, "%3d %3d %8.4f\n", cell[j].burn[k].xfit[i], 
+		    cell[j].burn[k].yfit[i], cell[j].burn[k].zero[i]);
+	 }
+      }
+   }
+   fclose(fp);
+
+   return(err);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/psfstamp.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/psfstamp.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/psfstamp.c	(revision 23490)
@@ -0,0 +1,374 @@
+/* psfstamp.c - identify and write PSF stars */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "math.h"
+
+#include "burntool.h"
+#include "burnparams.h"
+#include "pscoords/pscoords.h"
+
+#define PIXEL_FWHM 0.68	/* FWHM of one pixel: sqrt(ln(256)/12) */
+
+/****************************************************************/
+/* psf_select(): Choose worthy stars and copy a postage stamp */
+STATIC int psf_select(int nx, int ny, int NX, MTYPE *mask, DTYPE *data,
+		      int nbox, OBJBOX *box, int size, int sky)
+{
+   int i, j, k, sum;
+   int x0, x1, y0, y1, xm, xp, ym, yp;
+
+   for(k=0; k<nbox; k++) {
+      box[k].func = FUNC_NONE;
+
+/* Too small? */
+      if(VERBOSE & VERB_PSFSEL) {
+	 printf("Testing star at %d %d for max, %d\n", 
+		box[k].cx, box[k].cy, box[k].max);
+      }
+      if(box[k].max < PSF_THRESH) continue;
+
+/* If the max is very decentered in the box, choose the box */
+      if(ABS((box[k].sx+box[k].ex+1)/2 - box[k].cx) < PSF_CTR_TOL &&
+	 ABS((box[k].sy+box[k].ey+1)/2 - box[k].cy) < PSF_CTR_TOL) {
+	 x0 = box[k].cx - (size-1)/2;
+	 x1 = box[k].cx + size/2;
+	 y0 = box[k].cy - (size-1)/2;
+	 y1 = box[k].cy + size/2;
+	 box[k].up = box[k].cx;		/* Coopt for box center */
+	 box[k].y0 = box[k].cy;		/* Coopt for box center */
+      } else {
+	 x0 = (box[k].sx+box[k].ex+1)/2 - (size-1)/2;
+	 x1 = (box[k].sx+box[k].ex+1)/2 + size/2;
+	 y0 = (box[k].sy+box[k].ey+1)/2 - (size-1)/2;
+	 y1 = (box[k].sy+box[k].ey+1)/2 + size/2;
+	 box[k].up = (box[k].sx+box[k].ex+1)/2;		/* Coopt */
+	 box[k].y0 = (box[k].sy+box[k].ey+1)/2;		/* Coopt */
+      }
+
+/* Too close to the edge? */
+      if(VERBOSE & VERB_PSFSEL) {
+	 printf("testing for edge %d %d %d %d\n", x0, y0, x1, y1);
+      }
+      if(x0 < 0 || x1 > nx-1 || y0 < 0 || y1 > ny-1) continue;
+
+/* Box too big (blobby, extended crap)? */
+      if(VERBOSE & VERB_PSFSEL) {
+	 printf("testing for too big %d %d > %d ?\n", 
+	      box[k].ex-box[k].sx+1, box[k].ey-box[k].sy+1, size);
+      }
+      if(box[k].ex-box[k].sx+1 > size || 
+	 box[k].ey-box[k].sy+1 > size) continue;
+/* Box too small (CR?)? */
+      if(VERBOSE & VERB_PSFSEL) {
+	 printf("testing for too small %d %d < %d ?\n", 
+	      box[k].ex-box[k].sx+1, box[k].ey-box[k].sy+1, MIN_PSF_SIZE);
+      }
+      if(box[k].ex-box[k].sx+1 < MIN_PSF_SIZE || 
+	 box[k].ey-box[k].sy+1 < MIN_PSF_SIZE) continue;
+/* Overlap with mask?  Run around edge, outside of star box... */
+      ym = MIN(y0, box[k].sy-1);
+      yp = MAX(y1, box[k].ey+1);
+      if(ym < 0 || yp >= ny-1) {
+	 if(VERBOSE & VERB_PSFSEL) 
+	    printf("No edge below or above y %d %d\n", ym, yp);
+	 continue;
+      }
+      for(i=x0; i<=x1; i++) {
+	 if(mask[i+ym*NX] > MASK_STAR_HALO) break;
+	 if(mask[i+yp*NX] > MASK_STAR_HALO) break;
+      }
+      if(VERBOSE & VERB_PSFSEL) {
+	 printf("testing for too much mask overlap x %d < %d ?\n", i, x1);
+      }
+      if(i <= x1) continue;
+      xm = MIN(x0, box[k].sx-1);
+      xp = MAX(x1, box[k].ex+1);
+      if(xm < 0 || xp >= nx-1) {
+	 if(VERBOSE & VERB_PSFSEL) 
+	    printf("No edge left or right x %d %d\n", xm, xp);
+	 continue;
+      }
+      for(j=y0+1; j<y1; j++) {
+	 if(mask[xm+j*NX] > MASK_STAR_HALO) break;
+	 if(mask[xp+j*NX] > MASK_STAR_HALO) break;
+      }
+      if(VERBOSE & VERB_PSFSEL) {
+	 printf("testing for too much mask overlap y, %d < %d ?\n", j, y1);
+      }
+      if(j < y1) continue;
+
+/* Good star */
+      if(VERBOSE & VERB_PSFSEL) {
+	 printf("good star at %d %d...\n", box[k].up, box[k].y0);
+      }
+      box[k].func = PSF_STAR;
+
+/* Make a postage stamp for it */
+      box[k].stamp = (IMTYPE *)calloc(size*size, sizeof(IMTYPE));
+      sum = 0;
+      for(j=y0; j<=y1; j++) {
+	 for(i=x0; i<=x1; i++) {
+	    box[k].stamp[(i-x0)+(j-y0)*size] = data[i+j*NX] - sky +
+	       USHORT_BIAS - BZERO;
+	    sum += data[i+j*NX] - sky;
+	 }
+      }
+      box[k].diff = sum;
+      box[k].slope = MAX(0.1, sum) / box[k].max;
+   }
+
+   return(0);
+}
+
+
+/****************************************************************/
+/* psf_write() writes all the postage stamps to a 3D FITS file */
+STATIC int psf_write(int nx, int ny, CELL ota[], int otanum, 
+		     const char *psffile)
+{
+   int i, k, l, nstar, fdout, otacx, otacy, xid, yid, ntot=0, sumax;
+   int cellcount, ota_xid, ota_yid;
+   double scale, phi, fwhm[3], q[3], qt, xfp, yfp, pi=4*atan(1.0);
+   IMTYPE *median_image;
+   CELL *cell;
+   OBJBOX *box;
+
+/* How many do we have to write? */
+   nstar = 0;
+   for(k=0; k<MAXCELL; k++) {
+      cell = ota + k;
+      for(l=cellcount=0; l<cell->nstar; l++) {
+	 box = cell->star+l;
+	 if(box->func != PSF_STAR) continue;
+         if(cellcount++ > MAX_PSF_PER_CELL) break;
+	 if(nstar < nmedian_buf) median_buf[nstar] = box->slope;
+	 nstar++;
+      }
+   }
+   if(nstar == 0) {
+      printf("N= %d\n", nstar);
+      return(0);
+   }
+
+/* Use the wicked crude cheapfits.c */
+   if((fdout=creat(psffile, 0644)) < 0) {
+      fprintf(stderr,"error: cannot open output PSF file %s\n", psffile);
+      return(-1);
+   }
+
+   if(!CONCAT_FITS) write_3dhdr(nx, ny, nstar+1, 0, 0, fdout);
+
+/* Median sum/max */
+   sumax = int_median(MIN(nstar, nmedian_buf), median_buf);
+//   printf("sumax = %d\n", sumax);
+
+/* Create a median image and write as the first one */
+   median_image = (IMTYPE *)calloc(nx*ny, sizeof(IMTYPE));
+   for(i=0; i<nx*ny; i++) {
+      nstar = 0;
+      for(k=0; k<MAXCELL; k++) {
+	 cell = ota + k;
+	 for(l=cellcount=0; l<cell->nstar; l++) {
+	    box = cell->star+l;
+	    if(box->func != PSF_STAR) continue;
+	    if(cellcount++ > MAX_PSF_PER_CELL) break;
+	    scale = 1e4 * sumax / box->diff;
+	    median_buf[nstar++] = (box->stamp[i]-USHORT_BIAS+BZERO) * scale;
+	 }
+      }
+      median_image[i] = int_median(nstar, median_buf) + 
+	 USHORT_BIAS - BZERO;
+   }
+
+   i = psf_stats(nx, ny, median_image, USHORT_BIAS-BZERO, fwhm, q);
+
+/* Subtract out one pixel in quadrature from median */
+   if(fwhm[0] > PIXEL_FWHM && fwhm[1] > PIXEL_FWHM) {
+      fwhm[0] = sqrt(fwhm[0]*fwhm[0] - PIXEL_FWHM*PIXEL_FWHM);
+      fwhm[1] = sqrt(fwhm[1]*fwhm[1] - PIXEL_FWHM*PIXEL_FWHM);
+   }
+
+   ota_xid = otanum % 8;
+   ota_yid = otanum / 8;
+   psc_pixel_to_fp(ota_xid, ota_yid, 2423.0, 2434.0, &xfp, &yfp);
+   phi = atan2(yfp, xfp);
+/* Change so that + means tangential, - means radial */
+   qt = -q[1] * cos(2*phi) - q[2] * sin(2*phi);
+
+   printf("N= %d PSFmaj= %.2f min= %.2f theta= %.1f m2= %.2f q+= %.3f qx= %.3f qt= %.3f\n",
+	  nstar, fwhm[0], fwhm[1], fwhm[2]*180/pi, q[0], q[1], q[2], qt);
+
+   if(CONCAT_FITS) {
+      write_2dfits(nx, ny, 0, 0, median_image, fdout);
+   } else {
+      write_2ddata(nx, ny, &ntot, median_image, fdout);
+   }
+
+/* Write each stamp as concatenated or 3D FITS file */
+   nstar = 0;
+   for(k=0; k<MAXCELL; k++) {
+      cell = ota + k;
+      xid = k % 8;
+      yid = k / 8;
+      for(l=cellcount=0; l<cell->nstar; l++) {
+	 box = cell->star+l;
+	 if(box->func != PSF_STAR) continue;
+	 if(cellcount++ > MAX_PSF_PER_CELL) break;
+	 nstar++;
+/* Note that x flip required the bigger side offset when nx is even */
+	 otacx = (PSC_HCELL - box->up) + xid*(PSC_HCELL+PSC_VSTREET);
+	 otacy = box->y0 + yid*(PSC_VCELL+PSC_HSTREET);
+	 if(CONCAT_FITS) {
+	    write_2dfits(nx, ny, otacx, otacy, box->stamp, fdout);
+	 } else {
+/* Nahhh, nobody likes this but me... */
+//	    box->stamp[0] = otacx-BZERO;	/* Origin is first 2 pixels */
+//	    box->stamp[1] = otacy-BZERO;
+	    write_2ddata(nx, ny, &ntot, box->stamp, fdout);
+	 }
+
+      }
+   }
+   if(!CONCAT_FITS) write_3dend(&ntot, fdout);
+
+   close(fdout);
+   free(median_image);
+   return(0);
+}
+
+#define MAXPSFMEDIAN (20*64)		/* Max PSF's per OTA */
+#define MIN_BELIEVABLE_FWHM 2.0		/* Minimum FWHM we'll accept */
+
+/****************************************************************/
+/* psf_write_stats() writes average PSF stats for all the cells */
+STATIC int psf_write_stats(int nx, int ny, CELL ota[], int otanum, 
+			   const char *statfile, int psfavg)
+{
+   int i0, j0, i, j;
+   int k, l, cellx, celly, ota_xid, ota_yid, nfwave, nqavg;
+   double xota, yota, xfp, yfp, phi;
+   double fwhm[3], q[3], fw[MAXPSFMEDIAN];
+   double m2[MAXPSFMEDIAN], qp[MAXPSFMEDIAN], qc[MAXPSFMEDIAN];
+   double qt[MAXPSFMEDIAN], fwavg[MAXPSFMEDIAN];
+   double qpavg[MAXPSFMEDIAN], qcavg[MAXPSFMEDIAN], qtavg[MAXPSFMEDIAN];
+   int nstar[MAXCELL], nfw[MAXCELL];
+   double fwmed[MAXCELL], m2med[MAXCELL];
+   double qpmed[MAXCELL], qcmed[MAXCELL], qtmed[MAXCELL];
+   double qpmacro, qcmacro, qtmacro, fwmacro;
+   FILE *fp;
+   CELL *cell;
+   OBJBOX *box;
+
+/* Convert psfavg from log2(N) */
+   if(psfavg >= 3) psfavg = 8;
+   else if(psfavg == 2) psfavg = 4;
+   else if(psfavg == 1) psfavg = 2;
+   else psfavg = 1;
+
+   ota_xid = otanum % PSC_NX;
+   ota_yid = otanum / PSC_NX;
+
+/* Open the output file */
+   if( (fp=fopen(statfile, "w")) == NULL) {
+      fprintf(stderr, "error: psf_write_stats cannot open '%s' for writing\n",
+	      statfile);
+      return(-1);
+   }
+
+/* Loop over all the macro-cells */
+   for(j0=0; j0<PSC_NY; j0+=psfavg) {
+      for(i0=0; i0<PSC_NX; i0+=psfavg) {
+	 nfwave = nqavg = 0;
+/* Loop over the constituent cells */
+	 for(j=0; j<psfavg; j++) {
+	    for(i=0; i<psfavg; i++) {
+	       cellx = i0 + i;
+	       celly = j0 + j;
+	       k = PSC_NX*celly + cellx;
+	       cell = ota + k;
+	       nstar[k] = nfw[k] = 0;
+/* Generate average statistics for all the PSF stars */
+	       for(l=0; l<cell->nstar; l++) {
+		  box = cell->star+l;
+		  if(box->func != PSF_STAR) continue;
+		  psf_stats(nx, ny, box->stamp, USHORT_BIAS-BZERO, fwhm, q);
+		  if(nstar[k] < MAXPSFMEDIAN) {
+		     m2[nstar[k]] = q[0];
+		     qp[nstar[k]] = q[1];
+		     qc[nstar[k]] = q[2];
+/* Get the position in the focal plane and therefore the qt statistic */
+		     psc_cell_to_pixel(cellx, celly, 0.5*PSC_HCELL/PSC_PIXEL, 
+				       0.5*PSC_VCELL/PSC_PIXEL, &xota, &yota);
+		     psc_pixel_to_fp(ota_xid, ota_yid,	xota, yota, &xfp, &yfp);
+		     phi = atan2(yfp, xfp);
+/* Change so that + means tangential, - means radial */
+		     qt[nstar[k]] = -q[1] * cos(2*phi) - q[2] * sin(2*phi);
+		     nstar[k] += 1;
+		  }
+		  if(fwhm[0] > MIN_BELIEVABLE_FWHM && 
+		     fwhm[1] > MIN_BELIEVABLE_FWHM && nfw[k] < MAXPSFMEDIAN) {
+		     fw[nfw[k]] = sqrt(fwhm[0]*fwhm[1]);
+		     nfw[k] += 1;
+		  }
+	       }
+	       fwmed[k] = double_median(nfw[k], fw);
+	       if(nstar[k] > 0) {
+		  m2med[k] = double_median(nstar[k], m2);
+		  qpmed[k] = double_median(nstar[k], qp);
+		  qcmed[k] = double_median(nstar[k], qc);
+		  qtmed[k] = double_median(nstar[k], qt);
+	       } else {
+		  m2med[k] = qpmed[k] = qcmed[k] = qtmed[k] = -99.99;
+	       }
+/* Toss these results into the macrocell median hopper */
+	       for(l=0; l<nfw[k]; l++) {
+		  if(nfwave < MAXPSFMEDIAN) fwavg[nfwave++] = fw[l];
+	       }
+	       for(l=0; l<nstar[k]; l++) {
+		  if(nqavg < MAXPSFMEDIAN) {
+		     qpavg[nqavg] = qp[l];
+		     qcavg[nqavg] = qc[l];
+		     qtavg[nqavg] = qt[l];
+		     nqavg++;
+		  }
+	       }
+	    }
+	 }
+/* Get the median of FWHM and qt over this macrocell */
+	 qpmacro = double_median(nqavg, qpavg);
+	 qcmacro = double_median(nqavg, qcavg);
+	 qtmacro = double_median(nqavg, qtavg);
+	 if(nqavg == 0) qpmacro = qcmacro = qtmacro = -99.99;
+	 fwmacro = double_median(nfwave, fwavg);
+
+/* Print out the results from this macrocell */
+	 for(j=0; j<psfavg; j++) {
+	    for(i=0; i<psfavg; i++) {
+	       cellx = i0 + i;
+	       celly = j0 + j;
+	       k = PSC_NX*celly + cellx;
+	       cell = ota + k;
+
+	       fprintf(fp, "ext=xy%1d%1d bias=%d sky=%d rmssky=%d npsf=%d fwhm=%.2f fwmed=%.2f m2=%.2f qp=%.3f qc=%.3f qt=%.3f qpm=%.3f qcm=%.3f qtm=%.3f\n", 
+		       cellx, celly, cell->bias, cell->sky, cell->rms, 
+		       nstar[k], fwmed[k], fwmacro, m2med[k], 
+		       qpmed[k], qcmed[k], qtmed[k], 
+		       qpmacro, qcmacro, qtmacro);
+	    }
+	 }
+
+
+
+      } /* i0 */
+   } /* j0 */
+
+   fclose(fp);
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/psfstats.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/psfstats.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/psfstats.c	(revision 23490)
@@ -0,0 +1,115 @@
+/* psfstats.c - calculate some statistics about a PSF */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "burntool.h"
+#include "math.h"
+#include "psf/psf.h"
+
+//#define TEST		/* Dump all the PSF info? */
+
+static unsigned short int *psfbuf=NULL;
+static int npsfbuf=0;
+#define PHONYSKY 1000
+
+/****************************************************************/
+/* psf_stats(): Tell us about this PSF star */
+STATIC int psf_stats(int nx, int ny, IMTYPE *data, int bias, 
+		     double *fwhm, double *q)
+{
+   int i, j, r, r2, err, i0, j0;
+   double d, qxx, qxy, qyy, mx, my, sum;
+   PSF_PARAM psfout;      /* Results of fit */
+   PSF_EXTRA psfextra;    /* Extra results from fit */
+   double pi=4*atan(1.0);
+
+   if(nx*ny > npsfbuf) {
+      if(psfbuf != NULL) free(psfbuf);
+      psfbuf = (ushort *)calloc(nx*ny, sizeof(ushort));
+      npsfbuf = nx*ny;
+   }
+   for(i=0; i<nx*ny; i++) {
+      j = ((int)data[i]) - bias + PHONYSKY;
+      if(j >= 0 && j < 65535) psfbuf[i] = j;
+      else psfbuf[i] = 0;
+   }
+
+/* 2D PSF fit */
+   err = psf(nx, ny, psfbuf, PSF_2DIM, NULL, &psfout, &psfextra);
+
+#ifdef TEST
+   printf("err = %d\n", err);
+#endif
+
+   if(!err) {
+#ifdef TEST
+      printf("err = %d\n", err);
+      printf("bias = %d\n", bias);
+      printf("ix, iy = %d %d\n", psfout.ix, psfout.iy);
+      printf("x0, y0 = %.2f %.2f\n", psfout.x0, psfout.y0);
+      printf("fwhm = %.2f\n", psfout.fwhm);
+      printf("peak, bckgnd = %.1f %.1f\n", psfout.peak, psfout.bkgnd);
+      printf("flux, S/N = %.1f %.2f\n", psfout.flux, psfout.sn);
+      printf("weight = %.2f\n", psfout.weight);
+      printf("FWmaj, FWmin = %.2f %.2f\n", psfextra.majfw, psfextra.minfw);
+      printf("theta = %.1f\n", psfextra.thfw*180/pi);
+      printf("wpeak, wbkgnd = %.1f %.1f\n", psfextra.wpeak, psfextra.wbkgnd);
+      printf("dflux, dbckgnd = %.1f %.1f\n", psfextra.dflux, psfextra.dbkgnd);
+      printf("rmsbkgnd = %.1f\n", psfextra.rmsbkgnd);
+#endif
+      fwhm[0] = psfextra.majfw;
+      fwhm[1] = psfextra.minfw;
+      fwhm[2] = psfextra.thfw;
+
+/* Moments */
+      i0 = MIN(psfout.ix, nx-psfout.ix);
+      j0 = MIN(psfout.iy, ny-psfout.iy);
+   } else {
+      fwhm[0] = fwhm[1] = fwhm[2] = 0.0;
+      i0 = nx/2;
+      j0 = ny/2;
+   }
+
+   r = MIN(i0, j0) - 1;
+   sum = mx = my = qxx = qxy = qyy = 0.0;
+   for(j=j0-r; j<j0+r; j++) {
+      for(i=i0-r; i<i0+r; i++) {
+	 r2 = (i-i0)*(i-i0) + (j-j0)*(j-j0);
+	 if(r2 > r*r) continue;
+	 d = (double)data[i+j*nx] - bias;
+	 sum += d;
+	 mx += (i+0.5) * d;
+	 my += (j+0.5) * d;
+	 qxx += (i+0.5) * (i+0.5) * d;
+	 qxy += (i+0.5) * (j+0.5) * d;
+	 qyy += (j+0.5) * (j+0.5) * d;
+      }
+   }
+   if(sum > 0) {
+      mx /= sum;
+      my /= sum;
+      qxx = qxx / sum - mx*mx;
+      qxy = qxy / sum - mx*my;
+      qyy = qyy / sum - my*my;
+   } else {
+      q[0] = q[1] = q[2] = 0.0;
+   }
+
+   q[0] = (qxx + qyy) / 2;
+   q[1] = qxx - qyy;
+   q[2] = 2 * qxy;
+
+/* phi is the angular position of the OTA around the center [rad] */
+//   qtang = (qxx - qyy) * cos(2*phi) + 2 * qxy * sin(2*phi);
+
+#ifdef TEST
+   printf("Sum= %.1f mx= %.2f my= %.2f qxx= %.4f qxy= %.4f qyy= %.4f\n", 
+	  sum, mx, my, qxx, qxy, qyy);
+#endif
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/sort.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/sort.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/sort.c	(revision 23490)
@@ -0,0 +1,196 @@
+/* A few sorting routines */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAXSTACK 256
+//#define NSTOP 15
+#define NSTOP 8
+
+/* Quicksort program 1980 (John Tonry) */
+int qsort_dbl(int n, double *x)
+{
+  double key, kl, kr, km, temp;
+  int l, r, m, lstack[MAXSTACK], rstack[MAXSTACK], sp;
+  register int i, j, k;
+  int mgtl, lgtr, rgtm;
+
+  sp = 0;
+  lstack[sp] = 0;
+  rstack[sp] = n-1;
+
+  while(n > NSTOP && sp >= 0) {
+/* Sort a subrecord off the stack */
+    l = lstack[sp];
+    r = rstack[sp];
+    sp--;
+    m = (l + r) / 2;
+/* Set KEY = median of X(L), X(M), X(R) */
+    kl = x[l];
+    km = x[m];
+    kr = x[r];
+    mgtl = km > kl;
+    rgtm = kr > km;
+    lgtr = kl > kr;
+#ifndef STD_KEY
+    if(mgtl ^ rgtm) {
+      if(mgtl ^ lgtr) key = kr;
+      else            key = kl;
+    } else {
+      key = km;
+    }
+#else
+/* Curiously enough, this non-median seems to work as well or better */
+    if(mgtl ^ rgtm) {
+      key = km;
+    } else {
+      if(mgtl ^ lgtr) key = kl;
+      else            key = kr;
+    }
+#endif
+    i = l;
+    j = r;
+    while(1) {
+/* Find a big record on the left */
+      while(x[i] < key) i++;
+
+/* Find a small record on the right */
+      while(x[j] > key) j--;
+
+      if(i >= j) break;
+/* Exchange records */
+      temp = x[i];
+      x[i] = x[j];
+      x[j] = temp;
+      i++;
+      j--;
+    }
+
+/* Subfile is partitioned into two halves, left .le. right */
+/* Push the two halves on the stack */
+    if(j-l+1 > NSTOP) {
+      sp = sp + 1;
+      lstack[sp] = l;
+      rstack[sp] = j;
+    }
+    if(r-j > NSTOP) {
+      sp = sp + 1;
+      lstack[sp] = j+1;
+      rstack[sp] = r;
+    }
+    if(sp >= MAXSTACK) {
+//      fprintf(stderr,"QSORT8: Fatal error from stack overflow\n");
+//      fprintf(stderr,"Fall back on sort by insertion\n");
+      break;
+    }
+  }
+
+/* Sorting routine that sorts the N elements of single precision */
+/* array X by straight insertion between previously sorted numbers */
+  for(j=n-2; j>=0; j--) {
+    for(i=j+1, k=j; i<n; i++) {
+      if(x[j] <= x[i]) break;
+      k = i;
+    }
+    if(k != j) {
+      temp = x[j];
+      for(i=j+1; i<=k; i++) x[i-1] = x[i];
+      x[k] = temp;
+    }
+  }
+  return(0);
+}
+
+/* Quicksort program 1980 (John Tonry) */
+int qsort_int(int n, int *x)
+{
+  int key, kl, kr, km, temp;
+  int l, r, m, lstack[MAXSTACK], rstack[MAXSTACK], sp;
+  register int i, j, k;
+  int mgtl, lgtr, rgtm;
+
+  sp = 0;
+  lstack[sp] = 0;
+  rstack[sp] = n-1;
+
+  while(n > NSTOP && sp >= 0) {
+/* Sort a subrecord off the stack */
+    l = lstack[sp];
+    r = rstack[sp];
+    sp--;
+    m = (l + r) / 2;
+/* Set KEY = median of X(L), X(M), X(R) */
+    kl = x[l];
+    km = x[m];
+    kr = x[r];
+    mgtl = km > kl;
+    rgtm = kr > km;
+    lgtr = kl > kr;
+#ifndef STD_KEY
+    if(mgtl ^ rgtm) {
+      if(mgtl ^ lgtr) key = kr;
+      else            key = kl;
+    } else {
+      key = km;
+    }
+#else
+/* Curiously enough, this non-median seems to work as well or better */
+    if(mgtl ^ rgtm) {
+      key = km;
+    } else {
+      if(mgtl ^ lgtr) key = kl;
+      else            key = kr;
+    }
+#endif
+    i = l;
+    j = r;
+    while(1) {
+/* Find a big record on the left */
+      while(x[i] < key) i++;
+
+/* Find a small record on the right */
+      while(x[j] > key) j--;
+
+      if(i >= j) break;
+/* Exchange records */
+      temp = x[i];
+      x[i] = x[j];
+      x[j] = temp;
+      i++;
+      j--;
+    }
+
+/* Subfile is partitioned into two halves, left .le. right */
+/* Push the two halves on the stack */
+    if(j-l+1 > NSTOP) {
+      sp = sp + 1;
+      lstack[sp] = l;
+      rstack[sp] = j;
+    }
+    if(r-j > NSTOP) {
+      sp = sp + 1;
+      lstack[sp] = j+1;
+      rstack[sp] = r;
+    }
+    if(sp >= MAXSTACK) {
+//      fprintf(stderr,"QSORT8: Fatal error from stack overflow\n");
+//      fprintf(stderr,"Fall back on sort by insertion\n");
+      break;
+    }
+  }
+
+/* Sorting routine that sorts the N elements of single precision */
+/* array X by straight insertion between previously sorted numbers */
+  for(j=n-2; j>=0; j--) {
+    for(i=j+1, k=j; i<n; i++) {
+      if(x[j] <= x[i]) break;
+      k = i;
+    }
+    if(k != j) {
+      temp = x[j];
+      for(i=j+1; i<=k; i++) x[i-1] = x[i];
+      x[k] = temp;
+    }
+  }
+  return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/stardetect.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/stardetect.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/stardetect.c	(revision 23490)
@@ -0,0 +1,200 @@
+/* stardetect.c - identify burns and stars */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "math.h"
+
+#include "burntool.h"
+#include "burnparams.h"
+
+/****************************************************************/
+/* star_detect(): Find all the stars and burned patches in a cell */
+STATIC int star_detect(int nx, int ny, int NX, int NY, DTYPE *data,
+		       MTYPE *mask, MTYPE *veto, CELL *cell, int cellnum)
+{
+   int i, j, k, l;
+   int burnthresh, trailthresh, starthresh, starcut, thresh_hi, thresh_lo;
+   int nbox, xon, xoff;
+
+/* Reset the masks (DEPENDS on MASK_NONE = 0, tough!) */
+   bzero(mask, NX*ny*sizeof(MTYPE));
+   bzero(veto, NX*ny*sizeof(MTYPE));
+
+   nbox = 0;
+
+   burnthresh = thresh_hi = BURN_THRESH + cell->bias;
+   trailthresh = thresh_lo = TRAIL_THRESH + cell->bias;
+   starthresh = STAR_THRESH + cell->sky + cell->bias;
+   starcut = STAR_THRESH/2 + cell->sky + cell->bias;
+
+/* Look at all the pixels which pass the burn threshold */
+   for(j=0; j<ny; j++) {
+      xon = -1;
+      for(i=0; i<nx; i++) {
+/* Big enough?  Initialize a box and push it outwards to the trail level. */
+	 if(mask[i+j*NX] > MASK_NONE) continue;
+	 if(xon < 0) {
+	    if(data[i+j*NX] > burnthresh) {
+	       xon = i;
+	       thresh_hi = burnthresh;
+	       thresh_lo = trailthresh;
+	       if(VERBOSE & VERB_DETECT) {
+		  printf("Starting a burn at %d %d %d\n", i, j, data[i+j*NX]);
+	       }
+	    } else if(data[i+j*NX] > starthresh) {
+/* Local maximum? */
+	       if(!local_max(i, j, STAR_RADIUS, nx, ny, NX, data)) continue;
+	       if(data[i+j*NX] < veto[i+j*NX]) continue;
+	       xon = i;
+//	       thresh_hi = starthresh;
+//	       thresh_lo = starcut;
+	       thresh_hi = data[i+j*NX];
+	       thresh_lo = STAR_FRAC*(data[i+j*NX]-cell->sky-cell->bias) + 
+		  cell->sky + cell->bias;
+	       if(VERBOSE & VERB_DETECT) {
+		  printf("Starting a star at %d %d %d\n", i, j, data[i+j*NX]);
+	       }
+	    }
+	 }
+
+	 if(xon >= 0 && (data[i+j*NX] < thresh_hi || i == nx-1)) {
+
+//	 if(xon < 0 && data[i+j*NX] > burnthresh && mask[i+j*NX] == 0) xon = i;
+//	 if(xon > 0 && (data[i+j*NX] < burnthresh || i == nx-1)) {
+
+	    xoff = i<nx-1 ? i-1 : nx-1;
+	    if(nbox >= MAXBURN) {
+	       fprintf(stderr, "error: too many burn boxes\n");
+	       return(-1);
+	    }
+	    boxbuf[nbox].sx = xon;
+	    boxbuf[nbox].ex = xoff;
+	    boxbuf[nbox].sy = j;
+	    for(k=j; k<ny && data[(xon+xoff)/2+k*NX] > thresh_hi; k++);
+	    boxbuf[nbox].ey = k-1;
+	    grow_box(nx, ny, NX, data, thresh_lo, boxbuf+nbox);
+/* Fill in max and center info */
+	    boxbuf[nbox].max = 0;
+	    for(l=boxbuf[nbox].sy; l<=boxbuf[nbox].ey; l++) {
+	       for(k=boxbuf[nbox].sx; k<=boxbuf[nbox].ex; k++) {
+		  if(data[k+l*NX] > boxbuf[nbox].max) {
+		     boxbuf[nbox].cx = k;
+		     boxbuf[nbox].cy = l;
+		     boxbuf[nbox].max = data[k+l*NX];
+		  }
+	       }
+	    }
+/* A box which triggered on starthresh cannot envelop burnthresh */
+	    if(thresh_hi < burnthresh && boxbuf[nbox].max > burnthresh) {
+	       if(VERBOSE & VERB_DETECT) {
+		  printf("Ditching box %d %d %d %d  max = %d > burnthresh\n",
+			 boxbuf[nbox].sx, boxbuf[nbox].sy,
+			 boxbuf[nbox].ex, boxbuf[nbox].ey,
+			 boxbuf[nbox].max);
+	       }
+/* Mark the veto mask so as not to trigger on this one again */
+	       for(l=boxbuf[nbox].sy; l<=boxbuf[nbox].ey; l++) {
+		  for(k=boxbuf[nbox].sx; k<=boxbuf[nbox].ex; k++) {
+		     veto[k+l*NX] = boxbuf[nbox].max;
+		  }
+	       }
+	       xon = -1;
+	       continue;
+	    }
+
+/* Mask the pixels so as not to catch them again! */
+	    for(l=boxbuf[nbox].sy; l<=boxbuf[nbox].ey; l++) {
+	       for(k=boxbuf[nbox].sx; k<=boxbuf[nbox].ex; k++) {
+		  mask[k+l*NX] = MASK_CTR;
+	       }
+	    }
+	    boxbuf[nbox].sat = boxbuf[nbox].max >= burnthresh;
+	    boxbuf[nbox].max -= cell->sky + cell->bias;
+/* Burned only if it triggered on burnthresh, not if it enveloped it */
+	    boxbuf[nbox].burned = thresh_hi >= burnthresh;
+/* But take a hard look at stars with really bright centers... */
+	    if(!boxbuf[nbox].burned && boxbuf[nbox].max > MAX_THRESH) {
+	       burn_test(nx, ny, NX, data, cell->rms, mask, boxbuf+nbox);
+	    }
+	    boxbuf[nbox].time = cell->time;
+	    boxbuf[nbox].cell = cellnum;
+	    boxbuf[nbox].stamp = NULL;
+	    boxbuf[nbox].func = FUNC_NONE;
+	    boxbuf[nbox].sxfit = boxbuf[nbox].sx;
+	    boxbuf[nbox].exfit = boxbuf[nbox].ex;
+	    boxbuf[nbox].nfit = 0;
+	    boxbuf[nbox].zero = NULL;
+	    boxbuf[nbox].xfit = boxbuf[nbox].yfit = NULL;
+	    if(VERBOSE & VERB_DETECT) {
+	       printf("New box at %d %d %d %d", 
+		      boxbuf[nbox].sx, boxbuf[nbox].sy,boxbuf[nbox].ex, boxbuf[nbox].ey);
+	       printf("   %d %d %d %d", 
+		      boxbuf[nbox].x0m, boxbuf[nbox].x0p,boxbuf[nbox].x1m, boxbuf[nbox].x1p);
+	       printf("   %d %d %d %d\n", 
+		      boxbuf[nbox].y0m, boxbuf[nbox].y0p,boxbuf[nbox].y1m, boxbuf[nbox].y1p);
+	    }
+	    xon = -1;
+	    nbox++;
+	 }
+      }
+   }
+
+/* Reject any stars which have enveloped a burned core */
+   for(k=0; k<nbox; k++) {
+//      printf("Examining box %d\n", k);
+      if(!(boxbuf[k].burned)) continue;
+//      printf("  which is a burn\n");
+      for(l=0; l<nbox; l++) {
+	 if(k == l) continue;
+//	 printf("Examining star %d\n", l);
+/* Has star l enveloped burn k? */
+/* Don't care whether this is burned or unburned: enveloping is bad */
+//	 if(!(boxbuf[l].burned)) continue;
+//	 printf("  which has a burned core\n");
+//	 printf("%3d %3d %3d %3d %3d %3d %3d %3d\n", 
+//		boxbuf[k].sx, boxbuf[l].sx, boxbuf[k].ex, boxbuf[l].ex,
+//		boxbuf[k].sy, boxbuf[l].sy, boxbuf[k].ey, boxbuf[l].ey);
+	 if(boxbuf[k].sx >= boxbuf[l].sx &&
+	    boxbuf[k].ex <= boxbuf[l].ex &&
+	    boxbuf[k].sy >= boxbuf[l].sy &&
+	    boxbuf[k].ey <= boxbuf[l].ey) {
+/* Wipe it out */
+	    for(i=l; i<nbox-1; i++) memcpy(boxbuf+i, boxbuf+i+1, sizeof(OBJBOX));
+//	    printf("Wiping out star %d enveloping burn %d\n", l, k);
+	    nbox--;
+	    l--;
+	    if(k > l) k--;
+	 }
+      }
+   }
+
+/* Remark mask if saturated */
+   for(i=0; i<nbox; i++) {
+      if(boxbuf[i].sat) {
+	 for(l=boxbuf[i].sy; l<=boxbuf[i].ey; l++) {
+	    for(k=boxbuf[i].sx; k<=boxbuf[i].ex; k++) {
+	       mask[k+l*NX] = MASK_SAT;
+	    }
+	 }
+      }
+   }
+
+/* How many real burns? */
+   for(k=cell->nburn=0; k<nbox; k++) if(boxbuf[k].burned) cell->nburn++;
+   cell->nstar = nbox - cell->nburn;
+   cell->burn = (OBJBOX *)calloc(cell->nburn, sizeof(OBJBOX));
+   cell->star = (OBJBOX *)calloc(cell->nstar, sizeof(OBJBOX));
+
+/* Copy the boxes to the cell info structure */
+   for(k=i=j=0; k<nbox; k++) {
+      if(boxbuf[k].burned) memcpy(cell->burn+j++, boxbuf+k, sizeof(OBJBOX));
+      else                 memcpy(cell->star+i++, boxbuf+k, sizeof(OBJBOX));
+   }
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c	(revision 23490)
@@ -0,0 +1,281 @@
+/* trailfit.c - routines to fit and subtract trails */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "math.h"
+
+#include "burntool.h"
+#include "burnparams.h"
+
+STATIC double ybuf[MAXSIZE], zbuf[MAXSIZE], wbuf[MAXSIZE];
+
+/****************************************************************/
+/* Subtract one rectangle's fit from the data */
+STATIC int sub_fit(int nx, int ny, int NX, IMTYPE *buf, OBJBOX *box, 
+		   int sign)
+{
+   int i, j, k;
+   int y0, y1, ys, dy, delta;
+
+   if(ny > MAXSIZE) {
+      fprintf(stderr, "error: not enough buffer in fit_trail\n");
+      return(-1);
+   }
+
+   if(box->func != BURN_PWR && box->func != BURN_EXP) {
+      fprintf(stderr, "error: unimplemented fit function %d\n", box->func);
+      return(-1);
+   }
+
+   if(box->fiterr) return(-1);
+   y0 = box->y0;
+   y1 = (box->up) ? ny-1 : 0;
+   dy = (y0<y1) ? +1 : -1;
+   if(box->up) ys = box->sy;
+   else        ys = box->ey;
+
+/* Calculate all needed y values */
+   for(j=ys; dy*j<=dy*y1; j+=dy) {
+      if(box->func == BURN_PWR) {
+	 if(dy*(j-y0) <= 0) ybuf[j] = exp(box->slope*log(Y_SCALE*1.0));
+	 else ybuf[j] = exp(box->slope*log(Y_SCALE*dy*(j-y0)));
+      } else if(box->func == BURN_EXP) {
+//	 ybuf[j] = exp(box->slope*Y_SCALE*MAX(0,dy*(j-y0)));
+	 ybuf[j] = exp(box->slope*Y_SCALE*dy*(j-y0));
+      }
+   }
+/* Subtract the fits */
+//   printf("%3d %3d %3d %1d %1d %8.5f\n", 
+//	  box->cx, box->cy, box->y0, box->func, box->up, box->slope);
+
+   for(k=0; k<box->nfit; k++) {
+      i = box->xfit[k];
+      if(sign > 0) {		/* Subtract */
+	 for(j=box->yfit[k]; dy*j<=dy*y1; j+=dy) {
+//	 if(k==box->nfit/2) printf("%3d %6d ", j, buf[i+NX*j]);
+	    delta = box->zero[k] * ybuf[j] + 0.5;
+/* No 16 bit wraparound below zero allowed */
+//	    if(delta < buf[i+NX*j]+BZERO) buf[i+NX*j] -= delta;
+/* Allow 16 bit wraparound in order to undo it... */
+	    buf[i+NX*j] -= delta;
+//	 if(k==box->nfit/2) printf("%6.1f %6d\n", 
+//			 sign * box->zero[k] * ybuf[j], buf[i+NX*j]);
+	 }
+      } else {			/* Restore */
+	 for(j=box->yfit[k]; dy*j<=dy*y1; j+=dy) {
+/* No 16 bit wraparound allowed */
+//	    if(delta < buf[i+NX*j]+BZERO) buf[i+NX*j] += delta;
+	    delta = box->zero[k] * ybuf[j] + 0.5;
+	    buf[i+NX*j] += delta;
+	 }
+      }
+   }
+
+   return(0);
+}
+
+/****************************************************************/
+/* Tuning parameters for fit_trail */
+#define MAXWGT 2.0	/* Maximum allowed weight */
+#define MINWGT 0.1	/* Minimum allowed weight */
+#define MAXDEV 0.5	/* Maximum ln deviation above first pass fit */
+#define MAXRMS 4.0	/* Minimum factor of RMS to be chopped */
+
+/* Fit one rectangle with a power law or exp: up=0/1 for down/up from y0 */
+STATIC int fit_trail(int nx, int ny, int NX, 
+		    DTYPE *data, MTYPE *mask, OBJBOX *box,
+		    int up, int bckgnd, int rms, int fitfunc)
+{
+   int i, j, k, err, nfit;
+   int xs, xe, y0, y1, y2, dy, yfit;
+   double slope, zero, zsum, wsum, trial;
+   char fooname[60];
+   FILE *fp=stdout;
+
+   if(ny > MAXSIZE) {
+      fprintf(stderr, "error: not enough buffer in fit_trail\n");
+      return(-1);
+   }
+
+   xs = box->sxfit;
+   xe = box->exfit;
+
+   if(up) {
+      y0 = (box->y0m + box->y1m + box->y0p + box->y0p + 2) / 4;
+/* Maybe a bit better?  Maybe not... */
+//      y0 = box->ey;
+      y1 = box->ey + FIT_EDGE;	/* Start of fit, budged away from the burn */
+      y2 = ny - 1;		/* End of fit */
+      dy = +1;
+      yfit = box->sy;		/* Start of validity, TBD later by col */
+   } else {
+      y0 = (box->y0m + box->y1m + box->y0p + box->y0p + 2) / 4;
+      y1 = 0;			/* Start of fit */
+      y2 = box->sy - FIT_EDGE;	/* End of fit, budged away from the burn */
+//      y2 = box->ey - FIT_EDGE;	/* End of fit, budged away from the burn */
+//      y2 = y0;	/* End of fit, budged away from the burn */
+      dy = -1;
+      yfit = box->ey;		/* Start of validity, TBD later by col */
+   }
+
+   if(VERBOSE & VERB_FIT) {
+      printf("Fit requested xs,xe,y0,y1,y2,dy,up,f= %d %d %d %d %d %d %d %d\n", 
+	     xs, xe, y0, y1, y2, dy, up, fitfunc);
+   }
+
+/* Make sure to alloc memory, even if the fit fails */
+   if(box->zero != NULL) free(box->zero);
+   if(box->xfit != NULL) free(box->xfit);
+   if(box->yfit != NULL) free(box->yfit);
+   box->zero = (double *)calloc(xe-xs+1, sizeof(double));
+   box->xfit = (int *)calloc(xe-xs+1, sizeof(int));
+   box->yfit = (int *)calloc(xe-xs+1, sizeof(int));
+/* Some defaults */
+   box->slope = 0.0;
+   box->func = fitfunc;
+   box->up = up;
+   box->y0 = y0;
+   for(i=0; i<xe-xs+1; i++) {
+      box->zero[i] = 0.0;
+      box->xfit[i] = i+xs;
+      box->yfit[i] = y0;
+   }
+
+   if(up && y1 >= ny-1) {
+      box->slope = -1.0;
+      box->nfit = xe - xs + 1;
+      box->fiterr = FIT_TOP_ERROR;
+      return(0);
+   }
+
+   if(VERBOSE & VERB_FITPROF) {
+      sprintf(fooname, "/tmp/foobt.%d", xs);
+      fp = fopen(fooname, "w");
+   }
+
+/* Accumulate points to fit */
+   nfit = y2 - y1 + 1;
+   for(j=y1; j<=y2; j++) {
+      ybuf[j] = Y_SCALE * dy * (j-y0);
+      zbuf[j]=0.0;
+      for(i=xs, k=0; i<=xe; i++) {
+//	 printf("%4d %4d %7d %7d\n", i, j, data[i+j*NX], mask[i+j*NX]);
+	 if(data[i+j*NX] != NODATA && mask[i+j*NX] == MASK_NONE) {
+//	 if(data[i+j*NX] != NODATA) {
+	    zbuf[j] += data[i+j*NX];
+	    k++;
+	 }
+      }
+//      printf("%4d %4d %7d\n", k, j, zbuf[j]);
+      zbuf[j] = zbuf[j] / MAX(1,k) - bckgnd;
+/* Linearize for fit... */
+      if(fitfunc == BURN_PWR) ybuf[j] = log(ybuf[j]);
+      wbuf[j] = 0;
+      if(zbuf[j] > 1) {
+	 wbuf[j] = MIN(MAXWGT, (zbuf[j] / rms));  /* Quadratic not good */
+	 wbuf[j] = MAX(MINWGT, wbuf[j]);
+	 zbuf[j] = log(zbuf[j]);
+      }
+   }
+/* First pass fit */
+   err = wlinearfit(nfit, ybuf+y1, zbuf+y1, wbuf+y1, &slope, &zero);
+   if(VERBOSE & VERB_FIT) {
+      printf("nfit= %d  err= %d  slope= %.3f  zero= %.3f\n", 
+	     nfit, err, slope, zero);
+   }
+   if(err) {
+      box->fiterr = FIT_ERROR;
+      return(-1);
+   }
+
+/* Trim away any really big positive deviations */
+   for(j=y1; j<=y2; j++) {
+      if(zbuf[j]-(ybuf[j]*slope+zero) > MAXDEV && 
+	 zbuf[j] > log(MAXRMS*rms)) wbuf[j] = 0;
+      if(VERBOSE & VERB_FITPROF) {
+	 fprintf(fp, "%9.4f %9.4f %9.4f %3d\n", ybuf[j], zbuf[j], wbuf[j], j);
+      }
+   }
+/* Second pass fit */
+   err = wlinearfit(nfit, ybuf+y1, zbuf+y1, wbuf+y1, &slope, &zero);
+   if(err) {
+      box->fiterr = FIT_ERROR;
+      return(-1);
+   }
+   box->fiterr = 0;		/* Whew, got a fit */
+
+   if(VERBOSE & VERB_FITPROF) {
+      printf("jt %d  %.3f %.3f\n", xs, zero, slope);
+      fclose(fp);
+   }
+
+/* FIXME: sanity check fits */
+   if(slope >= FIT_MAX_SLOPE || slope < FIT_MIN_SLOPE) {
+      box->fiterr = FIT_SLOPE_ERROR;
+      return(-1);
+   }
+
+/* Reconstruct the fit for comparison with the data col by col */
+   for(j=y1; j<=y2; j++) zbuf[j] = exp(ybuf[j]*slope);
+/* And tag on the extras to determine the end of the fit */
+   for(j=yfit; dy*j<dy*(up?y1:y2); j+=dy) {
+      if(fitfunc == BURN_EXP) {
+//	 zbuf[j] = exp(Y_SCALE*MAX(0,dy*(j-y0))*slope);
+	 zbuf[j] = exp(Y_SCALE*dy*(j-y0)*slope);
+      } else {
+	 if(dy*(j-y0) <= 0) zbuf[j] = exp(log(Y_SCALE*1.0)*slope);
+	 else zbuf[j] = exp(log(Y_SCALE*dy*(j-y0))*slope);
+      }
+   }
+
+/* Save the fit information */
+   box->slope = slope;
+   box->nfit = 0;
+/* Save individual scaled versions for each column */
+   for(i=xs; i<=xe; i++) {
+      zsum = wsum = 0.0;
+      for(j=y1; j<=y2; j++) {
+	 if(wbuf[j] > 0 && data[i+j*NX] != NODATA && 
+	    mask[i+j*NX] == MASK_NONE) {
+//	 if(wbuf[j] > 0 && data[i+j*NX] != NODATA) {
+//	    wsum += wbuf[j];
+//	    zsum += wbuf[j] * (data[i+j*NX] - bckgnd) / zbuf[j];
+	    wsum += zbuf[j];
+	    zsum += data[i+j*NX] - bckgnd;
+	 }
+      }
+      if(zsum < 0 || wsum <= 0) {
+	 zsum = 0.0;
+      } else {
+	 zsum = zsum / wsum;
+      }
+/* FIXME: what's a really good criterion for negligible fit? */
+/* 100 pixels up fit is zsum or ~zsum/e */
+      if(zsum > NEGLIGIBLE_TRAIL*rms) {
+
+/* Ascertain the starting point of where the fit is good */
+//      box->yfit[box->nfit] = yfit;	/* Vanilla, misses center */
+//      box->yfit[box->nfit] = y0;	/* Center, no adjust */
+	 for(j=yfit; dy*j<=dy*(up?y2:y1); j+=dy) {
+	    trial = zsum * zbuf[j];
+/* First time data - fit is closer to sky than is data */
+	    if(data[i+j*NX] > bckgnd + 0.5*trial) break;
+	 }
+	 box->yfit[box->nfit] = j;
+	 box->zero[box->nfit] = zsum;
+	 box->xfit[box->nfit] = i;
+	 box->nfit += 1;
+      }
+   }
+/* Update fit ranges */
+   box->sxfit = box->xfit[0];
+   box->exfit = box->xfit[box->nfit-1];
+
+   return(0);
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/FHRealTime
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/FHRealTime	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/FHRealTime	(revision 23490)
@@ -0,0 +1,186 @@
+
+DRAFT - Real-Time extensions to libfh for "video" mode image clients.
+---------------------------------------------------------------------
+
+I. Definition of "real-time" display mode
+
+  A FITS viewer could be started in a special mode (e.g., with
+  a command line option) in which it is intended to display
+  only "current" image data.  The idea is to define an interface
+  that allow a FITS client to determine:
+
+  A. The number of extensions (if any) and the dimensions of the
+     image area(s), and whether or not the dimensions have changed.
+
+  B. If a file is current, whether or not it is still dynamically
+     changing (currently being written by DetCom, for example.)
+
+  C. If a single plane/image is partially written, which regions
+     are complete and which are yet to be read (e.g. from the camera.)
+
+  D. If the file has NAXIS>2, which plane in a cube is the most recent.
+
+  E. If a single plane/image is being built from an iterative
+     process such as on-the-ramp sampling, or being re-used
+     as in a circular buffer for guider images, which revision
+     of the data currently exists.
+
+  F. Whether a file is the most current or not, and which file
+     supercedes it.
+
+II. Methods
+
+  A. Extensions, file geometry - When a FITS client attempts to open
+     a new file, libfh takes care of waiting for the proper read-lock
+     to happen.  Once such a read lock can be obtained, the following
+     items are guaranteed to be populated and must not be changed
+     by detcom or whatever is providing the FITS file:
+
+     1. The number of extensions (NEXTEND in the primary header unit)
+     2. The number of dimensions (NAXIS for each image)
+     3. The dimensions themselves (NAXIS1, NAXIS2, NAXIS3, ...)
+     4. The pixel format (BITPIX)
+
+     . . . others?
+
+     Use of BITPIX and NAXIS* follows the FITS standard.
+
+     Use of extensions requires a little explanation.  If the
+     file has no extensions, a basic FITS image is assumed.
+     Otherwise, a set of FITS image extensions (other extension
+     types ignored??) are expected, exactly equal to NEXTEND
+     in the primary header.  The steps below may apply either
+     to a single basic FITS, or to an iteration through each
+     extension.
+
+     The above information is essentially available as soon as the
+     file exists.  This is ensured by the way a program generating
+     a FITS file using libfh uses file locks.
+
+  B. Next, a keyword RTACTIVE=T/F can be checked.  Its presence
+     during step (A) indicates whether or not the current FITS
+     buffer is going to support the real-time extensions that follow.
+     Initially, it will appear as T(rue), meaning that the FITS
+     file is actively being formed in real time.  Once the file will
+     no longer be changing RTACTIVE will change to F(alse).  The
+     internal methods in libfh for determining progress of a real-time
+     file are affected by this keyword in the following way:
+
+       RTACTIVE=T: Checks are made for zero-pixels plus a signature
+                   pixel within each image plane (if cubes) to determine
+                   current real-time progress of a frame, or a cube sequence.
+       RTACTIVE=F: Progress functions return 100% complete.
+       RTACTIVE not present: Real-time extensions should be disabled and
+                             progress functions also return 100% complete.
+
+  C. During the process of reading pixels from a camera, it may
+     be desirable to display the part of the image area which has
+     been read if the process takes several seconds.  For this case,
+     each extension (or the single FITS image) must end up getting
+     filled from the beginning or end of its image area buffer.
+     (If NOAO's model was followed strictly, and no flipping is
+     ever done on pixel data as it is read from the amplifier, only
+     the beginning-to-end case would be needed, but we have decided
+     to do some of our own flipping.)
+
+     By setting the RTACTIVE keyword, a creator of a FITS file is
+     indicating that it has initialized the pixel image areas with
+     marker-pixels at select locations.  It must set these if the
+     RTACTIVE keyword is used.  These locations are checked by libfh
+     to determine the progress of a FITS file being written.
+
+  D. In addition to determining the progress within a 2D image plane,
+     the marker pixels can be used to determine which plane(s) of
+     a cube have been written so far, by checking which planes are
+     still at 0%.  FITS providers which will be re-using a cube as a
+     circular buffer of frames (e.g., for guiding) must always maintain
+     an entire frame as unused (0%) by rewriting the marker pixels
+     in that buffer, before re-using the last remaining buffer with
+     marker pixels.  In this way, the most recent frame shall be determined
+     by looping through all of the planes and finding the first one
+     that is at 0%, and then backing up one (with a modulo.)  This finds
+     the most recent complete or partially complete frame.  To find the
+     most recently completed frame only, the same method is followed
+     except the search is made for the first frame that is <100% instead
+     of equal to 0%.  This plane will be the most recent one that an
+     image display should attempt to render at all times.
+
+  E. A keyword RTVERS will contain a version number (integer) which
+     increments each time a buffer is re-used.  If a client uses the
+     methods from (D) to determine that it is still on the correct
+     cube plane, (C) is used to compare the displayed-part with the
+     now-available-part.  However, the value of displayed-part must
+     be reset to 0 whenever the RTVERS number no longer matches.
+
+  F. Finding the "current" file.
+
+     For a science frame, creation of a totally new "current" file
+     may correspond to going to the next odometer number.  If a display
+     has been trained on viewing the current image stream from the
+     camera, it must switch to the new file when this happens.
+
+     For a guider, when a stream of images are not being saved, the
+     filename will typically be re-used (see (E), above)
+     However, since it greatly simplifies things
+     to constrain the size (NAXIS1, NAXIS2) of an image once it is
+     created, the guider could also use a jump to a new filename as
+     a signal that the image size may have changed, but otherwise be
+     able to rely on those and other parameters (BITPIX, etc.) not
+     changing.
+
+     The FITS client could accept control messages on stdin, telling
+     it to switch to a new FITS file location (and possibly do other
+     things, like turning on/off histogram equalization) through
+     the use of a basic command set.
+
+     From the session side, a link or symbolic link could be maintained
+     which always indicates the most "current" science and guide frame.
+     The full filename of the most recent frame could also be kept in a
+     fixed variable in the status server.
+
+     Joining the two previous pieces together would be a separate program
+     that monitors the filename in the status server and sends the command
+     to update to the FITS viewer.  For example:
+
+ssFitsMonitor /i/wircam/guide.fits | rtfits
+
+     Note that ssFitsMonitor would only be sending an update on every frame
+     if this happens to be a science frame done without cubes.  For other
+     cases where a cube is being built, rtfits would use libfh to poll
+     for the most recent cube plane.
+
+III. Keyword Examples
+
+RTACTIVE=                        T / Is file still being built?
+RTVERS  =                        3 / Number of real-time re-writes
+
+  ... everything else is determined from the marker pixels.
+
+IV. Libfh convenience functions
+
+  Real-time FITS files can be opened and accessed the usual way
+  with standard libfh calls.  But instead of accessing the RT*
+  keywords and marker pixels directly, it is recommended to use
+  the following new functions in libfh to determine the state of
+  "real time" FITS files:
+
+fh_bool fh_rt_present(HeaderUnit hu);
+fh_bool fh_rt_active(HeaderUnit hu);
+int     fh_rt_version(HeaderUnit hu);
+int     fh_rt_plane_completed(HeaderUnit hu); /* Returns 0..(NAXIS3-1) */
+int     fh_rt_plane_latest(HeaderUnit hu);    /* Returns 0..(NAXIS3-1) */
+int     fh_rt_plane_row_latest(HeaderUnit hu, int plane); /* Returns 0..(NAXIS2-1) */
+
+  It is not always necessary to call fh_rt_present() and fh_rt_active().
+
+  If fh_rt_present() would return false, then:
+
+     fh_rt_active() will also always return false,
+
+  and whenever fh_rt_active() would return false, then:
+
+     fh_rt_version() always returns some constant number,
+     fh_rt_plane_completed() returns NAXIS3-1, or 0 if no NAXIS3,
+     fh_rt_plane_latest() returns NAXIS3-1, or 0 if no NAXIS3,
+     fh_rt_plane_row_latest() returns NAXIS2-1 for any plane.
+
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Index
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Index	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Index	(revision 23490)
@@ -0,0 +1,18 @@
+# Description:
+
+  package		FITS Handling Library
+  version		1
+  organization		Canada-France-Hawaii Telescope
+  email			daprog@cfht.hawaii.edu
+  year			2001
+
+# Contents:
+
+  Makefile		Use with GNU make to build libfh
+
+  fh.h			FITS Handling Routines for Standard FITS and MEF
+  fh.c			FITS Handling Routines (see fh.h for descriptions)
+  fh_rt.h		FITS RealTime routines
+  fh_rt.c		FITS RealTime routines
+  fh_validate.c		A routine to validate the completeness of header.
+  fh_registry.h		A registry of FITS keywords in use at CFHT.
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Make.Common
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Make.Common	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Make.Common	(revision 23490)
@@ -0,0 +1,1 @@
+link ../Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Makefile
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Makefile	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/Makefile	(revision 23490)
@@ -0,0 +1,25 @@
+# `Makefile' - Use with GNU make to build libfh
+#
+#   This file is part of version 1 of the FITS Handling Library.
+#   Read the `License' file for terms of use and distribution.
+#   Copyright 2001, Canada-France-Hawaii Telescope, daprog@cfht.hawaii.edu.
+#
+# ___This header automatically generated from `Index'. Do not edit it here!___
+# Makefile for libfh
+
+include ../Make.Common
+
+VERSION = 2.01
+CCWARN += $(WERROR)
+CCDEFS += -DHAVE_FH_VALIDATE
+SRCS = fh.c
+HDRS = fh.h fh_registry.h fh_registry.asm
+
+fh_registry.asm: fh_registry.h fh_registry_to_asm.sh
+	./fh_registry_to_asm.sh < $< > $@
+
+include ../Make.Common
+
+# Dependencies by Make.Common $Revision: 2.17 $
+
+$(OBJ)/fh.o: fh.c fh.h fh_validate.c
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh.c	(revision 23490)
@@ -0,0 +1,3192 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`fh.c' - FITS Handling Routines (see fh.h for descriptions)
+
+This file is part of version 1 of the FITS Handling Library.
+Read the `License' file for terms of use and distribution.
+Copyright 2001, Canada-France-Hawaii Telescope, daprog@cfht.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>	/* for read() and write() */
+#include <fcntl.h>	/* For file locking */
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <float.h>
+#include <errno.h>
+
+#include "fh.h"
+
+static const char rcs_id[] = "@(#) $Id: fh.c,v 1.8 2003/05/28 06:47:23 isani Exp isani $";
+
+/*
+ * -----------------------------
+ * Internal values used by libfh
+ * -----------------------------
+ */
+#define FH_BUFFER_SIZE (128*1024) /* Buffer for copying data between FITS files */
+#define IDX_AUTO_INCR 0.001	/* Auto-increment idx numbers if 0.0 used */
+
+#define FH_RESERVE \
+"COMMENT  Reserved space.  This line can be used to add a new FITS card.         "
+#define FH_RESERVE_LEN 80
+
+#define FH_XTENSION_UNKNOWN 0
+#define FH_XTENSION_IMAGE   1
+#define FH_XTENSION_TABLE   2
+
+#define MAX_SIG_FIGS 62 /* An 80-column FITS card cannot hold more than
+			 * this many significant figures, if a double
+			 * precision float value is printed with an E+
+			 * exponent that could have up to 3 digits too,
+			 * and a decimal place, and a leading - if the
+			 * number is negative.
+			 */
+
+/*
+ * ---------------------------------
+ * Internal structures used by libfh
+ * ---------------------------------
+ */
+typedef struct
+{
+   double idx;		/* Sorting number */
+   char card[FH_CARD_SIZE+1]; /* card[80] is always '\0' so library can use strspn() */
+} FitsCard;
+
+typedef FitsCard* FitsCardPtr;
+/*
+ * The `FitsCard' structure contains the 80 bytes, exactly as they
+ * will appear in the FITS file, along with an "idx" floating point
+ * sorting number (which is removed when writing a file.)
+ */
+
+/*
+ * NOTE: When adding members to this structure, please check
+ * the block of code in fh_file() that checks "if (extname)"
+ * because it needs to decide whether to keep each element of
+ * the structure from the PHU or the EHU.
+ */
+#define HU_MAGIC 0x4855 /* "HU" */
+typedef struct
+{
+   unsigned int magic;	/* Just there to help routines make sure they got a HeaderUnit */
+   FitsCardPtr* hdr;	/* Table of FITS cards */
+   int len;		/* # of cards (excl. END and 1 blank line which will be added) */
+   int pos;		/* Loop counter for fh_first()/fh_next() */
+   int size;		/* # of slots allocated so far (for realloc) */
+   int bitpix;		/* Cached copy of BITPIX keyword */
+   int image_bytes;	/* Cached copy of calculated size of image */
+   int image_bytes_left;/* Used for fh_read_image and fh_write_image */
+   int extensions;	/* Cached copy of NEXTEND keyword (if EXTEND=T) */
+   int xtension;	/* Cached copy of XTENSION (0=none 1=IMAGE 2=TABLE) */
+   double idx_highest;	/* Highest idx number used (for auto-incrementing) */
+   int set_all_units;	/* Should fh_set* functions apply to extensions automatically? */
+   HeaderUnit ehu;	/* Headers for first contained extension (if any) */
+   HeaderUnit next;	/* Headers for next extension (if _this_ is an extension) */
+   HeaderUnit phu;	/* Headers from the primary (if _this_ is an extension) */
+   struct flock fl;	/* File lock, if any. */
+   int fd;		/* -1 if no file associated with this header unit */
+   int fd_locked;	/* -1 if no file has been locked */
+   int fd_to_close;	/* Make sure fh_destroy closes fds opened by fh_file */
+   int fd_header_blocks; /* # of header blocks in the original file (for fh_rewrite) */
+   int file_size;	/* Total size of file for mmap use only */
+   int mmap_count;      /* Number of extensions currently mapped */
+   void* mmap_addr;     /* -1 if file has not been memory-mapped */
+   int reserve;		/* Number of blank cards to reserve (for fh_write) */
+   int reserve_found;	/* Number of reserve cards found in existing header */
+   off_t off_hdrs;	/* Offset in file to this set of cards */
+   off_t off_data;	/* Offset in file to data (or extensions) after the cards */
+   int err_memory;	/* Used by fh_set*() to count memory errors */
+   int err_invalid;	/* Used by fh_set*() to count invalid argument errors */
+   int counting_cards;	/* No, we're not going to Vegas.  When this flag is set, the
+			 * library is in a special mode where fh_[re]write() does nothing
+			 * to a file, but instead prints the number of cards your program
+			 * is going to need to stdout.  This value should be captured and
+			 * summed together with other programs to calculate the value
+			 * to be passed to fh_reserve() by upstream programs which
+			 * actually create the FITS file.
+			 */
+} HeaderUnitStruct;
+
+/*
+ * The following cast is needed because the outside world doesn't
+ * see the internals of a HeaderUnitStruct.  Instead, they pass a
+ * (void*) pointer (HeaderUnit) which must be cast back to the real type.
+ */
+#define FH_HU(hu) (((hu)&&((HeaderUnitStruct*)(hu))->magic==HU_MAGIC)?\
+		(HeaderUnitStruct*)(hu):0)
+
+/*
+ * This table is for converting characters into legal
+ * characters for fits card NAMES.  It is equivalent to:
+ * 
+ * if (isalpha(c) || isdigit(c) || *name=='-' || *name=='_')
+ *   return = toupper(c);
+ * else
+ *   return '_';
+ */
+static char name_chr[256] =
+" _______________"
+"________________"
+" ____________-__"
+"0123456789______"
+"_ABCDEFGHIJKLMNO"
+"PQRSTUVWXYZ_____"
+"_ABCDEFGHIJKLMNO"
+"PQRSTUVWXYZ_____"
+"________________"
+"________________"
+"________________"
+"________________"
+"________________"
+"________________"
+"________________"
+"________________";
+
+#define NAME_CHR(c) (name_chr[(unsigned int)((unsigned char)(c))])
+
+/*
+ * The following is the return type of the Keyword name matching function.
+ * It is used for several thins internally in this library.  The highest
+ * valid return code is the one returned.
+ */
+typedef enum
+{
+   MATCH_FAILED = -1, /* Names do not match */
+   MATCH_SUBSTR = 0,  /* Name1 begins with all the characters in name2 */
+   MATCH_KEYWORD = 1, /* Names are the same for first 8 characters */
+   MATCH_FULL = 2     /* Names are the same (up to 80 chars compared) */
+} match_result;
+
+/*
+ * This library requires a SYSV style sprintf, which returns the number
+ * of bytes added to the string, just like printf and fprintf.
+ */
+#ifdef SUNOS
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+static int sysv_sprintf(char* s, const char* fmt, ...)
+{
+   va_list args;
+#ifdef __STDC__
+   va_start(args, fmt);
+#else
+   va_start(args);
+#endif
+   vsprintf(s, fmt, args);
+   return strlen(s);
+}
+#else
+#define sysv_sprintf sprintf
+#endif
+
+/*
+ * ----------------------------------------------
+ * Internal functions for implementation of libfh
+ * ----------------------------------------------
+ * (These are found at the end of this file.)
+ */
+
+/* Functions that do file operations WITH RETRY: */
+static int write_file(int fd, const void* buf, int len);
+static int read_file(int fd, const void* buf, int len);
+static int seek_file(int fd, off_t off); /* Performs lseek(SEEK_SET) */
+static int fh_lock_file(HeaderUnit hu, int fd, fh_mode mode);
+static int fh_unlock_file(HeaderUnit hu);
+
+static const char* padding_block(int type); /* Buffer of \0's or ' ' */
+static fh_result fix_characters(char* s, int repair); /* Fix bad chars in card */
+static match_result fh_cmp(const char* name1, const char* name2); /* Compares keywords */
+static int fh_compare(const void* a, const void* b); /* Compares `idx' */
+static void fh_sort(HeaderUnit hu); /* Uses fh_compare to sort HeaderUnit */
+
+/* Internal functions used to get and build cards */
+static FitsCardPtr get_hdr(HeaderUnitStruct* list, const char* name, double idx);
+static const char* get_value(HeaderUnitStruct* list, const char* name);
+static double auto_idx(const char* name);
+static char* get_card(HeaderUnitStruct* list, double idx, const char* name,
+		      double idxmatch);
+static void add_comment(char* s, int col, const char* comment);
+static void show_card_count(HeaderUnitStruct* hu) { printf("%d\n", FH_HU(hu)->len); }
+
+/*
+ * ----------------------
+ * Main library functions
+ * ----------------------
+ */
+#ifdef HAVE_FH_VALIDATE
+#include "fh_validate.c"
+#endif
+
+/*
+ * This is just so rcs_id doesn't turn up "unused".
+ * And who knows, maybe someone wants their program to print
+ * this information in debug mode.
+ */
+const char* fh_rcs_version(void) { return rcs_id; }
+
+/*
+ * This gets called any time a new header is set to force things like
+ * image_bytes and extensions to be re-calculated in case a relevant
+ * keyword got changed.  It's also used in fh_create().
+ */
+static void
+invalidate_hu_cache(HeaderUnitStruct* list)
+{
+   list->bitpix = list->image_bytes = list->extensions = list->xtension = -1;
+}
+
+/*
+ * ---------------------------
+ * Error/warning logging stuff
+ * ---------------------------
+ */
+
+/*
+ * Error logger routines take a single string constant parameter.
+ * There is one routine for errors and another for warnings.
+ * The library does not generate any other kinds of messages.
+ */
+
+static char err_buf[1024]; /* Buffer for building error strings */
+
+static void
+dfl_log_error(const char* s) { fprintf(stderr, "error: libfh: %s\n", s); }
+
+static void
+dfl_log_perror(const char* s) { perror(s); }
+
+static void
+dfl_log_warning(const char* s) { fprintf(stderr, "warning: libfh: %s\n", s); }
+/*
+ * Default message handlers print to stderr with the prefix "error:" or "warning:"
+ */
+
+static void
+null_log(const char* s) { if (s) ; }
+/*
+ * It's also possible to pass a NULL to fh_log_xxx() and rely only on the
+ * error returns from the functions themselves.
+ */
+
+static fh_logger_t log_error = dfl_log_error;
+static fh_logger_t log_perror = dfl_log_perror;
+static fh_logger_t log_warning = dfl_log_warning;
+
+/*
+ * Functions to install your own warning/error handlers:
+ */
+void
+fh_log_error(fh_logger_t newlogger)
+{
+   if (newlogger == 0) log_error = null_log;
+   else log_error = newlogger;
+}
+
+void
+fh_log_perror(fh_logger_t newlogger)
+{
+   if (newlogger == 0) log_perror = null_log;
+   else log_perror = newlogger;
+}
+
+void
+fh_log_warning(fh_logger_t newlogger)
+{
+   if (newlogger == 0) log_warning = null_log;
+   else log_warning = newlogger;
+}
+
+HeaderUnit
+fh_create()
+{
+   HeaderUnitStruct* rtn; 
+
+   if (!(rtn = (HeaderUnitStruct*)malloc(sizeof(HeaderUnitStruct))) ||
+       !(memset(rtn, 0, sizeof(HeaderUnitStruct))) ||
+       !(rtn->hdr = (FitsCardPtr*)malloc(sizeof(FitsCardPtr) * 200)))
+   {
+      if (rtn) free(rtn);
+      log_error("out of memory in fh_create()");
+      return 0;
+   }
+   rtn->len = 0;
+   rtn->size = 200;
+   rtn->idx_highest = 1000.000; /* User keywords start a 1000.001 */
+   rtn->fd = -1;
+   rtn->fd_locked = -1; /* Set if file descriptor need to be unlocked */
+   rtn->fd_to_close = -1; /* Set if fh_destroy() will close fd from fh_file */
+   rtn->fd_header_blocks = 0; /* Not valid unless fd >= 0 */
+   rtn->file_size = 0; /* Total size of file from stat() */
+   rtn->mmap_count = 0; /* Not memory mapped initially */
+   rtn->mmap_addr = (void*)-1;
+   rtn->reserve = 0;
+   rtn->reserve_found = 0;
+   rtn->ehu = 0;
+   rtn->next = 0;
+   rtn->off_hdrs = 0;
+   rtn->off_data = 0;
+   rtn->fl.l_type = F_UNLCK;
+   rtn->err_memory = 0;
+   rtn->err_invalid = 0;
+   rtn->counting_cards = 0;
+   invalidate_hu_cache(rtn);
+   rtn->magic = HU_MAGIC; /* Just used as a sanity check */
+   return (HeaderUnit)rtn;
+}
+
+/*
+ * Future fh_set_*() calls apply to any/all EHU's that were
+ * found in the same file.
+ */
+fh_result
+fh_set_all_units(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   off_t off;
+   int ext;
+
+   if (!list)
+   {
+      log_error("Invalid HeaderUnit passed to fh_set_all_units()");
+      return FH_INVALID;
+   }
+
+   if (list->fd == -1)
+   {
+      log_error("fh_set_all_units only applies to HeaderUnits "
+		"read from a file or file descriptor");
+      return FH_INVALID;
+   }
+
+   /*
+    * Save current file position, make sure all extensions are
+    * cached, and then restore the current file position.  If this
+    * is skipped, then the other fh_set() functions would have the
+    * unexpected side-effect of moving the file position around
+    * they happen to cause the first access to an EHU.
+    */
+   off = lseek(list->fd, 0, SEEK_CUR);
+   for (ext = 1; ext <= fh_extensions(list); ext++)
+   {
+      if (fh_ehu(hu, ext) == 0)
+	 return FH_NOT_FOUND;
+   }
+   seek_file(list->fd, off);
+
+   list->set_all_units = 1;
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_destroy(HeaderUnit hu)
+{
+   fh_result rtn = FH_SUCCESS;
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (!list)
+   {
+      log_error("Invalid HeaderUnit passed to fh_destroy()");
+      return FH_INVALID;
+   }
+
+   if (fh_unlock_file(hu) == -1)
+      rtn = FH_IN_ERRNO;
+
+   if (list->fd_to_close != -1 &&
+       close(list->fd_to_close) != 0)
+   {
+      log_perror("close for fh_file() failed");
+      rtn = FH_IN_ERRNO;
+   }
+
+   while (list->len)
+      free(list->hdr[--list->len]);
+   free(list->hdr);
+
+   if (list->ehu) fh_destroy(list->ehu);
+   if (list->next) fh_destroy(list->next);
+
+   free(list);
+   return rtn;
+}
+
+fh_result
+fh_count_cards(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (!list)
+   {
+      log_error("Invalid HeaderUnit passed to fh_count_cards()");
+      return FH_INVALID;
+   }
+   list->counting_cards++;
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_file(HeaderUnit hu, const char* filespec, fh_mode mode)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   char* extname = 0;
+   char* filename = 0;
+   struct stat st_buf;
+   int open_mode = 0, fd;
+   fh_result rtn = FH_SUCCESS;
+
+   if (!list)
+   {
+      log_error("Invalid HeaderUnit passed to fh_file()");
+      return FH_INVALID;
+   }
+
+   if (list->len)
+   {
+      log_error("fh_file() requires an empty HeaderUnit");
+      return FH_BAD_VALUE;
+   }
+
+   if (filespec && !strcmp(filespec, FH_COUNT_CARDS))
+   {
+      fh_count_cards(hu);
+      return FH_SUCCESS;
+   }
+
+   switch (mode)
+   {
+      case FH_FILE_RDONLY:
+      case FH_FILE_RDONLY_NOLOCK: open_mode = O_RDONLY; break;
+      case FH_FILE_RDWR:
+      case FH_FILE_RDWR_NOLOCK: open_mode = O_RDWR; break;
+      default:
+	 log_error("Invalid `mode' argument passed to fh_file()");
+	 return FH_INVALID;
+   }
+
+   /*
+    * If no filename, or if the filespec is "-", try to read from stdin.
+    */
+   if (!filespec || !strcmp(filespec, "-"))
+   {
+      if (isatty(STDIN_FILENO))
+      {
+	 log_error("cannot read from a terminal");
+	 return FH_IS_TTY;
+      }
+      if ((rtn = fh_read(hu, STDIN_FILENO, FH_AUTO)) != FH_SUCCESS)
+      {
+	 if (rtn != FH_END_OF_FILE)
+	    log_error("failed to read FITS header from stdin");
+	 return rtn;
+      }
+      return FH_SUCCESS; /* Successfully read header from stdin. */
+   }
+
+   /*
+    * Next test is to see if filespec, exactly as given, exists
+    * as a file (even including '[' ']' or other characters.)
+    */
+   if (stat(filespec, &st_buf) == 0)
+   {
+      if (S_ISDIR(st_buf.st_mode))
+      {
+	 sprintf(err_buf, "`%.900s' is a directory", filespec);
+	 log_error(err_buf);
+	 return FH_IS_DIR;
+      }
+      filename = strdup(filespec);
+   }
+   else
+   {
+      char* bracket_open = 0;
+      char* bracket_close = 0;
+
+      if (!(filename = (char*)malloc(strlen(filespec)*2 + 32)))
+      {
+	 log_error("out of memory in fh_file()");
+	 return FH_NO_MEMORY;
+      }
+      strcpy(filename, filespec);
+
+      /*
+       * Extract "[extname]" if present in filespec.
+       */
+      if ((bracket_open = strchr(filename, '[')) != 0 &&
+	  (bracket_close = strchr(bracket_open, ']')) != 0)
+      {
+	 *bracket_open++ = *bracket_close++ = '\0';
+	 extname = strdup(bracket_open);
+	 strcat(filename, bracket_close);
+      }
+
+      /*
+       * Make sure the filename contains ".fits" for the first test.
+       */
+      if (strlen(filename) <= 5 ||
+	  strcmp(filename + strlen(filename) - 5, ".fits"))
+	 strcat(filename, ".fits");
+
+      /*
+       * Now strip off the ".fits" and try that next.
+       */
+      if (stat(filename, &st_buf) != 0)
+      {
+	 filename[strlen(filename) - 5] = '\0';
+	 if (stat(filename, &st_buf) != 0)
+	 {
+	    log_perror(filespec);
+	    return FH_IN_ERRNO;
+	 }
+      }
+
+      if (S_ISDIR(st_buf.st_mode))
+      {
+	 const char* basename;
+
+	 if (!extname)
+	 {
+	    sprintf(err_buf, "`%.900s' is a directory", filespec);
+	    log_error(err_buf);
+	    return FH_IS_DIR;
+	 }
+
+	 /*
+	  * Get the part of filename without the path elements.
+	  */
+	 basename = strrchr(filename, '/');
+	 if (basename) basename++;
+	 else basename = filename;
+	 strcpy(filename + strlen(filename) + 1, basename);
+	 filename[strlen(filename)] = '/';
+
+	 if (!strncmp(extname, "chip", 4)) strcat(filename, extname + 4);
+	 else if (!strncmp(extname, "amp", 3)) strcat(filename, extname + 3);
+	 else if (!strncmp(extname, "im", 2)) strcat(filename, extname + 2);
+	 else strcat(filename, extname);
+	 strcat(filename, ".fits");
+	 free(extname); extname = 0;
+      }
+   }
+
+   /*
+    * Now try to open filename.
+    */
+   if ((fd = open(filename, open_mode, 0)) == -1)
+   {
+      log_perror(filename);
+      free(filename);
+      if (extname) free(extname);
+      return FH_IN_ERRNO;
+   }
+   free(filename);
+   list->fd_to_close = fd;
+   list->file_size = st_buf.st_size;
+
+   if (mode == FH_FILE_RDONLY || mode == FH_FILE_RDWR)
+   {
+      if (fh_lock_file(hu, fd, mode) == -1)
+	 log_perror("failed to lock file");
+   }
+
+   /*
+    * Read the (first) header unit from the file.
+    */
+   if ((rtn = fh_read(hu, fd, FH_AUTO)) != FH_SUCCESS)
+   {
+      if (extname) free(extname);
+      return rtn;
+   }
+
+   if (mode == FH_FILE_RDONLY)
+   {
+      if (fh_extensions(hu))
+      {
+	 /* === Read in the extension headers now, or just leave the file locked?
+	  * === For now, I'm opting to leave the whole file locked.
+	  */
+      }
+      else
+      {
+	 if (fh_unlock_file(hu) == -1)
+	    log_perror("failed to unlock file");
+      }
+   }
+
+   /*
+    * If an extension was given, try to locate that extension within
+    * the MEF file.  What happens here is a little gross.
+    */
+   if (extname)
+   {
+      HeaderUnit ehu;
+      fh_bool inherit;
+
+      if ((ehu = fh_ehu_by_extname(hu, extname)) == 0)
+      {
+	 sprintf(err_buf, "extension `%.900s' not found", extname);
+	 log_error(err_buf);
+	 free(extname);
+	 return FH_NOT_FOUND;
+      }
+      free(extname);
+      /*
+       * Extension was found, but the caller expects to find the keywords
+       * in `hu' which they passed in, not in `ehu'.  So the next step is
+       * either to replace or add to the cards already in `hu' to make it
+       * look like the extension.  Replace or add depends on INHERIT:
+       */
+      if (fh_get_bool(ehu, "INHERIT", &inherit) != FH_SUCCESS ||
+	  inherit == FH_FALSE)
+      {
+	 /*
+	  * Do not inherit keywords from the parent.
+	  */
+	 while (list->len)
+	    free(list->hdr[--list->len]);
+      }
+      /*
+       * In any case, do not inherit EXTEND and NEXTEND keywords.
+       */
+      fh_remove(hu, "EXTEND");
+      fh_remove(hu, "NEXTEND");
+      invalidate_hu_cache(list);
+      /*
+       * Change `hu' into the EHU by copying the following:
+       */
+      list->off_hdrs = FH_HU(ehu)->off_hdrs;
+      list->off_data = FH_HU(ehu)->off_data;
+      list->fd_header_blocks = FH_HU(ehu)->fd_header_blocks;
+      /*
+       * Now merge all the cards from the EHU into `hu'.
+       */
+      fh_merge(hu, ehu);
+      fh_destroy(list->ehu);
+      list->ehu = 0;
+   }
+
+   return FH_SUCCESS;
+}
+
+int
+fh_file_desc(HeaderUnit hu)
+{
+   return FH_HU(hu)->fd;
+}
+
+const char*
+fh_next(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (!list || !list->len) return 0;
+   if (list->pos < list->len)
+      return list->hdr[list->pos++]->card;
+   return 0;
+}
+
+const char*
+fh_first(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (!list) return 0;
+   list->pos = 0;
+   return fh_next(hu);
+}
+
+double
+fh_idx(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (!list || !list->len) return 0;
+   if (list->pos > list->len || list->pos < 1) return 0;
+   return list->hdr[list->pos-1]->idx;
+}
+
+void
+fh_set_str(HeaderUnit hu, double idx,
+	   const char* name, const char* value, const char* comment)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   char* s;
+   int col = FH_NAME_SIZE;
+
+   if (!list || !name || !value)
+   {
+      log_error("Invalid argument passed to fh_set_str()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   /*
+    * First set this value for all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+	 fh_set_str(fh_ehu(hu, ext), idx, name, value, comment);
+   }
+
+   s = get_card(list, idx, name, 0); /* Replace any other with same name */
+   if (!s) return; /* malloc problem; will be caught later by fh_rewrite() */
+   s[col++] = '=';
+   s[col++] = ' ';
+   s[col++] = '\'';
+   while (col < 78 && *value)
+   {
+      if (*value < ' ' || *value >= 127)
+      {
+	 sprintf(err_buf, "illegal character %x in string FITS card", *value++);
+	 log_warning(err_buf);
+	 s[col++] = '_';
+      }
+      else if (*value == '\'')
+      {
+	 s[col++] = '\'';
+	 s[col++] = '\'';
+	 value++;
+      }
+      else
+      {
+	 s[col++] = *value++;
+      }
+   }
+   /* col could be as high as 79 now, if the last char was a '' */
+
+   while (col < 19)
+      s[col++] = ' '; /* Old FITS standard wants this :-/ */
+
+   s[col++] = '\'';
+
+   add_comment(s, col, comment);
+}
+
+void
+fh_set_com(HeaderUnit hu, double idx,
+	   const char* name, const char* comment)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int col = FH_NAME_SIZE;
+   char* s;
+
+   if (!list || !name || !comment)
+   {
+      log_error("invalid argument to fh_set_com()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   /*
+    * First set this value for all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+	 fh_set_com(fh_ehu(hu, ext), idx, name, comment);
+   }
+
+   s = get_card(list, idx, name, idx); /* Only _replace_ if idx matches */
+   if (!s) return; /* malloc problem; will be caught later by fh_rewrite() */
+   while (col < FH_CARD_SIZE && *comment)
+   {
+      if (*comment)
+      {
+	 if (*comment < ' ' || *comment >= 127)
+	 {
+	    sprintf(err_buf, "illegal character %x in comment FITS card", *comment++);
+	    log_warning(err_buf);
+	    s[col++] = '_';
+	 }
+	 else
+	 {
+	    s[col++] = *comment++;
+	 }
+      }
+      else
+	 s[col++] = ' ';
+   }
+}
+
+void
+fh_set_int(HeaderUnit hu, double idx,
+	   const char* name, int value, const char* comment)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int col = FH_NAME_SIZE;
+   char* s;
+
+   if (!list || !name)
+   {
+      log_error("invalid argument to fh_set_int()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   invalidate_hu_cache(list); /* In case this changed BITPIX or NAXIS */
+
+   /*
+    * First set this value for all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+	 fh_set_int(fh_ehu(hu, ext), idx, name, value, comment);
+   }
+
+   s = get_card(list, idx, name, 0); /* Replace any other with same name */
+   if (!s) return; /* malloc problem; will be caught later by fh_rewrite() */
+   s[col++] = '=';
+   s[col++] = ' ';
+
+   col += sysv_sprintf(s + col, "%20d", value);
+   s[col] = ' '; /* Remove the \0 that sprintf added (add_comment overwrites it too) */
+
+   add_comment(s, col, comment);
+}
+
+void
+fh_set_flt(HeaderUnit hu, double idx,
+	   const char* name, double value,
+	   int significant_digits, const char* comment)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int col = FH_NAME_SIZE;
+   char* s;
+
+   if (!list || !name)
+   {
+      log_error("invalid argument to fh_set_flt()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   /*
+    * Sanity-check the significant_digits parameter and silently
+    * limit it to the size of the FITS card to prevent buffer
+    * overruns.  This is probably somewhat C-library dependent,
+    * and certainly dependent on the range of exponents that can
+    * occur in the floating point value being printed.  It assumes
+    * the optional "E+<exponent>" which may get printed will be at
+    * most 3 digits.  In that case, 62 significant digits and the
+    * space (or minus sign) in front of the number plus the decimal
+    * point will result in using all but the last column in the 80
+    * character FITS card.
+    */
+   if (significant_digits < 1 || significant_digits > MAX_SIG_FIGS)
+      significant_digits = MAX_SIG_FIGS;
+
+   /*
+    * First set this value for all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+	 fh_set_flt(fh_ehu(hu, ext), idx, name, value, significant_digits, comment);
+   }
+
+   s = get_card(list, idx, name, 0); /* Replace any other with same name */
+   if (!s) return; /* malloc problem; will be caught later by fh_rewrite() */
+   s[col++] = '=';
+   s[col++] = ' ';
+   col += sysv_sprintf(s + col, "%# 20.*G", significant_digits, value);
+   s[col] = ' '; /* Remove the \0 that sprintf added for us */
+
+   add_comment(s, col, comment);
+}
+
+void
+fh_set_pfl(HeaderUnit hu, double idx,
+	   const char* name, double value,
+	   int decimal_places, const char* comment)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int col = FH_NAME_SIZE;
+   char* s;
+   double i, hival = 0;
+
+   if (!list || !name)
+   {
+      log_error("invalid argument to fh_set_flt()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   /*
+    * If the value is too big (or too negative) to be expressed
+    * without exponent with the number of columns that a FITS card
+    * allows, fall back to the other way of formatting floats.
+    * Also do this if decimal_places is more than MAX_SIG_FIGS.
+    * The alternate float-formatting routine fh_set_flt() will be
+    * used at the limit of MAX_SIG_FIGS and may automatically
+    * switch to E-notation, even if fh_set_pfl() was used.
+    * This is necessary to prevent buffer overflows and potential
+    * memory corruption when very large magnitude numbers get
+    * passed to fh_set_pfl().
+    *
+    * For performance reasons, the first few cases are pre-calculated
+    * in a switch statement.  For more than 9 decimal places, the
+    * CPU will have to do a bunch of divide by 10's for each value
+    * passed to fh_set_pfl() to figure out if it is going to fit or
+    * not.  Note that we don't want to suck in a dependency on libm
+    * and use log10().  We also didn't want to just switch to snprintf()
+    * because we were not sure if all the systems we might want to use
+    * libfh on all have that function.  (Plus, snprintf would probably
+    * corrupt and truncate the number.  This solution does not.)
+    */
+   switch (decimal_places)
+   {
+      case 0: hival = 1.0E66; break;
+      case 1: hival = 1.0E65; break;
+      case 2: hival = 1.0E64; break;
+      case 3: hival = 1.0E63; break;
+      case 4: hival = 1.0E62; break;
+      case 5: hival = 1.0E61; break;
+      case 6: hival = 1.0E60; break;
+      case 7: hival = 1.0E59; break;
+      case 8: hival = 1.0E58; break;
+      case 9: hival = 1.0E57; break;
+      default:
+      {
+	 if (decimal_places < MAX_SIG_FIGS)
+	 {
+	    hival = 1.0E56;
+	    for (i = 10; i < decimal_places; i++)
+	       hival /= 10.;
+	 }
+      }
+   }
+   if (value >= hival || value <= -hival)
+   {
+      fh_set_flt(hu, idx, name, value, MAX_SIG_FIGS, comment);
+      return;
+   }
+
+   /*
+    * First set this value for all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+	 fh_set_pfl(fh_ehu(hu, ext), idx, name, value, decimal_places, comment);
+   }
+
+   s = get_card(list, idx, name, 0); /* Replace any other with same name */
+   if (!s) return; /* malloc problem; will be caught later by fh_rewrite() */
+   s[col++] = '=';
+   s[col++] = ' ';
+   col += sysv_sprintf(s + col, "%# 20.*f", decimal_places, value);
+   s[col] = ' '; /* Remove the \0 that sprintf added for us */
+
+   add_comment(s, col, comment);
+}
+
+void
+fh_set_val(HeaderUnit hu, double idx,
+	   const char* name, const char* value, const char* comment)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int col = FH_NAME_SIZE;
+   int len = strlen(value);
+   char* s;
+   char* endptr;
+
+   if (!list || !name || !value)
+   {
+      log_error("invalid argument to fh_set_val()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   /*
+    * If the value is not boolean or numeric, save it as a string.
+    */
+   strtod(value, &endptr);
+   if (strcmp(value, "T") &&
+       strcmp(value, "F") &&
+       (!endptr || *endptr!='\0'))
+   {
+      /*
+       * Strip quotes if needed.
+       */
+      if (*value == '\'' && strlen(value) > 1 &&
+	  value[strlen(value) - 1] == '\'')
+      {
+	 char* newval = strdup(value + 1);
+
+	 newval[strlen(newval) - 1] = '\0';
+	 fh_set_str(hu, idx, name, newval, comment);
+	 return;
+      }
+      fh_set_str(hu, idx, name, value, comment);
+      return;
+   }
+
+   /*
+    * First set this value for all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+	 fh_set_val(fh_ehu(hu, ext), idx, name, value, comment);
+   }
+
+   if (len > 70)
+   {
+      sprintf(err_buf, "truncating value for [%.8s]", name);
+      log_warning(err_buf);
+   }
+
+   s = get_card(list, idx, name, 0); /* Replace any other with same name */
+   if (!s) return; /* malloc problem; will be caught later by fh_rewrite() */
+   s[col++] = '=';
+   s[col++] = ' ';
+   while (len < 20) { s[col++] = ' '; len++; } /* Right justify */
+   col += sysv_sprintf(s + col, "%.70s", value);
+   if (col < FH_CARD_SIZE)
+   {
+      s[col] = ' '; /* Fix the \0 that sprintf added for us */
+      add_comment(s, col, comment);
+   }
+}
+
+void
+fh_set_bool(HeaderUnit hu, double idx,
+	    const char* name, fh_bool value, const char* comment)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int col = FH_NAME_SIZE;
+   char* s;
+
+   if (!list || !name)
+   {
+      log_error("invalid argument to fh_set_bool()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   /*
+    * First set this value for all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+	 fh_set_bool(fh_ehu(hu, ext), idx, name, value, comment);
+   }
+
+   s = get_card(list, idx, name, 0); /* Replace any other with same name */
+   if (!s) return; /* malloc problem; will be caught later by fh_rewrite() */
+   s[col++] = '=';
+   while (col < 29) s[col++] = ' ';
+   s[col++] = value?'T':'F';
+
+   add_comment(s, col, comment);
+}
+
+void
+fh_set_card(HeaderUnit hu, double idx, const char* card)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   const char* name = 0;
+   char* s;
+   int len;
+
+   if (!list || !card)
+   {
+      log_error("invalid argument to fh_set_card()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   len = strlen(card);
+   if (len > FH_CARD_SIZE)
+   {
+      log_error("card too long for fh_set_card()");
+      if (list) list->err_invalid++;
+      return;
+   }
+
+   /*
+    * First set this value for all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+	 fh_set_card(fh_ehu(hu, ext), idx, card);
+   }
+
+   if (len > FH_NAME_SIZE && card[FH_NAME_SIZE] == '=') name = card;
+   s = get_card(list, idx, name, 0); /* Replace any other with same name */
+   if (!s) return; /* malloc problem; will be caught later by fh_rewrite() */
+   memcpy(s, card, len);
+}
+
+fh_result
+fh_get_bool(HeaderUnit hu, const char* name, fh_bool* value)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   const char* p;
+
+   if (!list || !name || !value) return FH_INVALID; /* Bad arguments */
+   if (!(p = get_value(list, name))) return FH_NOT_FOUND;
+   if (p[0] == 'F' && p[1] == ' ') { *value=FH_FALSE; return FH_SUCCESS; }
+   if (p[0] == 'T' && p[1] == ' ') { *value=FH_TRUE; return FH_SUCCESS; }
+   return FH_BAD_VALUE; /* Card is not T or F? */
+}
+
+fh_result
+fh_get_int(HeaderUnit hu, const char* name, int* value)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   char* endptr;
+   const char* p;
+
+   if (!list || !name || !value) return FH_INVALID; /* Bad arguments */
+   if (!(p = get_value(list, name))) return FH_NOT_FOUND;
+   *value = (int)strtol(p, &endptr, 0);
+   if (endptr && *endptr==' ') return FH_SUCCESS;
+   return FH_BAD_VALUE; /* Card is not an integer? */
+}
+
+fh_result
+fh_get_flt(HeaderUnit hu, const char* name, double* value)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   char* endptr;
+   const char* p;
+
+   if (!list || !name || !value) return FH_INVALID; /* Bad arguments */
+   if (!(p = get_value(list, name))) return FH_NOT_FOUND;
+   *value = strtod(p, &endptr);
+   if (endptr && *endptr==' ') return FH_SUCCESS;
+   return FH_BAD_VALUE; /* Card is not an valid double? */
+}
+
+fh_result
+fh_get_str(HeaderUnit hu, const char* name, char* value, int maxlen)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   fh_result rtn = FH_SUCCESS;
+   const char* p;
+   char* valp = value;
+   int len = 0;
+   int free_format = 0;
+
+   if (!list || !name || !value || !maxlen) return FH_INVALID;
+   if (!(p = get_value(list, name))) return FH_NOT_FOUND;
+   if (*p++!='\'') return FH_BAD_VALUE; /* Not a string */
+   while (1)
+   {
+      if (!*p) { rtn=FH_BAD_VALUE; break; } /* Unterminated string */
+      if (*p == '\'')
+      {
+	 if (p[1] == '\'') p++;	/* Literal single quote character in string? */
+	 else break;		/* Or actual end of string? */
+      }
+      if (++len > maxlen) { rtn=FH_BAD_VALUE; break; } /* value buf too small */
+      *valp++ = *p++;
+   }
+   /*
+    * Make sure there are no other characters (other than space) between
+    * the end of string and the start of the comment field.
+    */
+   if (*p == '\'')
+   {
+      /*
+       * Check for strings which are not in "fixed" format.
+       */
+      if (len < 8) free_format = 1;
+      while (*(++p) == ' ');
+      if (*p != '\0' && *p != '/') rtn=FH_BAD_VALUE;
+   }
+   while (len && *(valp - 1)==' ')
+   { valp--; len--; } /* Trim white space off end, but not beginning */
+   *valp++ = '\0';
+   if (free_format && rtn == FH_SUCCESS)
+   {
+      static int warned = 0;
+      int tmp;
+      
+      if (!warned)
+      {
+	 log_warning("converting strings to \"fixed\" format");
+	 warned = 1;
+      }
+      tmp = list->set_all_units; /* === Hack to prevent EHU's from being affected. */
+      list->set_all_units = 0;
+      fh_set_str(hu, 0, name, value, 0);
+      list->set_all_units = tmp;
+   }
+   return rtn;
+}
+
+fh_result
+fh_search(HeaderUnit hu, const char* name, double* idx)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   FitsCardPtr hdr;
+
+   if (!list || !name) return FH_INVALID;
+   hdr = get_hdr(list, name, 0);
+   if (!hdr) return FH_NOT_FOUND;
+   if (idx) *idx = hdr->idx;
+   return FH_SUCCESS;
+}
+
+double
+fh_idx_after(HeaderUnit hu, const char* name)
+{
+   double idx;
+
+   if (fh_search(hu, name, &idx) == FH_SUCCESS)
+      return idx + 0.00001;
+   else
+      return 0.0;
+}
+
+double
+fh_idx_before(HeaderUnit hu, const char* name)
+{
+   double idx;
+
+   if (fh_search(hu, name, &idx) == FH_SUCCESS)
+      return idx - 0.00001;
+   else
+      return 0.0;
+}
+
+fh_result
+fh_remove(HeaderUnit hu, const char* name)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   double idx = 0.; /* For future use? */
+   int i;
+
+   if (!list || !name) return FH_INVALID;
+
+   for (i = 0; i < list->len; i++)
+   {
+      if (fh_cmp(list->hdr[i]->card, name)>=MATCH_KEYWORD &&
+	  (idx == 0 || list->hdr[i]->idx == idx))
+      {
+	 free(list->hdr[i]);
+	 list->hdr[i] = 0;
+	 /*
+	  * Shift the rest of the list (this only has to copy pointers)
+	  */
+	 for (i++ ; i < list->len; i++)
+	    list->hdr[i-1] = list->hdr[i];
+	 list->len--;
+	 return FH_SUCCESS;
+      }
+   }
+   return FH_NOT_FOUND;
+}
+
+int
+fh_extensions(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   fh_bool extend;
+   int nextend;
+
+   if (!list)
+   {
+      log_error("invalid argument to fh_extensions()");
+      return 0;
+   }
+   if (list->extensions != -1)
+      return list->extensions;
+   if (fh_get_bool(list, "EXTEND", &extend)!=FH_SUCCESS ||
+       fh_get_int(list, "NEXTEND", &nextend)!=FH_SUCCESS)
+      nextend = 0;
+
+   list->extensions = nextend;
+   return nextend;
+}
+
+int
+fh_header_blocks(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int rtn;
+
+   if (!list)
+   {
+      log_error("invalid argument to fh_header_blocks()");
+      return 0;
+   }
+
+   /*
+    * Calculate the minimum number of header blocks required to store
+    * all of the keywords plus an END line.
+    */
+   rtn = list->len + 1; /* +1 is for the END line */
+   if (list->reserve)
+   {
+      /*
+       * If reserve keywords are requested, the header is written with
+       * special COMMENT lines and the way END is written is also changed:
+       * the END line is never placed in the very last slot.  Instead, it
+       * always goes in the second-to-last slot (to avoid triggering bugs
+       * in other FITS reading software that may have a problem with this
+       * boundary condition.)
+       */
+      rtn +=
+	 list->reserve + 1; /* +1 is for the extra blank line at the end */
+   }
+   rtn = (rtn * FH_CARD_SIZE + FH_BLOCK_SIZE - 1) / FH_BLOCK_SIZE;
+
+   /*
+    * Bump size up to previous size.  It is possible to remove enough
+    * keywords that the header shrinks by a block, but we never actually
+    * write back a smaller header (for one thing, fh_rewrite() wouldn't
+    * work at all if we did.)
+    */
+   if (rtn < list->fd_header_blocks)
+      rtn = list->fd_header_blocks;
+
+   return rtn;
+}
+
+static int
+fh_xtension(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   if (list->xtension == -1)
+   {
+      char tmp[80];
+      if (fh_get_str(list, "XTENSION", tmp, sizeof(tmp)) != FH_SUCCESS)
+	 list->xtension = FH_XTENSION_UNKNOWN;
+      else if (!strcmp(tmp, "IMAGE"))
+	 list->xtension = FH_XTENSION_IMAGE;
+      else if (!strcmp(tmp, "TABLE"))
+	 list->xtension = FH_XTENSION_TABLE;
+      else
+	 list->xtension = FH_XTENSION_UNKNOWN;
+   }
+   return list->xtension;
+}
+
+static int
+fh_bitpix(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (list->bitpix == -1)
+      if (fh_get_int(list, "BITPIX", &list->bitpix)!=FH_SUCCESS)
+	 list->bitpix = -1;
+
+   return list->bitpix;
+}
+
+static int
+fh_bytepix(HeaderUnit hu)
+{
+   switch (fh_bitpix(hu))
+   {
+      case 8:
+      case -8: return 1; break;
+      case 16:
+      case -16: return 2; break;
+      case 32:
+      case -32: return 4; break;
+      case 64:
+      case -64: return 8; break;
+      default:
+      {
+	 log_error("invalid or missing BITPIX card");
+	 return 0;
+      }
+   }
+}
+
+int
+fh_image_bytes(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int naxis = 0;
+   int n_bytes = 1;
+   int tmp;
+
+   if (!list)
+   {
+      log_error("invalid argument to fh_image_bytes()");
+      return 0;
+   }
+   if (list->image_bytes != -1)
+      return list->image_bytes;
+
+   if (fh_get_int(list, "NAXIS", &naxis)!=FH_SUCCESS || naxis<1 || naxis>999)
+      return 0;
+
+   while (naxis)
+   {
+      char naxis_hdr[9];
+
+      sprintf(naxis_hdr, "NAXIS%d", naxis);
+      if (fh_get_int(list, naxis_hdr, &tmp)!=FH_SUCCESS || tmp < 1)
+      {
+	 sprintf(err_buf, "missing %.900s card", naxis_hdr);
+	 log_error(err_buf);
+	 return 0;
+      }
+      n_bytes *= tmp;
+      naxis--;
+   }
+   n_bytes *= fh_bytepix(hu);
+   /*
+    * The following allows BINTABLE extensions to be copied correctly,
+    * even though libfh does not provide support for interpreting them.
+    */
+   if (fh_get_int(list, "PCOUNT", &tmp) == FH_SUCCESS)
+      n_bytes += tmp;
+   list->image_bytes = n_bytes;
+   list->image_bytes_left = n_bytes;
+   return n_bytes;
+}
+
+int
+fh_image_blocks(HeaderUnit hu)
+{
+   return ((fh_image_bytes(hu) + FH_BLOCK_SIZE - 1) / FH_BLOCK_SIZE);
+}
+
+fh_result
+fh_merge(HeaderUnit hu, const HeaderUnit source_)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   const HeaderUnitStruct* source = FH_HU(source_);
+   int i = 0;
+   char* s;
+
+   if (!list || !source)
+   {
+      log_error("invalid argument passed to fh_merge()");
+      return FH_INVALID;
+   }
+
+   while (i < source->len)
+   {
+      double idxmatch;
+      char name[9] = "        ";
+
+      /*
+       * No `=' in the FITS card?  In that case, create a new entry
+       * unless the idx values match exactly.  Otherwise, leave idxmatch
+       * set to 0, which tells get_card() to re-use an old card if
+       * it had the same name.
+       */
+      if (source->hdr[i]->card[8] != '=' ||
+	  !memcmp(source->hdr[i]->card, "COMMENT ", 8) ||
+	  !memcmp(source->hdr[i]->card, "HISTORY ", 8) ||
+	  !memcmp(source->hdr[i]->card, "        ", 8))
+	 idxmatch = source->hdr[i]->idx;
+      else
+	 idxmatch = 0.;
+      memcpy(name, source->hdr[i]->card, 8);
+      s = get_card(list, source->hdr[i]->idx, name, idxmatch);
+      if (!s) return FH_NO_MEMORY;
+      memcpy(s, source->hdr[i]->card, FH_CARD_SIZE);
+      i++;
+   }
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_read_keyword_buffer(HeaderUnit hu, const char* buffer, double idx, int fast)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   char* s;
+   int cards = FH_BLOCK_SIZE/FH_CARD_SIZE;
+
+   if (!list || !buffer)
+   {
+      log_error("invalid argument passed to fh_read_keyword_buffer()");
+      return FH_INVALID;
+   }
+
+   while (cards)
+   {
+      s = get_card(list, idx, 0, 0); /* 0, 0 means no check for existing */
+      if (!s) return FH_NO_MEMORY;
+      idx = 0.0; /* Switch to auto-increment mode. */
+
+      do
+      {
+	 memcpy(s, buffer, FH_CARD_SIZE);
+	 buffer += FH_CARD_SIZE;
+	 cards --;
+	 if (!fast && !memcmp(s, FH_RESERVE, FH_RESERVE_LEN))
+	 {
+	    list->reserve_found++;
+	    continue; /* Skip FH_RESERVE lines */
+	 }
+	 break;
+      } while (1);
+
+      if (!fast && fix_characters(s, /*repair=*/0) != FH_SUCCESS)
+      {
+	 sprintf(err_buf, "FITS format error in card [%.80s]", s);
+	 log_error(err_buf);
+	 return FH_BAD_VALUE;
+      }
+      if (!memcmp(s, "END     ", 8))
+      {
+	 double idx_auto;
+	 int i;
+
+	 free(list->hdr[--list->len]); /* Remove the END */
+	 while (!fast && list->len &&
+		strspn(list->hdr[list->len-1]->card, " ")==FH_CARD_SIZE)
+	    free(list->hdr[--list->len]); /* Remove trailing blank lines
+					   * and FH_RESERVE lines
+					   */
+
+	 /*
+	  * fh_read() is the only case where get_card() is called without
+	  * knowing what the keyword name is.  In order to enforce proper
+	  * `idx' numbers for the reserved keywords, one pass through all
+	  * the entries must be made here to correct the values.
+	  */
+	 if (!fast)
+	 {
+	    for (i = 0; i < list->len; i++)
+	    {
+	       idx_auto = auto_idx(list->hdr[i]->card);
+	       if (idx_auto < 10.0) list->hdr[i]->idx = idx_auto;
+	    }
+	    /* === Also do padding check if !fast? */
+	 }
+	 return FH_END_OF_FILE; /* This block included END. */
+      }
+   }
+   return FH_SUCCESS; /* More to read... */
+}
+
+fh_result
+fh_read(HeaderUnit hu, int fd, double idx)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int bytes_read = 0;
+   char* s;
+   fh_result rtn = FH_SUCCESS;
+
+   if (!list)
+   {
+      log_error("invalid argument passed to fh_read()");
+      return FH_INVALID;
+   }
+
+   list->fd = fd;
+   list->off_hdrs = lseek(fd, 0, SEEK_CUR);
+   list->off_data = (off_t)-1; /* Gets set before returning FH_SUCCESS */
+   
+   while (1)
+   {
+      s = get_card(list, idx, 0, 0); /* 0, 0 means no check for existing */
+      if (!s) return FH_NO_MEMORY;
+      idx = 0.0; /* Switch to auto-increment mode. */
+
+      /* Get the next (non-reserve-space) FITS card */
+      do
+      {
+	 switch (read_file(fd, s, FH_CARD_SIZE))
+	 {
+	    case -1:
+	    {
+	       log_perror("failed to read FITS card");
+	       return FH_IN_ERRNO;
+	       break;
+	    }
+	    case 0:
+	    {
+	       /*
+		* For use in programs like fitspipe, it can be
+		* expected to have end of file occur, but not
+		* if some of the header was already found (i.e.,
+		* an error message is only printed if the EOF
+		* occurs in the middle of a header read, not at
+		* the beginning.)  Either way, FH_END_OF_FILE is
+		* returned so the caller can do with that as
+		* they wish.
+		*/
+	       if (bytes_read != 0)
+		  log_error("unexpected end of file");
+	       return FH_END_OF_FILE;
+	       break;
+	    }
+	    case FH_CARD_SIZE: break; /* success */
+	    default:
+	    {
+	       log_error("short read on FITS card");
+	       return FH_BAD_VALUE;
+	    }
+	 }
+	 bytes_read += FH_CARD_SIZE;
+	 if (!memcmp(s, FH_RESERVE, FH_RESERVE_LEN))
+	 {
+	    list->reserve_found++;
+	    continue; /* Skip FH_RESERVE lines */
+	 }
+	 break;
+      } while (1);
+
+      if (fix_characters(s, /*repair=*/0) != FH_SUCCESS)
+      {
+	 sprintf(err_buf, "FITS format error in card [%.80s]", s);
+	 log_error(err_buf);
+	 rtn = FH_BAD_VALUE;
+      }
+      if (!memcmp(s, "END     ", 8))
+      {
+	 int first_padding = 1;
+	 double idx_auto;
+	 int i;
+
+	 free(list->hdr[--list->len]); /* Remove the END */
+	 while (list->len &&
+		strspn(list->hdr[list->len-1]->card, " ")==FH_CARD_SIZE)
+	    free(list->hdr[--list->len]); /* Remove trailing blank lines
+					   * and FH_RESERVE lines
+					   */
+
+	 /*
+	  * fh_read() is the only case where get_card() is called without
+	  * knowing what the keyword name is.  In order to enforce proper
+	  * `idx' numbers for the reserved keywords, one pass through all
+	  * the entries must be made here to correct the values.
+	  */
+	 for (i = 0; i < list->len; i++)
+	 {
+	    idx_auto = auto_idx(list->hdr[i]->card);
+	    if (idx_auto < 10.0) list->hdr[i]->idx = idx_auto;
+	 }
+
+	 /*
+	  * Verify the padding.
+	  */
+	 while ((bytes_read % FH_BLOCK_SIZE)!=0)
+	 {
+	    char tmp[FH_CARD_SIZE+1];
+	    int rd;
+	    
+	    rd = read_file(fd, tmp, FH_CARD_SIZE);
+	    if (rd == -1)
+	    {
+	       log_perror("FITS cards not properly padded");
+	       return FH_IN_ERRNO;
+	    }
+	    tmp[FH_CARD_SIZE] = '\0';
+	    if (rd == 0 && first_padding)
+	    {
+	       /*
+		* If there is no padding at all, this is OK (might be useful
+		* for generating templates which this library needs to read.)
+		* However, don't set fd_header_blocks... just return here.
+		* That way, the library will refuse to *update* one of these
+		* truncated header files, but can read in the headers without
+		* complaints.
+		*/
+	       return rtn;
+	    }
+	    if (rd != FH_CARD_SIZE)
+	    {
+	       log_error("FITS cards not properly padded");
+	       return FH_BAD_PADDING;
+	    }
+	    bytes_read += FH_CARD_SIZE;
+	    first_padding = 0;
+
+	    if (strspn(tmp, " ") != FH_CARD_SIZE)
+	    {
+	       log_warning("header padding contains characters other than ' '");
+	       return FH_BAD_PADDING;
+	    }
+	 }
+	 list->off_data = lseek(fd, 0, SEEK_CUR);
+	 list->fd_header_blocks = bytes_read / FH_BLOCK_SIZE;
+	 return rtn;
+      }
+   }
+   return FH_INVALID; /* Not reached */
+}
+
+
+fh_result
+fh_reserve(HeaderUnit hu, int n)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (!list)
+   {
+      log_error("invalid argument to fh_reserve()");
+      return FH_INVALID;
+   }
+
+   list->reserve = n;
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_rewrite(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   fh_result rtn;
+
+   if (!list)
+   {
+      log_error("invalid argument to fh_rewrite()");
+      return FH_INVALID;
+   }
+
+   if (list->counting_cards)
+   {
+      show_card_count(hu);
+      return FH_SUCCESS;
+   }
+
+   if (!(list->fd_header_blocks) ||
+       (list->fd == -1))
+   {
+      log_error("fh_rewrite only valid on headers created from fh_read()");
+      return FH_INVALID;
+   }
+
+   /*
+    * First rewrite all extensions too, if applicable.
+    */
+   if (list->set_all_units)
+   {
+      fh_result tmp;
+      int ext;
+
+      for (ext = 1; ext <= fh_extensions(list); ext++)
+         if ((tmp = fh_rewrite(fh_ehu(hu, ext))) != FH_SUCCESS)
+	    return tmp;
+   }
+
+   /*
+    * If the number of blocks that will be written isn't still
+    * equal to the number of blocks found in the original file,
+    * it won't fit.  Return FH_NO_SPACE error.
+    */
+   if (fh_header_blocks(list) != list->fd_header_blocks)
+   {
+      sprintf(err_buf,
+	      "need %d blocks for new header, have %d; "
+	      "increase upstream fh_reserve()",
+	      fh_header_blocks(list), list->fd_header_blocks);
+      log_error(err_buf);
+      return FH_NO_SPACE;
+   }
+
+   /*
+    * Seek to the start of the old headers.
+    */
+   if (seek_file(list->fd, list->off_hdrs) != 0)
+      return FH_IN_ERRNO; /* seek_file() prints its own error message */
+   /* === IN_ERRNO is not always correct here ! */
+
+   /*
+    * Write the new header block.
+    */
+   rtn = fh_write(list, list->fd); /* fh_write prints its own error message */
+
+   /*
+    * Just a quick sanity check... make sure that the file is now back at the start
+    * of the data.  This should always be the case, unless there is a bug in this library.
+    */
+   if (rtn == FH_SUCCESS)
+   {
+      if (lseek(list->fd, 0, SEEK_CUR) != list->off_data)
+      {
+	 log_error("not at start of data after updating headers");
+	 return FH_INTERNAL_ERROR;
+      }
+   }
+
+   if (fh_unlock_file(hu) == -1)
+      log_perror("failed to unlock file");
+
+   return rtn;
+}
+
+static fh_result
+check_latent_errors(HeaderUnitStruct* list)
+{
+   /*
+    * The fh_set() functions do not return an errors.  However,
+    * they do set a flag for the rare case that memory allocation
+    * should fail, or if they were called with invalid arguments
+    * (NULL pointers, etc.)  fh_write*() flushes out these errors.
+    */
+   if (list->err_memory)
+   {
+      list->err_memory = list->err_invalid = 0;
+      return FH_NO_MEMORY;
+   }
+   if (list->err_invalid)
+   {
+      list->err_memory = list->err_invalid = 0;
+      return FH_INVALID;
+   }
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_write_keyword_buffer(HeaderUnit hu, char* buffer, int* fits_blocks_inout)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   char* writebuf = buffer;
+   int i = 0, writelen;
+   int blocks_left;
+   fh_result result;
+
+   /*
+    * Check for valid arguments.
+    */
+   if (!list || !buffer ||
+       !fits_blocks_inout || *fits_blocks_inout < 1)
+   {
+      log_error("invalid argument to fh_write_keyword_buffer()");
+      return FH_INVALID;
+   }
+
+   result = check_latent_errors(list);
+   if (result != FH_SUCCESS) return result;
+
+   fh_sort(list);
+   blocks_left = fh_header_blocks(list);
+
+   /*
+    * Truncate the header if it will not fit.
+    */
+   if (blocks_left > *fits_blocks_inout)
+   {
+      blocks_left = *fits_blocks_inout;
+      result = FH_NO_SPACE; /* At the end, return this error/warning */
+   }
+   else
+   {
+      *fits_blocks_inout = blocks_left;
+   }
+
+   while (blocks_left--)
+   {
+      /*
+       * Initialize the header block with spaces (' ' character.)
+       */
+      memset(writebuf, ' ', FH_BLOCK_SIZE);
+
+      /*
+       * If there are headers remaining in the list (i < list->len)
+       * then copy them in until the entire block is filled.  Obviously
+       * FH_BLOCK_SIZE better be divisible by FH_CARD_SIZE (it is.)
+       */
+      for (writelen = 0;
+	   writelen < FH_BLOCK_SIZE;
+	   writelen += FH_CARD_SIZE)
+      {
+	 if (i < list->len)
+	    memcpy(writebuf + writelen, list->hdr[i++]->card, FH_CARD_SIZE);
+      }
+      /*
+       * Last block? Add END plus a blank line in the last two slots.
+       * This relies on the calculation of fh_header_blocks() being
+       * correct, and having left at least two empty slots at the
+       * end of the final blocks.
+       */
+      if (!blocks_left)
+      {
+	 memset(writebuf + FH_BLOCK_SIZE - 2 * FH_CARD_SIZE, ' ', 2 * FH_CARD_SIZE);
+	 memcpy(writebuf + FH_BLOCK_SIZE - 2 * FH_CARD_SIZE, "END", 3);
+      }
+      writebuf += FH_BLOCK_SIZE;
+   }
+   return result;
+}
+
+fh_result
+fh_write(HeaderUnit hu, int fd)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   char writebuf[FH_BLOCK_SIZE];
+   int i = 0, writelen;
+   int blocks_left;
+   fh_result result;
+
+   if (!list)
+   {
+      log_error("invalid argument to fh_write()");
+      return FH_INVALID;
+   }
+
+   if (list->counting_cards)
+   {
+      show_card_count(hu);
+      return FH_SUCCESS;
+   }
+
+   result = check_latent_errors(list);
+   if (result != FH_SUCCESS) return result;
+
+   list->off_hdrs = lseek(fd, 0, SEEK_CUR);
+
+   fh_sort(list);
+
+   blocks_left = fh_header_blocks(list);
+
+   while (blocks_left--)
+   {
+      /*
+       * Initialize the header block with spaces (' ' character.)
+       */
+      memset(writebuf, ' ', sizeof(writebuf));
+
+      /*
+       * If there are headers remaining in the list (i < list->len)
+       * then copy them in until the entire block is filled.  Obviously
+       * FH_BLOCK_SIZE better be divisible by FH_CARD_SIZE (it is.)
+       */
+      for (writelen = 0;
+	   writelen < sizeof(writebuf);
+	   writelen += FH_CARD_SIZE)
+      {
+	 if (i < list->len)
+	    memcpy(writebuf + writelen, list->hdr[i++]->card, FH_CARD_SIZE);
+	 /*
+	  * Reserve COMMENT lines get inserted in three cases:
+	  * 1) They were requested with fh_reserve().
+	  * 2) They were found in the existing FITS header.
+	  * 3) A header without any is being re-written with LESS blocks
+	  *    such that the END would land in the wrong block.  (Which
+	  *    only happens if the program deleted a bunch of keywords.)
+	  */	  
+	 else if (list->reserve || list->reserve_found ||
+		  ((i == list->len) && (blocks_left > 0)))
+	    memcpy(writebuf + writelen, FH_RESERVE, FH_RESERVE_LEN);
+	 else if (i == list->len)
+	 {
+	    memcpy(writebuf + writelen, "END", 3);
+	    i++;
+	 }
+      }
+      /*
+       * Last block? Add END plus a blank line in the last two slots.
+       * This relies on the calculation of fh_header_blocks() being
+       * correct, and having left at least two empty slots at the
+       * end of the final blocks.
+       *
+       * This only happens for the case with the special "reserve" comments.
+       * If list->reserve == 0, then the END was already included, immediately
+       * after the last keyword.
+       */
+      if (!blocks_left && (list->reserve || list->reserve_found))
+      {
+	 memset(writebuf + sizeof(writebuf) - 2 * FH_CARD_SIZE, ' ', 2 * FH_CARD_SIZE);
+	 memcpy(writebuf + sizeof(writebuf) - 2 * FH_CARD_SIZE, "END", 3);
+      }
+      if (write_file(fd, writebuf, sizeof(writebuf)) != sizeof(writebuf))
+      {
+	 log_perror("write failed");
+	 return FH_IN_ERRNO;
+      }
+   }
+   /*
+    * Remember the data offset.
+    */
+   list->off_data = lseek(fd, 0, SEEK_CUR);
+
+   /*
+    * Remember the number of blocks written for potential fh_rewrite() later.
+    */
+   list->fd_header_blocks = fh_header_blocks(list);
+
+   /*
+    * Remember the file descriptor for potential mmap later.
+    */
+   if (list->fd == -1)
+      list->fd = fd;
+   return FH_SUCCESS;
+}
+
+
+fh_result
+fh_read_padding(HeaderUnit hu, int fd)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int padding_bytes = fh_image_blocks(hu) * FH_BLOCK_SIZE - fh_image_bytes(hu);
+   int bytes_read;
+   char buf[FH_BLOCK_SIZE];
+   char* p = buf;
+   char padding = '\0';
+
+   if (!list)
+   {
+      log_error("invalid HeaderUnit passed to fh_read_padding");
+      return FH_INVALID;
+   }
+
+   if (list->image_bytes_left)
+   {
+      log_error("fh_read_padding attempted with pixels left to read");
+      return FH_BAD_SIZE;
+   }
+
+   if (padding_bytes)
+   {
+      bytes_read = read_file(fd, buf, padding_bytes);
+      if (bytes_read < 0)
+      {
+	 log_perror("failed to read padding");
+	 return FH_IN_ERRNO;
+      }
+      if (bytes_read != padding_bytes)
+      {
+	 log_error("not enough padding");
+	 return FH_END_OF_FILE;
+      }
+   }
+   if (fh_xtension(hu) == FH_XTENSION_TABLE) padding = ' ';
+   while (padding_bytes--)
+      if (*p++ != padding)
+      {
+	 if (fh_xtension(hu) == FH_XTENSION_TABLE)
+	    log_error("padding contains characters other than ' '");
+	 else
+	    log_error("padding contains characters other than \\0");
+	 return FH_BAD_PADDING;
+      }
+
+   return FH_SUCCESS;
+}
+
+/* Simple run-time test for the host byte-order, and swapping routines. */
+static int _endian_test = 1;
+#define is_little_endian() (*(char*)&_endian_test)
+static void fh_chsign(unsigned short* buffer, int elements)
+{
+#if 0
+   if (is_little_endian()) /* %%% Or is it always 0x0080 ? */
+      while (elements--)
+	 *buffer++ ^= 0x8000;
+   else
+#else
+   while (elements--)
+      *buffer++ ^= 0x0080;
+#endif
+}
+static void fh_bswap2(unsigned short* buffer, int elements)
+{
+   register unsigned short temp;
+
+   while (elements--)
+   {
+      temp = *buffer;
+      *buffer    = (temp & 0xff00) >> 8;
+      *buffer++ |= (temp & 0x00ff) << 8;
+   }
+}
+static void fh_bswap2chsign(unsigned short* buffer, int elements)
+{
+   register unsigned short temp;
+
+   while (elements--)
+   {
+      temp = *buffer;
+      *buffer    = ((temp^0x8000) & 0xff00) >> 8;
+      *buffer++ |= (temp & 0x00ff) << 8;
+   }
+}
+static void fh_bswap4(unsigned long* buffer, int elements)
+{
+   register unsigned long temp;
+
+   while (elements--)
+   {
+      temp = *buffer;
+      *buffer    =  (temp & 0xff000000) >> 24;
+      *buffer   |= (temp & 0x00ff0000) >> 8;
+      *buffer   |= (temp & 0x0000ff00) << 8;
+      *buffer++ |= (temp & 0x000000ff) << 24;
+   }
+}
+static void fh_bswap8(unsigned long* buffer, int elements)
+{
+   register unsigned temp1, temp2;
+
+   while (elements--)
+   {
+      temp1 = *buffer;
+      temp2 = *(buffer + 1);
+      *buffer    =  (temp2 & 0xff000000) >> 24;
+      *buffer   |= (temp2 & 0x00ff0000) >> 8;
+      *buffer   |= (temp2 & 0x0000ff00) << 8;
+      *buffer++ |= (temp2 & 0x000000ff) << 24;
+      *buffer    =  (temp1 & 0xff000000) >> 24;
+      *buffer   |= (temp1 & 0x00ff0000) >> 8;
+      *buffer   |= (temp1 & 0x0000ff00) << 8;
+      *buffer++ |= (temp1 & 0x000000ff) << 24;
+   }
+}
+
+fh_result
+fh_munmap_raw_image(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   HeaderUnitStruct* primary = FH_HU(list->phu);
+
+   if (!primary) primary = list;
+   if (!list)
+   {
+      log_error("invalid argument to fh_munmap_raw_image()");
+      return FH_INVALID;
+   }
+
+   if (list->mmap_count == 0 || primary->mmap_count == 0)
+      return FH_SUCCESS; /* Don't complain if nothing to munmap? */
+
+   list->mmap_count--;
+   primary->mmap_count--;
+
+   if (primary->mmap_count == 0)
+   {
+      if (munmap(primary->mmap_addr, primary->file_size) != 0)
+      {
+	 log_error("munmap failed");
+	 return FH_IN_ERRNO;
+      }
+   }
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_map_raw_image(HeaderUnit hu, void** data, int size)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   HeaderUnitStruct* primary = FH_HU(list->phu);
+
+   if (!primary) primary = list;
+   if (!list || !data || !size)
+   {
+      log_error("invalid argument to fh_map_raw_image()");
+      return FH_INVALID;
+   }
+
+   if (list->fd == -1)
+   {
+      log_error("fh_map_raw_image attempted before fh_read");
+      return FH_INVALID;
+   }
+
+   if (fh_image_bytes(hu) == 0)
+   {
+      log_error("image size must be set by NAXIS/BITPIX keywords before mmaping");
+      return FH_BAD_SIZE;
+   }
+
+   fh_munmap_raw_image(hu); /* Remove any previous mapping. */
+
+   /*
+    * Calculate file_size now, if this is a newly created file.
+    * Upon a read, file_size is determined by a stat() call.
+    * When writing a new file, it is determined with the seek,
+    * below:
+    *
+    * %%% It doesn't seem to work.  Why?
+    */
+   if (list->file_size == 0)
+   {
+      list->file_size = lseek(list->fd, 0, SEEK_END);
+      if (list->file_size == (off_t)-1)
+      {
+	 log_perror("seek to end of file failed");
+	 return -1;
+      }
+   }
+
+   if (size != list->image_bytes)
+   {
+      sprintf(err_buf,
+	      "fh_map_raw_image size (%d) does not match image_bytes (%d)",
+	      size, list->image_bytes);
+      log_error(err_buf);
+      return FH_BAD_SIZE;
+   }
+   if (primary->mmap_count == 0)
+   {
+      primary->mmap_addr = mmap(0, primary->file_size,
+				PROT_READ|PROT_WRITE, MAP_SHARED, /* %%% ### The PROT_WRITE is only temporary */
+				list->fd, 0);
+      if (primary->mmap_addr == (void*)-1 ||
+	  primary->mmap_addr == (void*)0)
+      {
+	 log_perror("error: mmap failed");
+	 return FH_IN_ERRNO;
+      }
+   }
+
+   list->mmap_count++;
+   primary->mmap_count++;
+
+   *data = (char*)primary->mmap_addr + list->off_data;
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_read_image(HeaderUnit hu, int fd, void* data, int size, int typesize)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int need_swap = 0;
+   int bytes_to_read, bytes_left;
+
+   if (!list || !data || fd == -1)
+   {
+      log_error("invalid argument to fh_read_image()");
+      return FH_INVALID;
+   }
+
+   if (is_little_endian()) need_swap = 1;		/* Auto */
+   if (typesize < 0) { need_swap = 1; typesize *= -1; }	/* Forced on */
+   else if (typesize < 2) need_swap = 0;		/* Forced off or N/A */
+
+   if (typesize && fh_bitpix(hu) != -1 && typesize != fh_bytepix(hu))
+   {
+      log_error("fh_read_image typesize/BITPIX mismatch");
+      return FH_BAD_SIZE;
+   }
+
+   if (fh_image_bytes(hu) == 0) /* Calculate image size if needed. */
+   {
+      log_error("image size must be set by NAXIS/BITPIX keywords before reading");
+      return FH_BAD_SIZE;
+   }
+
+   if (size > list->image_bytes_left)
+   {
+      sprintf(err_buf,
+	      "fh_read_image size (%d) is more than image_bytes_left (%d)",
+	      size, list->image_bytes_left);
+      log_error(err_buf);
+      return FH_BAD_SIZE;
+   }
+   bytes_left = size;
+   list->image_bytes_left -= size;
+
+   while (bytes_left)
+   {
+      bytes_to_read = bytes_left;
+      /* Do smaller reads to pipeline byte-swapping if need_swap is true */
+      if (need_swap && bytes_to_read > 32768) bytes_to_read = 32768;
+      if (read_file(fd, data, bytes_to_read) != bytes_to_read)
+      {
+	 log_perror("failed to read image data");
+	 return FH_IN_ERRNO;
+      }
+      if (need_swap) switch (typesize)
+      {
+	 case 2: fh_bswap2(data, bytes_to_read / 2); break;
+	 case 4: fh_bswap4(data, bytes_to_read / 4); break;
+	 case 8: fh_bswap8(data, bytes_to_read / 8); break;
+	 default:
+	 log_error("byte-swapping only defined for 2,4,8-byte data types");
+	 return FH_INVALID;
+      }
+      bytes_left -= bytes_to_read;
+      data = (char*)data + bytes_to_read;
+   }
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_read_padded_image(HeaderUnit hu, int fd, void* data, int size, int typesize)
+{
+   fh_result rtn;
+
+   if (size &&
+       (rtn = fh_read_image(hu, fd, data, size, typesize)) != FH_SUCCESS)
+      return rtn;
+
+   return fh_read_padding(hu, fd);
+}
+
+fh_result
+fh_write_padding(HeaderUnit hu, int fd)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   HeaderUnitStruct* primary = list?(FH_HU(list->phu)):0;
+   int padding_bytes;
+
+   if (!list || fd == -1)
+   {
+      log_error("invalid argument to fh_write_padding()");
+      return FH_INVALID;
+   }
+
+   padding_bytes = fh_image_blocks(hu) * FH_BLOCK_SIZE - fh_image_bytes(hu);
+
+   /*
+    * The library will only write the padding for two cases:
+    *
+    * 1) The library itself has been used to write all the data,
+    *    all at once or in segments, so image_bytes_left is 0.
+    * 2) The library has written none of the data (image_bytes_left
+    *    is equal to image_bytes) in which case it is assumed
+    *    that the data was written to the file by the user.
+    *
+    * The main point of this check is to catch alignment problems
+    * where not enough data is written to the FITS file before
+    * the padding was added.
+    */
+   if (list->image_bytes_left != 0 &&
+       list->image_bytes_left != fh_image_bytes(hu))
+   {
+      sprintf(err_buf,
+	      "fh_write_padding attempted but %d pixels left to write",
+	      list->image_bytes_left);
+      log_error(err_buf);
+      return FH_BAD_SIZE;
+   }
+
+   if (padding_bytes)
+   {
+      if (write_file(fd, padding_block(fh_xtension(hu)), padding_bytes)
+	  != padding_bytes)
+      {
+	 log_perror("failed to write padding");
+	 return FH_IN_ERRNO;
+      }
+   }
+   /* %%% ... */
+   if (list->file_size < list->off_data + fh_image_bytes(hu) + padding_bytes)
+      list->file_size = list->off_data + fh_image_bytes(hu) + padding_bytes;
+   if (primary && primary->file_size < list->file_size)
+      primary->file_size = list->file_size; /* ... %%% */
+
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_write_image(HeaderUnit hu, int fd, void* data, int size, int typesize)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int need_swap = 0;
+   int need_chsign = 0;
+   int bytes_to_write, bytes_left;
+
+   if (is_little_endian()) need_swap = 1;		/* Auto */
+   if (typesize < 0) { need_swap = 1; typesize *= -1; }	/* Forced on */
+   else if (typesize < 2 ||				/* Forced off or N/A */
+	    typesize == FH_TYPESIZE_16URAW) need_swap = 0;
+   if (typesize == FH_TYPESIZE_16U ||			/* 16-bit unsigned */
+       typesize == FH_TYPESIZE_16URAW) { typesize = 2; need_chsign = 1; }
+
+   if (!list || !data || fd == -1)
+   {
+      log_error("invalid argument to fh_write_image()");
+      return FH_INVALID;
+   }
+   if (typesize && fh_bitpix(hu) != -1 && typesize != fh_bytepix(hu))
+   {
+      log_error("fh_write_padded_image typesize/BITPIX mismatch");
+      return FH_BAD_SIZE;
+   }
+   if (fh_image_bytes(hu) == 0) /* Calculate image size if needed. */
+   {
+      log_error("image size must be set by NAXIS/BITPIX keywords before writing");
+      return FH_BAD_SIZE;
+   }
+   if (size > list->image_bytes_left)
+   {
+      sprintf(err_buf,
+	      "fh_write_image size (%d) is more than image_bytes_left (%d)",
+	      size, list->image_bytes_left);
+      log_error(err_buf);
+      return FH_BAD_SIZE;
+   }
+   bytes_left = size;
+   list->image_bytes_left -= size;
+   if (!need_swap && !need_chsign)
+   {
+      if (write_file(fd, data, bytes_left) != bytes_left)
+      {
+	 log_perror("failed to write image data");
+	 return FH_IN_ERRNO;
+      }
+   }
+   else /* byte-swapping case requires a temporary buffer */
+   {
+      unsigned char outbuf[32768];
+
+      while (bytes_left)
+      {
+	 bytes_to_write = bytes_left;
+	 if (bytes_to_write > sizeof(outbuf)) bytes_to_write = sizeof(outbuf);
+	 memcpy(outbuf, data, bytes_to_write);
+	 switch (typesize + need_chsign)
+	 {
+	    case 2: fh_bswap2((void*)outbuf, bytes_to_write / 2); break;
+	    case 3: /* Special case that also converts unsign->sign (16-bit) */
+	    if (need_swap)
+	       fh_bswap2chsign((void*)outbuf, bytes_to_write / 2);
+	    else
+	       fh_chsign((void*)outbuf, bytes_to_write / 2);
+	    break;
+	    case 4: fh_bswap4((void*)outbuf, bytes_to_write / 4); break;
+	    case 8: fh_bswap8((void*)outbuf, bytes_to_write / 8); break;
+	    default:
+	    log_error("byte-swapping only defined for 2,4,8-byte data types");
+	    return FH_INVALID;
+	 }
+	 if (write_file(fd, outbuf, bytes_to_write) != bytes_to_write)
+	 {
+	    log_perror("failed to write image data");
+	    return FH_IN_ERRNO;
+	 }
+	 bytes_left -= bytes_to_write;
+	 data = (char*)data + bytes_to_write;
+      }
+   }
+   return FH_SUCCESS;
+}
+
+fh_result
+fh_reserve_padded_image(HeaderUnit hu, int fd)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (!list || fd == -1)
+   {
+      log_error("invalid argument to fh_reserve_padded_image()");
+      return FH_INVALID;
+   }
+   if (list->off_data == 0 || list->off_data == (off_t)-1)
+   {
+      log_error("no header for fh_reserve_padded_image()");
+      return FH_INVALID;
+   }
+   if (fh_image_bytes(hu) == 0) /* Calculate image size if needed. */
+   {
+      log_error("image size must be set by NAXIS/BITPIX keywords before reserving image area");
+      return FH_BAD_SIZE;
+   }
+   if (seek_file(fd, list->off_data + list->image_bytes_left - 1) != 0)
+      return FH_IN_ERRNO; /* seek_file() prints its own error message */
+   if (write_file(fd, "\0", 1) != 1)
+   {
+      log_perror("reserve image failed");
+      return FH_IN_ERRNO; /* seek_file() prints its own error message */
+   }
+   list->image_bytes_left = 0;
+   return fh_write_padding(hu, fd);
+}
+
+fh_result
+fh_write_padded_image(HeaderUnit hu, int fd, void* data, int size, int typesize)
+{
+   fh_result rtn;
+
+   if (size &&
+       (rtn = fh_write_image(hu, fd, data, size, typesize)) != FH_SUCCESS)
+      return rtn;
+   
+   return fh_write_padding(hu, fd);
+}
+
+static fh_result
+fh_copy_padded_image_internal(HeaderUnit hu, int fd_out, int fd_in, int verify)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   static char* buf = 0;
+   int copy_size;
+   int image_bytes;
+   fh_result rtn0 = FH_SUCCESS, rtn1, rtn2;
+   int zero_bytes;
+   char* p;
+
+
+   if (!list || fd_out == -1 || fd_in == -1)
+   {
+      log_error("invalid argument to fh_copy_padded_image()");
+      return FH_INVALID;
+   }
+   if (!buf &&
+       !(buf = (char*)malloc(FH_BUFFER_SIZE)))
+   {
+      log_error("out of memory in fh_copy_padded_image()");
+      return FH_NO_MEMORY;
+   }
+
+   image_bytes = fh_image_bytes(hu);
+
+   while (image_bytes)
+   {
+      int bytes;
+
+      copy_size = image_bytes;
+      if (copy_size > FH_BUFFER_SIZE) copy_size = FH_BUFFER_SIZE;
+      bytes = read_file(fd_in, buf, copy_size);
+      if (bytes == 0)
+      {
+	 log_error("fh_copy_padded_image unexpected EOF");
+	 return FH_END_OF_FILE;
+      }
+      if (bytes == -1)
+      {
+	 log_perror("fh_copy_padded_image read failed");
+	 return FH_IN_ERRNO;
+      }
+      if (bytes != copy_size)
+      {
+	 log_error("fh_copy_padded_image short read");
+	 return FH_BAD_VALUE;
+      }
+      if (verify) for (p = buf, zero_bytes = 0; p < buf + copy_size; p++)
+      {
+	 if (*p != '\0')
+	 {
+	    zero_bytes = 0;
+	    p = (char*)((unsigned int)p|511); /* next disk sector */
+	 }
+	 else if (++zero_bytes == 512)
+	 {
+	    /* %%% log_error? */
+	    fprintf(stderr, "warning: fhtool: file contains zero-block(s)\n");
+	    rtn0 = FH_BAD_VALUE;
+	    break;
+	 }
+      }
+      bytes = write_file(fd_out, buf, copy_size);
+      if (bytes != copy_size)
+      {
+	 log_perror("fh_copy_padded_image write failed");
+	 return FH_IN_ERRNO;
+      }
+      list->image_bytes_left -= copy_size;
+      image_bytes -= copy_size;
+   }
+
+   rtn1 = fh_read_padding(hu, fd_in);
+   rtn2 = fh_write_padding(hu, fd_out);
+   if (rtn2 != FH_SUCCESS) return rtn2;
+   if (rtn0 != FH_SUCCESS) return rtn0;
+   return rtn1;
+}
+
+fh_result
+fh_copy_padded_image(HeaderUnit hu, int fd_out, int fd_in)
+{
+   return fh_copy_padded_image_internal(hu, fd_out, fd_in, /*verify=*/0);
+}
+
+fh_result
+fh_copy_and_verify_padded_image(HeaderUnit hu, int fd_out, int fd_in)
+{
+   return fh_copy_padded_image_internal(hu, fd_out, fd_in, /*verify=*/1);
+}
+
+void
+fh_link_ehu_to_phu(HeaderUnit ehu, HeaderUnit phu)
+{
+   HeaderUnitStruct* ehu_list = FH_HU(ehu);
+   HeaderUnitStruct* phu_list = FH_HU(phu);
+
+   ehu_list->next = phu_list->ehu;
+   phu_list->ehu = ehu_list;
+   ehu_list->phu = phu_list;
+}
+
+static HeaderUnit
+ehu_internal(HeaderUnitStruct* phu, const char* extname, int imageid)
+{
+   int i = 0, found = 0;
+   off_t next_off;
+   HeaderUnit* next_ehu = &(phu->ehu);
+
+   if (phu == 0)
+   {
+      log_error("invalid argument to ehu function");
+      return 0;
+   }
+
+   if (phu->fd == -1)
+   {
+      log_error("no file associated with PHU");
+      return 0;
+   }
+
+   next_off = phu->off_data;
+
+   if (fh_extensions(phu)==0)
+   {
+      log_error("no extensions found in file");
+      return 0;
+   }
+
+   /*
+    * Search all extensions for `extname' or `imageid'
+    */
+   while (i++ < fh_extensions(phu))
+   {
+      if (!*next_ehu)
+      {
+	 /*
+	  * If this is the first pass, read the EHU into the cache.
+	  */
+	 *next_ehu = fh_create();
+	 FH_HU(*next_ehu)->phu = phu; /* Link to phu for mmap re-use */
+	 if (seek_file(phu->fd, next_off) != 0) return 0;
+	 if (fh_read(*next_ehu, phu->fd, 0) != FH_SUCCESS)
+	 {
+	    log_error("problem with MEF structure");
+	    return 0; /* File error? */
+	 }
+      }
+      /*
+       * Now look for either a matching EXTNAME or IMAGEID card.
+       */
+      if (extname)
+      {
+	 char n[FH_MAX_STRLEN + 1];
+
+	 if (fh_get_str(*next_ehu, "EXTNAME", n, sizeof(n)) == FH_SUCCESS &&
+	     fh_cmp(n, extname)>=MATCH_FULL)
+	    found = 1;
+      }
+      else if (imageid >= 0)
+      {
+	 int id;
+
+	 if (fh_get_int(*next_ehu, "IMAGEID", &id) == FH_SUCCESS &&
+	     id == imageid)
+	    found = 1;
+      }
+      else
+      {
+	 if (i == -imageid)
+	    found = 1;
+      }
+
+      if (found)
+      {
+	 if (seek_file(phu->fd, FH_HU(*next_ehu)->off_data) != 0)
+	    return 0;
+	 return *next_ehu; /* Success! */
+      }
+
+      /*
+       * Set the offset to the beginning of the next extension (but don't
+       * actually seek there unless the EHU hasn't been cached yet.)
+       */
+      next_off = FH_HU(*next_ehu)->off_data +
+	 fh_image_blocks(*next_ehu) * FH_BLOCK_SIZE;
+      next_ehu = &(FH_HU(*next_ehu)->next);
+   }
+   return 0; /* Not found */
+}
+
+HeaderUnit
+fh_ehu(HeaderUnit phu, int number)
+{
+   HeaderUnitStruct* list = FH_HU(phu);
+   
+   if (number == 0 && list)
+   {
+      if (seek_file(list->fd, list->off_data) != 0)
+	 return 0;
+      list->image_bytes_left = fh_image_bytes(phu);
+      return (HeaderUnit)list;
+   }
+   return ehu_internal(list, 0, -number);
+}
+
+HeaderUnit
+fh_ehu_by_imageid(HeaderUnit phu, int imageid)
+{
+   return ehu_internal(FH_HU(phu), 0, imageid);
+}
+
+HeaderUnit
+fh_ehu_by_extname(HeaderUnit phu, const char* extname)
+{
+   return ehu_internal(FH_HU(phu), extname, 0);
+}
+
+#if 0
+/* %%% Decide whether to keep this or not.*/
+typedef fh_result (*fh_handler)(double idx, const char* card);
+
+fh_result
+fh_foreach(HeaderUnit hu, fh_handler handler)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   fh_result rtn = FH_SUCCESS;
+   int i;
+
+   for (i = 0; i < list->len ; i++)
+      if (handler(list->hdr[i]->idx, handler) != FH_SUCCESS)
+
+
+   return rtn;
+}
+#endif
+
+fh_result
+fh_show(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int i;
+
+   for (i = 0; i < list->len ; i++)
+      printf("%.79s\n", list->hdr[i]->card);
+
+   return FH_SUCCESS;
+}
+
+/* -------------------------------------------------------------------------
+ *             Implementation of internal utility functions:
+ * -------------------------------------------------------------------------
+ */
+static const char*
+padding_block(int type)
+{
+   static int s_initialized = 0;
+   static char s[FH_BLOCK_SIZE];
+   static int z_initialized = 0;
+   static char z[FH_BLOCK_SIZE];
+
+   if (type == FH_XTENSION_TABLE) /* FITS ASCII TABLES are padded with ' ' */
+   {
+      if (!s_initialized)
+      {
+	 memset(s, ' ', sizeof(s));
+	 s_initialized = 1;
+      }
+      return s;
+   }
+
+   if (!z_initialized) /* FITS data and IMAGE extensions are padded with \0 */
+   {
+      memset(z, 0, sizeof(z));
+      z_initialized = 1;
+   }
+   return z;
+}
+
+static int
+write_file(int fd, const void* buf, int len)
+{
+   int rtn;
+   int count = 0;
+
+   while (len)
+   {
+      rtn = write(fd, (char*)buf, len);
+
+      switch (rtn)
+      {
+	 case -1: if (errno == EINTR || errno == EAGAIN)
+	    continue; /* retry */
+	    return -1; /* permanent failure */
+	 case 0: return count;
+	 default:
+	 {
+	    len -= rtn;
+	    count += rtn;
+	    buf = (char*)buf + rtn;
+	 }
+      }
+   }
+   return count;
+}
+
+static int
+read_file(int fd, const void* buf, int len)
+{
+   int rtn;
+   int count = 0;
+
+   while (len)
+   {
+      rtn = read(fd, (char*)buf, len);
+
+      switch (rtn)
+      {
+	 case -1: if (errno == EINTR || errno == EAGAIN)
+	    continue; /* retry */
+	    return -1; /* permanent failure */
+	 case 0: return count;
+	 default:
+	 {
+	    len -= rtn;
+	    count += rtn;
+	    buf = (char*)buf + rtn;
+	 }
+      }
+   }
+   return count;
+}
+
+static int
+seek_file(int fd, off_t off)
+{
+   if (off == (off_t)-1)
+   {
+      log_error("cannot seek in input");
+      return -1;
+   }
+
+   if (lseek(fd, off, SEEK_SET) == (off_t)-1)
+   {
+      log_perror("seek failed");
+      return -1;
+   }
+   return 0;
+}
+
+static int
+fh_unlock_file(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int rtn;
+
+   if (list->fl.l_type != F_UNLCK && list->fd_locked != -1)
+   {
+      list->fl.l_type = F_UNLCK;
+      do
+      {
+         rtn = fcntl(list->fd_locked, F_SETLKW, &list->fl);
+      } while (rtn == -1 && errno == EINTR);
+      return rtn;
+   }
+   return 0;
+}
+
+static int
+fh_lock_file(HeaderUnit hu, int fd, fh_mode mode)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   int rtn;
+
+   fh_unlock_file(hu); /* Remove any old lock, if needed */
+   list->fd_locked = fd;
+   list->fl.l_type = (mode == FH_FILE_RDONLY)? F_RDLCK : F_WRLCK;
+   list->fl.l_whence = SEEK_SET;
+   list->fl.l_start = 0;
+   list->fl.l_len = 0;
+   do
+   {
+      rtn = fcntl(fd, F_SETLKW, &list->fl);
+   } while (rtn == -1 && errno == EINTR);
+   return rtn;
+}
+
+
+static fh_result
+fix_characters(char* s, int repair)
+{
+   int col;
+   int bad_value = 0;
+
+   for (col=0; col<FH_NAME_SIZE; col++)
+   {
+      if (s[col] == ' ')
+      {
+	 while (++col < FH_NAME_SIZE)
+	    if (s[col] != ' ') { if (repair) s[col] = ' '; bad_value++; }
+	 break;
+      }
+      if (s[col] != NAME_CHR(s[col]))
+      { if (repair) s[col] = NAME_CHR(s[col]); bad_value++; }
+   }
+   
+   for (col=FH_NAME_SIZE; col<FH_CARD_SIZE; col++)
+      if (s[col] < ' ' || s[col] >= 127) { if (repair) s[col] = '_'; bad_value++; }
+
+   if (bad_value) return FH_BAD_VALUE;
+   return FH_SUCCESS;
+}
+
+/*
+ * See if "name1" is the same as "name2".
+ *
+ * Only the first 8 characters are compared, or up to a '\0'.
+ * If one name contains a '\0', the other must contain only
+ * ' ' characters (or also a a '\0') for the match to be
+ * successful.
+ */
+static match_result
+fh_cmp(const char* name1, const char* name2)
+{
+   int i;
+
+   if (!name1 || !name2) return MATCH_FAILED;
+   for (i = 0; i < FH_CARD_SIZE; i++)
+   {
+      if (NAME_CHR(*name1) != NAME_CHR(*name2))
+      {
+         /* mismatch found */
+         if (i >= FH_NAME_SIZE) return MATCH_KEYWORD;
+         if (!*name2) return MATCH_SUBSTR;
+         return MATCH_FAILED;
+      }
+      if (*name1) name1++;
+      if (*name2) name2++;
+   }
+   return MATCH_FULL;
+}
+
+static int
+fh_compare(const void* a, const void* b)
+{
+   double diff = (*((FitsCard**)a))->idx - (*((FitsCard**)b))->idx;
+
+   if (diff < 0) return -1;
+   else if (diff > 0) return 1;
+   else return 0;
+}
+
+static void
+fh_sort(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (list->len <= 0) return; /* No keywords to sort! */
+
+   qsort(list->hdr, list->len, sizeof(FitsCardPtr), fh_compare);
+}
+
+/*
+ * Passing a 0 for `idx' means match only by `name'
+ */
+static FitsCardPtr
+get_hdr(HeaderUnitStruct* list, const char* name, double idx)
+{
+   FitsCardPtr hdr;
+   int i;
+
+   for (i = 0; i < list->len; i++)
+   {
+      hdr = list->hdr[i];
+      if (fh_cmp(hdr->card, name) >= MATCH_KEYWORD &&
+	  (idx == 0 || hdr->idx == idx))
+	 return hdr;
+   }
+   return 0;
+}
+
+static const char*
+get_value(HeaderUnitStruct* list, const char* name)
+{
+   FitsCardPtr hdr = get_hdr(list, name, 0);
+   const char* p;
+   fh_bool inherit;
+
+   if (!hdr && name &&
+       strcmp(name, "EXTEND") &&
+       strcmp(name, "NEXTEND") &&
+       strcmp(name, "INHERIT"))
+   {
+      if (list->phu && name &&
+	  fh_get_bool(list, "INHERIT", &inherit)==FH_SUCCESS &&
+	  inherit==FH_TRUE)
+      {
+	 /* %%% Only do this if INHERIT=T */
+	 hdr = get_hdr(list->phu, name, 0);
+      }
+   }
+   if (!hdr) return 0; /* Not found. */
+
+   p = hdr->card + FH_NAME_SIZE;
+   if (*p++ != '=') return 0; /* Something wrong with FITS file? */
+   while (*p == ' ') p++;
+   return p;
+}
+
+static double
+auto_idx(const char* name)
+{
+   if (!name) return 10.0;
+   if (fh_cmp(name, "SIMPLE")  >=MATCH_KEYWORD)	return 0.0;
+   if (fh_cmp(name, "XTENSION")>=MATCH_KEYWORD)	return 0.0;
+   if (fh_cmp(name, "BITPIX")  >=MATCH_KEYWORD)	return 1.0;
+   if (fh_cmp(name, "NAXIS")   >=MATCH_SUBSTR) 	return 2.0 + 0.1 * atoi(name + 5);
+   if (fh_cmp(name, "EXTEND")  >=MATCH_KEYWORD)	return 3.0;
+   if (fh_cmp(name, "NEXTEND") >=MATCH_KEYWORD)	return 3.1;
+   if (fh_cmp(name, "GROUPS")  >=MATCH_KEYWORD)	return 4.0;
+   if (fh_cmp(name, "PCOUNT")  >=MATCH_KEYWORD)	return 5.0;
+   if (fh_cmp(name, "GCOUNT")  >=MATCH_KEYWORD)	return 6.0;
+   if (fh_cmp(name, "TFIELDS") >=MATCH_KEYWORD)	return 7.000;
+   if (fh_cmp(name, "TFORM")   >=MATCH_SUBSTR)  return 7.0001 + 0.001*atoi(name+5);
+   if (fh_cmp(name, "TBCOL")   >=MATCH_SUBSTR)  return 7.0002 + 0.001*atoi(name+5);
+   if (fh_cmp(name, "INHERIT") >=MATCH_KEYWORD) return 9.0;
+   if (fh_cmp(name, "END")     >=MATCH_SUBSTR)	return DBL_MAX;
+   return 10.0;
+}
+
+/*
+ * Find/Create a new card in the list.
+ */
+static char*
+get_card(HeaderUnitStruct* list, double idx, const char* name, double idxmatch)
+{
+   FitsCardPtr rtn;
+   int i;
+   double idx_auto = auto_idx(name);
+
+   if (idx == DBL_MAX)
+   {
+      log_warning("END is added automatically by libfh");
+      return 0;
+   }
+
+   /*
+    * If idx_auto < 10, the library should assign the idx value itself
+    * in such a way that the output will conform to the FITS standard.
+    */
+   if (idx_auto < 10.0) idx = idx_auto;
+   else
+      /*
+       * Otherwise, if the user's idx < 10.0, auto-increment the last idx.
+       */
+      if (idx < 10.0) idx = (list->idx_highest += IDX_AUTO_INCR);
+      else if (idx > list->idx_highest) list->idx_highest = idx;
+
+   /*
+    * Check if a card by the same name (or same name _and_ idxmatch,
+    * if idxmatch is non-zero) already existed.
+    */
+   if (name && (rtn = get_hdr(list, name, idxmatch))) return rtn->card;
+
+   /*
+    * Allocate more memory (just double the size) if table is full.
+    */
+   if (++list->len > list->size)
+   {
+      FitsCardPtr* newhdr;
+      if (!(newhdr = (FitsCardPtr*)realloc(list->hdr,
+					   sizeof(FitsCardPtr) *
+					   list->size * 2)))
+      {
+	 log_error("out of memory for FITS card slots");
+	 list->err_memory++;
+	 return 0; /* Save for delayed error from fh_rewrite() */
+	 /* Old list->hdr is still valid if realloc fails. */
+      }
+      list->size *= 2;
+      list->hdr = newhdr;
+   }
+
+   /*
+    * Allocate a new FITS card.
+    */
+   if (!(rtn = list->hdr[list->len-1] = (FitsCard*)malloc(sizeof(FitsCard))))
+   {
+      log_error("out of memory for new FITS card");
+      list->err_memory++; /* Save for delayed error from fh_rewrite() */
+      return 0;
+   }
+
+   /*
+    * Blank the entry and fill in the name.
+    */
+   rtn->idx = idx;
+   memset(rtn->card, ' ', FH_CARD_SIZE);
+   rtn->card[FH_CARD_SIZE] = '\0';
+
+   /*
+    * Check, and fill in the name if needed.
+    */
+   if (name)
+   {
+      for (i=0; i<FH_NAME_SIZE && *name; i++)
+	 rtn->card[i] = NAME_CHR(*name++);
+
+      /*
+       * The '=' case is OK.  It happens since fh_set_card passes
+       * the whole card in for name also.
+       */
+      if (*name!='\0' && *name!='=')
+	 log_warning("long (>8 byte) keyword name truncated");
+   }
+
+   return rtn->card;
+}
+
+
+static void
+add_comment(char* s, int col, const char* comment)
+{
+   /*
+    * Comments must not begin before column 30.
+    */
+   while (col < 30) s[col++] = ' ';
+
+   /*
+    * If no comment given, leave the old comment in place,
+    * if possible.  It could be that a longer string
+    * has overwritten the / that starts the comment, in which
+    * case this will make sure that the first non-space character
+    * after the value is still a '/'.
+    */
+   if (!comment || !*comment)
+   {
+      if (col < FH_CARD_SIZE) s[col++] = ' ';
+      while (col < FH_CARD_SIZE && s[col] == ' ') col++;
+      if (col < FH_CARD_SIZE) s[col++] = '/';
+      return;
+   }
+
+   if (col < 77 && comment && *comment)
+   {
+      s[col++] = ' ';
+      s[col++] = '/';
+      s[col++] = ' ';
+      while (col < FH_CARD_SIZE && *comment)
+      {
+	 if (*comment < ' ' || *comment >= 127)
+	 {
+	    s[col++] = '_';
+	    sprintf(err_buf, "illegal character %x in FITS card comment.",
+		    *comment++); /* Don't forget to increment comment */
+	    log_warning(err_buf);
+	 }
+	 else
+	 {
+	    s[col++] = *comment++;
+	 }
+      }
+   }
+   while (col < FH_CARD_SIZE) s[col++] = ' '; /* Blank out rest of old value, if any */
+}
+
+/* End of fh.c */
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh.h	(revision 23490)
@@ -0,0 +1,347 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`fh.h' - FITS Handling Routines for Standard FITS and MEF
+
+This file is part of version 1 of the FITS Handling Library.
+Read the `License' file for terms of use and distribution.
+Copyright 2001, Canada-France-Hawaii Telescope, daprog@cfht.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+/* $Id: fh.h,v 1.5 2003/05/28 06:45:17 isani Exp isani $
+ * Created: 2001-4-2
+ * Documentation: See http://software.cfht.hawaii.edu/libfh/
+ */
+#ifndef _INCLUDED_fh
+#define _INCLUDED_fh 1
+/* ------------------------------------------------
+ * Definitions, Types, and Structures used by libfh
+ * ------------------------------------------------
+ */
+#define FH_MAX_STRLEN	68  	/* Longest possible FITS string value */
+#define FH_NAME_SIZE	8   	/* Size in bytes of a FITS card name */
+#define FH_CARD_SIZE	80  	/* Size in bytes of a FITS card */
+#define FH_BLOCK_SIZE	2880	/* FITS file block size in bytes (36 cards) */
+#define FH_AUTO		0.0 	/* Don't need `idx' numbers?  Use this everywhere. */
+#define FH_TYPESIZE_RAW	0 	/* Never swap the image data === Document! */
+#define FH_TYPESIZE_8	1 	/* 8-bit data (swapping not applicable) */
+#define FH_TYPESIZE_16	2 	/* 16-bit data, auto-swap if needed */
+#define FH_TYPESIZE_16U 3	/* 16-bit unsign, offset 32768 when writing */
+#define FH_TYPESIZE_16US -3	/* 16-bit unsign, offset 32768, force swap */
+#define FH_TYPESIZE_16URAW 5	/* 16-bit unsign, offset 32768, no swap */
+#define FH_TYPESIZE_16S	-2	/* 16-bit data, force swapping */
+#define FH_TYPESIZE_32	4 	/* 32-bit data, auto-swap if needed */
+#define FH_TYPESIZE_32S	-4	/* 32-bit data, force swapping */
+#define FH_TYPESIZE_64	8 	/* 64-bit data, auto-swap if needed */
+#define FH_TYPESIZE_64S	-8	/* 64-bit data, force swapping */
+#define FH_COUNT_CARDS "@FH_COUNT_CARDS@"  /* See also: fh_count_cards() */
+
+typedef enum /* fh_result -- Result Code for most functions in this library: */
+{  FH_SUCCESS = 0,
+   FH_IN_ERRNO = -1,	/* A system call failed; check value of errno */
+   FH_END_OF_FILE = -2,	/* EOF condition */
+   FH_NOT_FOUND = -3,	/* No such card or header unit found */
+   FH_INVALID = -4,	/* Invalid arguments passed (NULL pointer, etc.) */
+   FH_BAD_VALUE = -5,	/* Wrong type, error in conversion, string too long */
+   FH_BAD_SIZE = -6,	/* Size argument doesn't match BITPIX and NAXIS */
+   FH_BAD_PADDING = -7,	/* Problem with header padding or \0's after data */
+   FH_NO_SPACE = -8,	/* No space for header (file must be re-created.) */
+   FH_NO_MEMORY = -9,	/* A call to malloc failed somewhere */
+   FH_IS_TTY = -10,	/* This call doesn't work on tty devices */
+   FH_IS_DIR = -11,	/* This call requires a file, not a directory */
+   FH_INTERNAL_ERROR=-99, /* Internal error with the library */
+} fh_result;
+
+typedef enum
+{  FH_FILE_RDONLY,		/* Open, get non-exclusive lock, read header, unlock */
+   FH_FILE_RDWR,		/* Open, get exclusive lock, read, unlock on rewrite */
+   FH_FILE_RDONLY_NOLOCK,	/* Same as RDONLY but without advisory lock */
+   FH_FILE_RDWR_NOLOCK 		/* Same as RDWR but without advisory lock */
+} fh_mode;
+
+typedef enum
+{  FH_FALSE=0,			/* FITS card contains 'F' in column 30 */
+   FH_TRUE=1			/* FITS card contains 'T' in column 30 */
+} fh_bool;			/* Value for "logical" FITS cards */
+
+typedef void* HeaderUnit; /* Handle to a list of FITS cards allocated by fh_create. */
+
+typedef void (*fh_logger_t) (const char* message);
+void fh_log_error(fh_logger_t logger);	/* These are used only if you do not */
+void fh_log_perror(fh_logger_t logger);	/* want messages going to stderr. */
+void fh_log_warning(fh_logger_t logger); /* See manual for more information. */
+
+/* ---------------------------------------------------------
+ * Open, Close, Lock, or create new FITS files/header blocks
+ * ---------------------------------------------------------
+ */
+HeaderUnit	fh_create(void);
+fh_result	fh_destroy(HeaderUnit hu);
+/*
+ * These are the first and last functions called to allocate and free
+ * space for a HeaderUnit. After fh_create, use fh_file, fh_read, fh_set...
+ * NOT to be used with HeaderUnit's returned by the fh_ehu() functions!
+ */
+fh_result	fh_file(HeaderUnit hu, const char* filespec, fh_mode mode);
+/*
+ * Open file and read headers from the PHU or [extname] if given in filespec.
+ * File is left at start of image data in the file or 1st extension.
+ */
+int		fh_file_desc(HeaderUnit hu);
+/*
+ * Returns the file descriptor associated with HeaderUnit (or -1, if 
+ * if no file is open.)  This is only needed if you used fh_file() to
+ * open a file and you need to read or write its file descriptor directly.
+ */
+fh_result	fh_read(HeaderUnit hu, int fd, double idx);
+/*
+ * Alternative to fh_file() if you opened the file descriptor yourself.
+ * fh_read() reads cards from a file descriptor and inserts them into
+ * the HeaderUnit cards starting at "idx" (use FH_AUTO to append to the end.)
+ * `fd' is left at start of image data in the file or 1st extension.
+ */
+
+fh_result fh_read_keyword_buffer(HeaderUnit hu, const char* fitsblock, double idx, int fast);
+/*
+ * Use this function if keywords are already in memory instead of a file.
+ *
+ * Inputs:
+ *    fitsblock    - Exactly 2880 bytes of FITS keyword data in memory.
+ *    idx          - Starting sorting number (or use FH_AUTO).
+ *    fast         - If non-zero, skip all integrity checks in order to
+ *                   make parsing the keywords as fast as possible.
+ *
+ * Outputs:
+ *    hu           - Keyword header unit with parsed keywords added.
+ *
+ * Returns:
+ *    FH_INVALID   - If hu or fitsblock is NULL.
+ *    FH_NO_MEMORY - Memory allocation error
+ *    FH_BAD_VALUE - Illegal characters in keyword value (only if !fast)
+ *    FH_SUCCESS     - OK.
+ *    FH_END_OF_FILE - OK, and END Keyword found.
+ */
+
+fh_result fh_count_cards(HeaderUnit hu);
+/*
+ * Any following fh_[re]write() call will print the number of cards
+ * needed instead of actually updating a file.  This mode is also
+ * selected when fh_file() is called with filedesc = FH_COUNT_CARDS.
+ */
+fh_result fh_reserve(HeaderUnit hu, int n);
+/*
+ * Set the number of COMMENT cards to reserve in the output when fh_write()
+ * is used to create a new FITS header.  NOT for use with fh_rewrite().
+ */
+fh_result fh_validate(HeaderUnit hu); /* fh_validate.c; for use by fhtool.c */
+
+fh_result fh_write(HeaderUnit hu, int fd);
+/*
+ * Writes cards in 2880 byte **PADDED** blocks to a file descriptor.
+ * This adds `END' line also, and file pointer `fd' is left at start of
+ * image data, just like it is after a call to fh_file().
+ */
+
+fh_result fh_write_keyword_buffer(HeaderUnit hu, char* buffer, int* fits_blocks_inout);
+/*
+ * Use this function to get formatted keywords into a memory buffer.
+ *
+ * Inputs:
+ *    hu                - Header unit structure with some keywords in it.
+ *    buffer            - Pointer to user allocated memory buffer
+ *    fits_blocks_inout - Pointer to buffer size / 2880 (FH_BLOCK_SIZE)
+ *
+ * Outputs:
+ *    fits_blocks_inout - Returns with the number of 2880-byte blocks copied.
+ *
+ * Returns:
+ *    FH_INVALID   - An argument was null or invalid.
+ *    FH_NO_SPACE  - Partial header copied, but there was insufficient space.
+ *    FH_NO_MEMORY - Memory allocation error occurred previously (on fh_set)
+ *    FH_SUCCESS   - OK.
+ */
+
+fh_result fh_map_raw_image(HeaderUnit hu, void** data, int size);
+fh_result fh_munmap_raw_image(HeaderUnit hu);
+/*
+ * These calls give the calling program access to a memory mapped pointer
+ * to the data in the FITS file.  The data format is equivalent to what
+ * would be produced by fh_read_image() with typesize=FH_TYPESIZE_RAW.
+ * Whether or not the file can be modified through the memory-mapped
+ * pointer depends on whether fh_mode=FH_FILE_RDONLY or FH_FILE_RDWR
+ * in the call to fh_file() that opened the file.  Be sure to use
+ * fh_munmap_raw_image() when done.
+ *
+ * `size' must match the exact number bytes of data which should be in
+ * the file, according to its NAXIS and BITPIX values, excluding padding.
+ *
+ * %%% TODO: FH_FILE_RDWR is completely unimplemented!
+ *
+ * %%% TODO: File locking is not handled properly yet.  For now, use
+ * FH_FILE_RDONLY_NOLOCK and FH_FILE_RDWR_NOLOCK, especially on MEF
+ * files where the locks are left in place until the file is closed
+ * otherwise!
+ */
+
+fh_result fh_write_image(HeaderUnit hu, int fd, void* data, int size, int typesize);
+fh_result fh_write_padding(HeaderUnit hu, int fd);
+fh_result fh_write_padded_image(HeaderUnit hu, int fd, void* data, int size, int typesize);
+/*
+ * fh_write_image and fh_write_padded_image writes exactly `size' bytes of
+ * `data' at the current file position of `fd'.  In the case of
+ * fh_write_padded_image, it is followed by enough padding to reach an
+ * FH_BLOCK_SIZE boundary, and `size' must match what the library
+ * calculates from the NAXIS and BITPIX values in `hu', excluding padding.
+ *
+ * fh_write_padding writes padding meant to go AFTER THE DATA.  (The header
+ * is automatically padded.)  This routine is used if you write the data
+ * to fd yourself, or in segments using fh_write_image().
+ */
+fh_result fh_read_image(HeaderUnit hu, int fd, void* data, int size, int typesize);
+fh_result fh_read_padding(HeaderUnit hu, int fd);
+fh_result fh_read_padded_image(HeaderUnit hu, int fd, void* data, int size, int typesize);
+/*
+ * Read image data into buffer.  Padding is not copied into *data.
+ * To read data in segments, use fh_read_image() followed by a final
+ * call to fh_read_padding().  Calling fh_read_padding() and ensuring
+ * that it returns FH_SUCCESS helps ensure that the entire file was
+ * read correctly.
+ *
+ * Use the final form, fh_read_padded_image() to read the entire data
+ * in one call.  In this case, as with fh_write_padded_image(), `size'
+ * must match the exact number bytes of data which should be in the
+ * file, according to its NAXIS and BITPIX values, excluding padding.
+ */
+fh_result fh_copy_padded_image(HeaderUnit hu, int fd_out, int fd_in);
+/*
+ * Read image data for `fd_out' from `fd_in'.
+ */
+fh_result fh_copy_and_verify_padded_image(HeaderUnit hu, int fd_out, int fd_in);
+/*
+ * Just like fh_copy_padded_image, but with an additional check for blocks
+ * of data with zero pixels.
+ */
+
+/* WARNING: If you intend to make a utility that can read from pipes
+ * (stdin) then you should avoid the following functions.  The are the
+ * only routines which need to be able to seek in a file.  If you are
+ * always reading from a file, this routines are ok.
+ */
+/* ------------- BEGIN ROUTINES WHICH USE lseek() ....  ------------ */
+fh_result fh_reserve_padded_image(HeaderUnit hu, int fd);
+/*
+ * This is like fh_write_padded_image(), except that it quickly seeks
+ * to the location where the last byte of actual image data will
+ * eventually go, writes a NUL character, and then writes all of the
+ * padding.  This sets things up for a future write by mmap.
+ */
+fh_result fh_rewrite(HeaderUnit hu);
+/*
+ * This call is only valid if fh_read() has been called to create `hu' in the
+ * first place.  Headers are written back to the same file from which they
+ * were read.  Your program should check for FH_NO_SPACE (and any other non-
+ * FH_SUCCESS returns).  FH_NO_SPACE means there was not enough room to
+ * rewrite the modified header unit back to the same file.
+ */
+void fh_link_ehu_to_phu(HeaderUnit ehu, HeaderUnit phu);
+
+HeaderUnit fh_ehu(HeaderUnit phu, int number);
+HeaderUnit fh_ehu_by_imageid(HeaderUnit phu, int imageid);
+HeaderUnit fh_ehu_by_extname(HeaderUnit phu, const char* extname);
+/*
+ * `phu' must be first be filled from a file by fh_read().
+ * `number' = 0 returns the phu and seeks the file to end of the phu cards.
+ * `number' = 1,2,3 returns the extension 1,2,3 and seeks to the start of data.
+ * Last two functions search for matching IMAGEID or EXTNAME cards.
+ */
+/* ------------- END OF ROUTINES WHICH USE lseek() ...  ------------ */
+
+int fh_extensions(HeaderUnit hu); /* Count extensions (0 if EXTEND=F) */
+
+int fh_image_bytes(HeaderUnit hu); /* Proper # of image bytes for hu */
+int fh_image_blocks(HeaderUnit hu); /* Same value, div 2880, rounded up */
+int fh_header_blocks(HeaderUnit hu); /* # of header bytes, div 2880, rnd. up */
+/*
+ * The number of image_blocks is calculated from hu's BITPIX and NAXIS cards.
+ * The image_blocks functions return 0 if BITPIX or an NAXIS card is missing.
+ */
+/* ----------------------
+ * Getting Keyword Values
+ * ----------------------
+ */
+fh_result fh_get_bool(HeaderUnit hu, const char* name, fh_bool* value);
+fh_result fh_get_int(HeaderUnit hu, const char* name, int* value);
+fh_result fh_get_flt(HeaderUnit hu, const char* name, double* value);
+fh_result fh_get_str(HeaderUnit hu, const char* name, char* value, int maxlen);
+/*
+ * Get FITS card values from `hu'.
+ * For fh_get_str(), `maxlen' is the size of the buffer, including
+ * space for a '\0' termination character which will be added by
+ * this routine.  If it doesn't fit, a FH_BAD_VALUE will be returned.
+ * (Pass buffers of FH_MAX_STRLEN + 1 to be sure this doesn't happen.)
+ */
+double fh_idx_after(HeaderUnit hu, const char* name);
+double fh_idx_before(HeaderUnit hu, const char* name);
+/*
+ * Get a value for a new `idx' which will cause a new card to be inserted
+ * just after (or before) an existing card `name'.  If `name' does not
+ * exist, this function returns FH_AUTO, which causes the new card to be
+ * added to the end of the header.
+ */
+fh_result fh_search(HeaderUnit hu, const char* name, double* idx);
+/*
+ * Search for a particular card, and (if idx!=0), save a copy of its
+ * internal sorting number.  The `idx' is useful if you need to insert
+ * cards just before or after those read from a file.  (Increment or
+ * decrement the idx value by .000001)
+ */
+fh_result fh_show(HeaderUnit hu); /* Print `hu' to screen for debugging */
+
+/* ----------------------
+ * Setting Keyword Values
+ * ----------------------
+ */
+fh_result fh_remove(HeaderUnit hu, const char* name);
+/*
+ * Removes a card `name' from `hu'.  COMMENTS cannot be removed.
+ */
+fh_result fh_set_all_units(HeaderUnit hu);
+/*
+ * By default, if fh_set*() operations are performed on a PHU read
+ * from a file, they are not applied to extension units.  Call this
+ * function BEFORE calling any other fh_set* functions on a PHU when
+ * you also want the extensions (which you'd get with fh_ehu()) to
+ * be changed, otherwise fh_set() only applies to the current HeaderUnit.
+ */
+void fh_set_str(HeaderUnit hu, double idx, const char* name,
+		const char* value, const char* comment);
+void fh_set_com(HeaderUnit hu, double idx, const char* name,
+		const char* comment);
+void fh_set_int(HeaderUnit hu, double idx, const char* name,
+		int value, const char* comment);
+void fh_set_flt(HeaderUnit hu, double idx, const char* name,
+		double value, int significant_digits, const char* comment);
+void fh_set_pfl(HeaderUnit hu, double idx, const char* name,
+		double value, int decimal_places, const char* comments);
+void fh_set_bool(HeaderUnit hu, double idx, const char* name,
+		 fh_bool value, const char* comment);
+/*
+ * Change/Create FITS card in table of type string, integer, or floating point.
+ * The comment field may get silently truncated if it doesn't fit in 80 cols.
+ */
+void fh_set_val(HeaderUnit hu, double idx, const char* name,
+		const char* value, const char* comment);
+/*
+ * This final form of fh_set is used by neodatah to insert pre-formatted
+ * FITS cards (80 bytes) obtained from the status server staging area.
+ */
+void fh_set_card(HeaderUnit hu, double idx, const char* card);
+/*
+ * This one is used by the nheader command in DetCom to set a value with
+ * "auto-detected" type of float, int, boolean, or string.  Use typed
+ * functions instead, when the value type is known.
+ */
+const char* fh_first(HeaderUnit hu);	/* See examples.  These are */
+const char* fh_next(HeaderUnit hu);	/* used to iterate through a list */
+double fh_idx(HeaderUnit hu); /* idx of the last card returned by fh_next */
+fh_result fh_merge(HeaderUnit hu, const HeaderUnit source); /* source unchanged */
+#endif /* _INCLUDED_fh */
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.asm
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.asm	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.asm	(revision 23490)
@@ -0,0 +1,786 @@
+DETCOM_SIMPLE MACRO ARG
+    COBJ "detcom:dheader 0.0 SIMPLE \"\ARG\" \"Standard FITS\""
+    ENDM
+DETCOM_XTENSION MACRO ARG
+    COBJ "detcom:dheader 0.0 XTENSION \"\ARG\" \"\""
+    ENDM
+DETCOM_BITPIX MACRO ARG
+    COBJ "detcom:dheader 1.0 BITPIX \"\ARG\" \"Bits per pixel\""
+    ENDM
+DETCOM_NAXIS MACRO ARG
+    COBJ "detcom:dheader 2.0 NAXIS \"\ARG\" \"Number of axes\""
+    ENDM
+DETCOM_NAXIS1 MACRO ARG
+    COBJ "detcom:dheader 2.1 NAXIS1 \"\ARG\" \"Number of pixel columns\""
+    ENDM
+DETCOM_NAXIS2 MACRO ARG
+    COBJ "detcom:dheader 2.2 NAXIS2 \"\ARG\" \"Number of pixel rows\""
+    ENDM
+DETCOM_NAXIS3 MACRO ARG
+    COBJ "detcom:dheader 2.3 NAXIS3 \"\ARG\" \"Number of stacked frames (cube)\""
+    ENDM
+DETCOM_EXTEND MACRO ARG
+    COBJ "detcom:dheader 3.0 EXTEND \"\ARG\" \"File contains extensions\""
+    ENDM
+DETCOM_NEXTEND MACRO ARG
+    COBJ "detcom:dheader 3.1 NEXTEND \"\ARG\" \"Number of extensions\""
+    ENDM
+DETCOM_GROUPS MACRO ARG
+    COBJ "detcom:dheader 4.0 GROUPS \"\ARG\" \"File contains random groups records\""
+    ENDM
+DETCOM_PCOUNT MACRO ARG
+    COBJ "detcom:dheader 5.0 PCOUNT \"\ARG\" \"Random parameters before each array in a group\""
+    ENDM
+DETCOM_GCOUNT MACRO ARG
+    COBJ "detcom:dheader 6.0 GCOUNT \"\ARG\" \"Number of random groups\""
+    ENDM
+DETCOM_TFIELDS MACRO ARG
+    COBJ "detcom:dheader 7.0000 TFIELDS \"\ARG\" \"Number of fields in a row\""
+    ENDM
+DETCOM_TFORM1 MACRO ARG
+    COBJ "detcom:dheader 7.0011 TFORM1 \"\ARG\" \"Table format for field 1\""
+    ENDM
+DETCOM_TBCOL1 MACRO ARG
+    COBJ "detcom:dheader 7.0012 TBCOL1 \"\ARG\" \"Start Column for field 1\""
+    ENDM
+DETCOM_TFORM2 MACRO ARG
+    COBJ "detcom:dheader 7.0021 TFORM2 \"\ARG\" \"Table format for field 2\""
+    ENDM
+DETCOM_TBCOL2 MACRO ARG
+    COBJ "detcom:dheader 7.0022 TBCOL2 \"\ARG\" \"Start Column for field 2\""
+    ENDM
+DETCOM_TFORM3 MACRO ARG
+    COBJ "detcom:dheader 7.0031 TFORM3 \"\ARG\" \"Table format for field 3\""
+    ENDM
+DETCOM_TBCOL3 MACRO ARG
+    COBJ "detcom:dheader 7.0032 TBCOL3 \"\ARG\" \"Start Column for field 3\""
+    ENDM
+DETCOM_TFORM4 MACRO ARG
+    COBJ "detcom:dheader 7.0041 TFORM4 \"\ARG\" \"Table format for field 4\""
+    ENDM
+DETCOM_TBCOL4 MACRO ARG
+    COBJ "detcom:dheader 7.0042 TBCOL4 \"\ARG\" \"Start Column for field 4\""
+    ENDM
+DETCOM_TFORM5 MACRO ARG
+    COBJ "detcom:dheader 7.0051 TFORM5 \"\ARG\" \"Table format for field 5\""
+    ENDM
+DETCOM_TBCOL5 MACRO ARG
+    COBJ "detcom:dheader 7.0052 TBCOL5 \"\ARG\" \"Start Column for field 5\""
+    ENDM
+DETCOM_CMMTOBS MACRO ARG
+    COBJ "detcom:dheader 51.0 CMMTOBS \"\ARG\" \"\""
+    ENDM
+DETCOM_CMMTSEQ MACRO ARG
+    COBJ "detcom:dheader 52.0 CMMTSEQ \"\ARG\" \"\""
+    ENDM
+DETCOM_OBJECT MACRO ARG
+    COBJ "detcom:dheader 53.0 OBJECT \"\ARG\" \"\""
+    ENDM
+DETCOM_OBSERVER MACRO ARG
+    COBJ "detcom:dheader 54.0 OBSERVER \"\ARG\" \"\""
+    ENDM
+DETCOM_PI_NAME MACRO ARG
+    COBJ "detcom:dheader 55.0 PI_NAME \"\ARG\" \"\""
+    ENDM
+DETCOM_RUNID MACRO ARG
+    COBJ "detcom:dheader 56.0 RUNID \"\ARG\" \"\""
+    ENDM
+DETCOM_FILENAME MACRO ARG
+    COBJ "detcom:dheader 71.00 FILENAME \"\ARG\" \"Base filename at acquisition\""
+    ENDM
+DETCOM_PATHNAME MACRO ARG
+    COBJ "detcom:dheader 71.01 PATHNAME \"\ARG\" \"Original directory name at acquisition\""
+    ENDM
+DETCOM_EXTNAME MACRO ARG
+    COBJ "detcom:dheader 71.10 EXTNAME \"\ARG\" \"Extension name\""
+    ENDM
+DETCOM_EXTVER MACRO ARG
+    COBJ "detcom:dheader 71.20 EXTVER \"\ARG\" \"Extension version\""
+    ENDM
+DETCOM_DATE MACRO ARG
+    COBJ "detcom:dheader 74.00 DATE \"\ARG\" \"UTC Date of file creation\""
+    ENDM
+DETCOM_HSTTIME MACRO ARG
+    COBJ "detcom:dheader 74.10 HSTTIME \"\ARG\" \"Local time in Hawaii\""
+    ENDM
+DETCOM_IMAGESWV MACRO ARG
+    COBJ "detcom:dheader 77.00 IMAGESWV \"\ARG\" \"Image creation software version\""
+    ENDM
+DETCOM_DETECTOR MACRO ARG
+    COBJ "detcom:dheader 91.0 DETECTOR \"\ARG\" \"Science Detector\""
+    ENDM
+DETCOM_INSTRUME MACRO ARG
+    COBJ "detcom:dheader 92.0 INSTRUME \"\ARG\" \"Instrument Name\""
+    ENDM
+DETCOM_INSTMODE MACRO ARG
+    COBJ "detcom:dheader 92.1 INSTMODE \"\ARG\" \"Instrument Mode\""
+    ENDM
+DETCOM_DETSIZE MACRO ARG
+    COBJ "detcom:dheader 102.0 DETSIZE \"\ARG\" \"Total data pixels in full mosaic\""
+    ENDM
+DETCOM_RASTER MACRO ARG
+    COBJ "detcom:dheader 103.0 RASTER \"\ARG\" \"\""
+    ENDM
+DETCOM_CCDSUM MACRO ARG
+    COBJ "detcom:dheader 105.0 CCDSUM \"\ARG\" \"Binning factors\""
+    ENDM
+DETCOM_CCDBIN1 MACRO ARG
+    COBJ "detcom:dheader 105.1 CCDBIN1 \"\ARG\" \"Binning factor along first axis\""
+    ENDM
+DETCOM_CCDBIN2 MACRO ARG
+    COBJ "detcom:dheader 105.2 CCDBIN2 \"\ARG\" \"Binning factor along second axis\""
+    ENDM
+DETCOM_PIXSIZE MACRO ARG
+    COBJ "detcom:dheader 110.0 PIXSIZE \"\ARG\" \"Pixel size for both axes (microns)\""
+    ENDM
+DETCOM_PIXSIZE1 MACRO ARG
+    COBJ "detcom:dheader 111.1 PIXSIZE1 \"\ARG\" \"Pixel size for axis 1 (microns)\""
+    ENDM
+DETCOM_PIXSIZE2 MACRO ARG
+    COBJ "detcom:dheader 111.2 PIXSIZE2 \"\ARG\" \"Pixel size for axis 2 (microns)\""
+    ENDM
+DETCOM_PIXSCAL1 MACRO ARG
+    COBJ "detcom:dheader 112.1 PIXSCAL1 \"\ARG\" \"Pixel scale for axis 1 (arcsec/pixel)\""
+    ENDM
+DETCOM_PIXSCAL2 MACRO ARG
+    COBJ "detcom:dheader 112.2 PIXSCAL2 \"\ARG\" \"Pixel scale for axis 2 (arcsec/pixel)\""
+    ENDM
+DETCOM_AMPLIST MACRO ARG
+    COBJ "detcom:dheader 130.0 AMPLIST \"\ARG\" \"List of amplifiers for this image\""
+    ENDM
+DETCOM_AMPNAME MACRO ARG
+    COBJ "detcom:dheader 131.0 AMPNAME \"\ARG\" \"Amplifier name\""
+    ENDM
+DETCOM_CCDSIZE MACRO ARG
+    COBJ "detcom:dheader 140.0 CCDSIZE \"\ARG\" \"Detector imaging area size\""
+    ENDM
+DETCOM_DETSEC MACRO ARG
+    COBJ "detcom:dheader 140.1 DETSEC \"\ARG\" \"Mosaic area of the detector\""
+    ENDM
+DETCOM_DETSECA MACRO ARG
+    COBJ "detcom:dheader 140.11 DETSECA \"\ARG\" \"Mosaic area of the detector from Amp A\""
+    ENDM
+DETCOM_DETSECB MACRO ARG
+    COBJ "detcom:dheader 140.12 DETSECB \"\ARG\" \"Mosaic area of the detector from Amp B\""
+    ENDM
+DETCOM_DETSECC MACRO ARG
+    COBJ "detcom:dheader 140.13 DETSECC \"\ARG\" \"Mosaic area of the detector from Amp C\""
+    ENDM
+DETCOM_DETSECD MACRO ARG
+    COBJ "detcom:dheader 140.14 DETSECD \"\ARG\" \"Mosaic area of the detector from Amp D\""
+    ENDM
+DETCOM_DATASEC MACRO ARG
+    COBJ "detcom:dheader 140.2 DATASEC \"\ARG\" \"Imaging area of the detector\""
+    ENDM
+DETCOM_BIASSEC MACRO ARG
+    COBJ "detcom:dheader 140.3 BIASSEC \"\ARG\" \"Overscan (bias) area of the detector\""
+    ENDM
+DETCOM_ASECA MACRO ARG
+    COBJ "detcom:dheader 141.11 ASECA \"\ARG\" \"Section from Amp A (non-contig. bias excluded)\""
+    ENDM
+DETCOM_ASECB MACRO ARG
+    COBJ "detcom:dheader 141.12 ASECB \"\ARG\" \"Section from Amp B (non-contig. bias excluded)\""
+    ENDM
+DETCOM_ASECC MACRO ARG
+    COBJ "detcom:dheader 141.13 ASECC \"\ARG\" \"Section from Amp C (non-contig. bias excluded)\""
+    ENDM
+DETCOM_ASECD MACRO ARG
+    COBJ "detcom:dheader 141.14 ASECD \"\ARG\" \"Section from Amp D (non-contig. bias excluded)\""
+    ENDM
+DETCOM_BSECA MACRO ARG
+    COBJ "detcom:dheader 141.21 BSECA \"\ARG\" \"Overscan (bias) area from Amp A\""
+    ENDM
+DETCOM_BSECB MACRO ARG
+    COBJ "detcom:dheader 141.22 BSECB \"\ARG\" \"Overscan (bias) area from Amp B\""
+    ENDM
+DETCOM_BSECC MACRO ARG
+    COBJ "detcom:dheader 141.23 BSECC \"\ARG\" \"Overscan (bias) area from Amp C\""
+    ENDM
+DETCOM_BSECD MACRO ARG
+    COBJ "detcom:dheader 141.24 BSECD \"\ARG\" \"Overscan (bias) area from Amp D\""
+    ENDM
+DETCOM_CSECA MACRO ARG
+    COBJ "detcom:dheader 141.31 CSECA \"\ARG\" \"Section in full CCD for DSECA\""
+    ENDM
+DETCOM_CSECB MACRO ARG
+    COBJ "detcom:dheader 141.32 CSECB \"\ARG\" \"Section in full CCD for DSECB\""
+    ENDM
+DETCOM_CSECC MACRO ARG
+    COBJ "detcom:dheader 141.33 CSECC \"\ARG\" \"Section in full CCD for DSECC\""
+    ENDM
+DETCOM_CSECD MACRO ARG
+    COBJ "detcom:dheader 141.34 CSECD \"\ARG\" \"Section in full CCD for DSECD\""
+    ENDM
+DETCOM_DSECA MACRO ARG
+    COBJ "detcom:dheader 141.41 DSECA \"\ARG\" \"Imaging area from Amp A\""
+    ENDM
+DETCOM_DSECB MACRO ARG
+    COBJ "detcom:dheader 141.42 DSECB \"\ARG\" \"Imaging area from Amp B\""
+    ENDM
+DETCOM_DSECC MACRO ARG
+    COBJ "detcom:dheader 141.43 DSECC \"\ARG\" \"Imaging area from Amp C\""
+    ENDM
+DETCOM_DSECD MACRO ARG
+    COBJ "detcom:dheader 141.44 DSECD \"\ARG\" \"Imaging area from Amp D\""
+    ENDM
+DETCOM_TSECA MACRO ARG
+    COBJ "detcom:dheader 141.51 TSECA \"\ARG\" \"Trim section for Amp A\""
+    ENDM
+DETCOM_TSECB MACRO ARG
+    COBJ "detcom:dheader 141.52 TSECB \"\ARG\" \"Trim section for Amp B\""
+    ENDM
+DETCOM_TSECC MACRO ARG
+    COBJ "detcom:dheader 141.53 TSECC \"\ARG\" \"Trim section for Amp C\""
+    ENDM
+DETCOM_TSECD MACRO ARG
+    COBJ "detcom:dheader 141.54 TSECD \"\ARG\" \"Trim section for Amp D\""
+    ENDM
+DETCOM_CCDNAME MACRO ARG
+    COBJ "detcom:dheader 150.1 CCDNAME \"\ARG\" \"Name of the CCD (manufacturer reference)\""
+    ENDM
+DETCOM_CCDNICK MACRO ARG
+    COBJ "detcom:dheader 150.2 CCDNICK \"\ARG\" \"Nickname of the CCD\""
+    ENDM
+DETCOM_MAXLIN MACRO ARG
+    COBJ "detcom:dheader 152.0 MAXLIN \"\ARG\" \"Maximum linearity value (ADU)\""
+    ENDM
+DETCOM_MAXLINA MACRO ARG
+    COBJ "detcom:dheader 152.01 MAXLINA \"\ARG\" \"Maximum linearity value for Amp A (ADU)\""
+    ENDM
+DETCOM_MAXLINB MACRO ARG
+    COBJ "detcom:dheader 152.02 MAXLINB \"\ARG\" \"Maximum linearity value for Amp B (ADU)\""
+    ENDM
+DETCOM_MAXLINC MACRO ARG
+    COBJ "detcom:dheader 152.03 MAXLINC \"\ARG\" \"Maximum linearity value for Amp C (ADU)\""
+    ENDM
+DETCOM_MAXLIND MACRO ARG
+    COBJ "detcom:dheader 152.04 MAXLIND \"\ARG\" \"Maximum linearity value for Amp D (ADU)\""
+    ENDM
+DETCOM_SATURATE MACRO ARG
+    COBJ "detcom:dheader 152.1 SATURATE \"\ARG\" \"Saturation value (ADU)\""
+    ENDM
+DETCOM_GAIN MACRO ARG
+    COBJ "detcom:dheader 155.0 GAIN \"\ARG\" \"Amplifier gain (electrons/ADU)\""
+    ENDM
+DETCOM_GAINA MACRO ARG
+    COBJ "detcom:dheader 155.01 GAINA \"\ARG\" \"Amp A gain (electrons/ADU)\""
+    ENDM
+DETCOM_GAINB MACRO ARG
+    COBJ "detcom:dheader 155.02 GAINB \"\ARG\" \"Amp B gain (electrons/ADU)\""
+    ENDM
+DETCOM_GAINC MACRO ARG
+    COBJ "detcom:dheader 155.03 GAINC \"\ARG\" \"Amp C gain (electrons/ADU)\""
+    ENDM
+DETCOM_GAIND MACRO ARG
+    COBJ "detcom:dheader 155.04 GAIND \"\ARG\" \"Amp D gain (electrons/ADU)\""
+    ENDM
+DETCOM_RDNOISE MACRO ARG
+    COBJ "detcom:dheader 156.0 RDNOISE \"\ARG\" \"Read noise (electrons)\""
+    ENDM
+DETCOM_RDNOISEA MACRO ARG
+    COBJ "detcom:dheader 156.01 RDNOISEA \"\ARG\" \"Amp A read noise (electrons)\""
+    ENDM
+DETCOM_RDNOISEB MACRO ARG
+    COBJ "detcom:dheader 156.02 RDNOISEB \"\ARG\" \"Amp B read noise (electrons)\""
+    ENDM
+DETCOM_RDNOISEC MACRO ARG
+    COBJ "detcom:dheader 156.03 RDNOISEC \"\ARG\" \"Amp C read noise (electrons)\""
+    ENDM
+DETCOM_RDNOISED MACRO ARG
+    COBJ "detcom:dheader 156.04 RDNOISED \"\ARG\" \"Amp D read noise (electrons)\""
+    ENDM
+DETCOM_DCURRENT MACRO ARG
+    COBJ "detcom:dheader 157.0 DCURRENT \"\ARG\" \"Dark current (ADU/pixel/second)\""
+    ENDM
+DETCOM_DARKCUR MACRO ARG
+    COBJ "detcom:dheader 157.1 DARKCUR \"\ARG\" \"Dark current (e-/pixel/hour)\""
+    ENDM
+DETCOM_QEPOINTS MACRO ARG
+    COBJ "detcom:dheader 158.0 QEPOINTS \"\ARG\" \"QE%@wavelength in nm\""
+    ENDM
+DETCOM_CONSWV MACRO ARG
+    COBJ "detcom:dheader 170.0 CONSWV \"\ARG\" \"Controller software DSPID and SERNO versions\""
+    ENDM
+DETCOM_DETSTAT MACRO ARG
+    COBJ "detcom:dheader 180.0 DETSTAT \"\ARG\" \"Detector status\""
+    ENDM
+DETCOM_DETTEM MACRO ARG
+    COBJ "detcom:dheader 190.0 DETTEM \"\ARG\" \"Detector temperature\""
+    ENDM
+DETCOM_TELESCOP MACRO ARG
+    COBJ "detcom:dheader 501.1 TELESCOP \"\ARG\" \"\""
+    ENDM
+DETCOM_ORIGIN MACRO ARG
+    COBJ "detcom:dheader 501.2 ORIGIN \"\ARG\" \"Canada-France-Hawaii Telescope\""
+    ENDM
+DETCOM_TELSTAT MACRO ARG
+    COBJ "detcom:dheader 503.0 TELSTAT \"\ARG\" \"Telescope Control System status\""
+    ENDM
+DETCOM_TIMESYS MACRO ARG
+    COBJ "detcom:dheader 510.0 TIMESYS \"\ARG\" \"Time System for DATExxxx\""
+    ENDM
+DETCOM_UTIME MACRO ARG
+    COBJ "detcom:dheader 512.0 UTIME \"\ARG\" \"Time at start of observation (UT)\""
+    ENDM
+DETCOM_SIDTIME MACRO ARG
+    COBJ "detcom:dheader 514.0 SIDTIME \"\ARG\" \"Sidereal time at start of observation\""
+    ENDM
+DETCOM_EPOCH MACRO ARG
+    COBJ "detcom:dheader 521.0 EPOCH \"\ARG\" \"Equinox of coordinates\""
+    ENDM
+DETCOM_EQUINOX MACRO ARG
+    COBJ "detcom:dheader 521.1 EQUINOX \"\ARG\" \"Equinox of coordinates\""
+    ENDM
+DETCOM_RADECSYS MACRO ARG
+    COBJ "detcom:dheader 522.0 RADECSYS \"\ARG\" \"Coordinate system for equinox (FK4/FK5/GAPPT)\""
+    ENDM
+DETCOM_RA MACRO ARG
+    COBJ "detcom:dheader 522.1 RA \"\ARG\" \"Object right ascension\""
+    ENDM
+DETCOM_DEC MACRO ARG
+    COBJ "detcom:dheader 522.2 DEC \"\ARG\" \"Object declination\""
+    ENDM
+DETCOM_CTYPE1 MACRO ARG
+    COBJ "detcom:dheader 525.211 CTYPE1 \"\ARG\" \"WCS Coordinate type\""
+    ENDM
+DETCOM_CTYPE2 MACRO ARG
+    COBJ "detcom:dheader 525.212 CTYPE2 \"\ARG\" \"WCS Coordinate type\""
+    ENDM
+DETCOM_CD1_1 MACRO ARG
+    COBJ "detcom:dheader 525.411 CD1_1 \"\ARG\" \"WCS Coordinate scale matrix\""
+    ENDM
+DETCOM_CD1_2 MACRO ARG
+    COBJ "detcom:dheader 525.412 CD1_2 \"\ARG\" \"WCS Coordinate scale matrix\""
+    ENDM
+DETCOM_CD2_1 MACRO ARG
+    COBJ "detcom:dheader 525.421 CD2_1 \"\ARG\" \"WCS Coordinate scale matrix\""
+    ENDM
+DETCOM_CD2_2 MACRO ARG
+    COBJ "detcom:dheader 525.422 CD2_2 \"\ARG\" \"WCS Coordinate scale matrix\""
+    ENDM
+DETCOM_NGUIDER MACRO ARG
+    COBJ "detcom:dheader 530.0 NGUIDER \"\ARG\" \"TCS Number of guiders\""
+    ENDM
+DETCOM_NGUISTAR MACRO ARG
+    COBJ "detcom:dheader 530.01 NGUISTAR \"\ARG\" \"TCS number of guide stars/probes in use\""
+    ENDM
+DETCOM_GUINAME MACRO ARG
+    COBJ "detcom:dheader 530.1 GUINAME \"\ARG\" \"TCS guider name\""
+    ENDM
+DETCOM_GUIEQUIN MACRO ARG
+    COBJ "detcom:dheader 530.21 GUIEQUIN \"\ARG\" \"TCS guider equinox\""
+    ENDM
+DETCOM_GUIRADEC MACRO ARG
+    COBJ "detcom:dheader 530.22 GUIRADEC \"\ARG\" \"TCS guider system for equinox\""
+    ENDM
+DETCOM_GUIRA MACRO ARG
+    COBJ "detcom:dheader 530.23 GUIRA \"\ARG\" \"TCS guider right ascension\""
+    ENDM
+DETCOM_GUIDEC MACRO ARG
+    COBJ "detcom:dheader 530.24 GUIDEC \"\ARG\" \"TCS guider declination\""
+    ENDM
+DETCOM_GUIOBJN MACRO ARG
+    COBJ "detcom:dheader 530.3 GUIOBJN \"\ARG\" \"TCS guider object name\""
+    ENDM
+DETCOM_GUIFLUX MACRO ARG
+    COBJ "detcom:dheader 530.6 GUIFLUX \"\ARG\" \"TCS guider flux\""
+    ENDM
+DETCOM_SKYFLUX MACRO ARG
+    COBJ "detcom:dheader 530.8 SKYFLUX \"\ARG\" \"TCS total sky flux\""
+    ENDM
+DETCOM_GUINAME1 MACRO ARG
+    COBJ "detcom:dheader 531.1 GUINAME1 \"\ARG\" \"TCS guider #1 identification\""
+    ENDM
+DETCOM_GUIEQUI1 MACRO ARG
+    COBJ "detcom:dheader 531.21 GUIEQUI1 \"\ARG\" \"TCS guider #1 equinox\""
+    ENDM
+DETCOM_GUIRADE1 MACRO ARG
+    COBJ "detcom:dheader 531.22 GUIRADE1 \"\ARG\" \"TCS guider #1 system for equinox\""
+    ENDM
+DETCOM_GUIRA1 MACRO ARG
+    COBJ "detcom:dheader 531.23 GUIRA1 \"\ARG\" \"TCS guider #1 right ascension\""
+    ENDM
+DETCOM_GUIDEC1 MACRO ARG
+    COBJ "detcom:dheader 531.24 GUIDEC1 \"\ARG\" \"TCS guider #1 declination\""
+    ENDM
+DETCOM_GUIOBJN1 MACRO ARG
+    COBJ "detcom:dheader 531.3 GUIOBJN1 \"\ARG\" \"TCS guider #1 object name\""
+    ENDM
+DETCOM_GUIFLUX1 MACRO ARG
+    COBJ "detcom:dheader 531.6 GUIFLUX1 \"\ARG\" \"TCS guider #1 flux\""
+    ENDM
+DETCOM_GUINAME2 MACRO ARG
+    COBJ "detcom:dheader 532.1 GUINAME2 \"\ARG\" \"TCS guider #2 identification\""
+    ENDM
+DETCOM_GUIEQUI2 MACRO ARG
+    COBJ "detcom:dheader 532.21 GUIEQUI2 \"\ARG\" \"TCS guider #2 equinox\""
+    ENDM
+DETCOM_GUIRADE2 MACRO ARG
+    COBJ "detcom:dheader 532.22 GUIRADE2 \"\ARG\" \"TCS guider #2 system for equinox\""
+    ENDM
+DETCOM_GUIRA2 MACRO ARG
+    COBJ "detcom:dheader 532.23 GUIRA2 \"\ARG\" \"TCS guider #2 right ascension\""
+    ENDM
+DETCOM_GUIDEC2 MACRO ARG
+    COBJ "detcom:dheader 532.24 GUIDEC2 \"\ARG\" \"TCS guider #2 declination\""
+    ENDM
+DETCOM_GUIOBJN2 MACRO ARG
+    COBJ "detcom:dheader 532.3 GUIOBJN2 \"\ARG\" \"TCS guider #2 object name\""
+    ENDM
+DETCOM_GUIFLUX2 MACRO ARG
+    COBJ "detcom:dheader 532.6 GUIFLUX2 \"\ARG\" \"TCS guider #2 flux\""
+    ENDM
+DETCOM_GUINAME3 MACRO ARG
+    COBJ "detcom:dheader 533.1 GUINAME3 \"\ARG\" \"TCS guider #3 identification\""
+    ENDM
+DETCOM_GUIEQUI3 MACRO ARG
+    COBJ "detcom:dheader 533.21 GUIEQUI3 \"\ARG\" \"TCS guider #3 equinox\""
+    ENDM
+DETCOM_GUIRADE3 MACRO ARG
+    COBJ "detcom:dheader 533.22 GUIRADE3 \"\ARG\" \"TCS guider #3 system for equinox\""
+    ENDM
+DETCOM_GUIRA3 MACRO ARG
+    COBJ "detcom:dheader 533.23 GUIRA3 \"\ARG\" \"TCS guider #3 right ascension\""
+    ENDM
+DETCOM_GUIDEC3 MACRO ARG
+    COBJ "detcom:dheader 533.24 GUIDEC3 \"\ARG\" \"TCS guider #3 declination\""
+    ENDM
+DETCOM_GUIOBJN3 MACRO ARG
+    COBJ "detcom:dheader 533.3 GUIOBJN3 \"\ARG\" \"TCS guider #3 object name\""
+    ENDM
+DETCOM_GUIFLUX3 MACRO ARG
+    COBJ "detcom:dheader 533.6 GUIFLUX3 \"\ARG\" \"TCS guider #3 flux\""
+    ENDM
+DETCOM_GUINAME4 MACRO ARG
+    COBJ "detcom:dheader 534.1 GUINAME4 \"\ARG\" \"TCS guider #4 identification\""
+    ENDM
+DETCOM_GUIEQUI4 MACRO ARG
+    COBJ "detcom:dheader 534.21 GUIEQUI4 \"\ARG\" \"TCS guider #4 equinox\""
+    ENDM
+DETCOM_GUIRADE4 MACRO ARG
+    COBJ "detcom:dheader 534.22 GUIRADE4 \"\ARG\" \"TCS guider #4 system for equinox\""
+    ENDM
+DETCOM_GUIRA4 MACRO ARG
+    COBJ "detcom:dheader 534.23 GUIRA4 \"\ARG\" \"TCS guider #4 right ascension\""
+    ENDM
+DETCOM_GUIDEC4 MACRO ARG
+    COBJ "detcom:dheader 534.24 GUIDEC4 \"\ARG\" \"TCS guider #4 declination\""
+    ENDM
+DETCOM_GUIOBJN4 MACRO ARG
+    COBJ "detcom:dheader 534.3 GUIOBJN4 \"\ARG\" \"TCS guider #4 object name\""
+    ENDM
+DETCOM_GUIFLUX4 MACRO ARG
+    COBJ "detcom:dheader 534.6 GUIFLUX4 \"\ARG\" \"TCS guider #4 flux\""
+    ENDM
+DETCOM_FOCUSID MACRO ARG
+    COBJ "detcom:dheader 550.0 FOCUSID \"\ARG\" \"Telescope focus in use\""
+    ENDM
+DETCOM_TELCONF MACRO ARG
+    COBJ "detcom:dheader 550.1 TELCONF \"\ARG\" \"Telescope focus in use\""
+    ENDM
+DETCOM_FOCUSPOS MACRO ARG
+    COBJ "detcom:dheader 551.0 FOCUSPOS \"\ARG\" \"Telescope focus encoder readout\""
+    ENDM
+DETCOM_TELFOCUS MACRO ARG
+    COBJ "detcom:dheader 551.1 TELFOCUS \"\ARG\" \"Telescope focus encoder readout\""
+    ENDM
+DETCOM_ISUSTATE MACRO ARG
+    COBJ "detcom:dheader 560.4 ISUSTATE \"\ARG\" \"ISU control state (Off/Only/TCS/Full/Frozen)\""
+    ENDM
+DETCOM_FSASTATE MACRO ARG
+    COBJ "detcom:dheader 570.4 FSASTATE \"\ARG\" \"FSA control state (Off/On/Paused)\""
+    ENDM
+DETCOM_FSANMOVE MACRO ARG
+    COBJ "detcom:dheader 570.5 FSANMOVE \"\ARG\" \"FSA number of actual moves in last 10 minutes\""
+    ENDM
+DETCOM_TCSGPSBC MACRO ARG
+    COBJ "detcom:dheader 580.11 TCSGPSBC \"\ARG\" \"TCS GPS read out in BCD\""
+    ENDM
+DETCOM_TCSRBUSS MACRO ARG
+    COBJ "detcom:dheader 580.13 TCSRBUSS \"\ARG\" \"TCS RBUSS clock time\""
+    ENDM
+DETCOM_TCSEPICS MACRO ARG
+    COBJ "detcom:dheader 580.14 TCSEPICS \"\ARG\" \"TCS EPICS clock time\""
+    ENDM
+DETCOM_TCSAMODE MACRO ARG
+    COBJ "detcom:dheader 580.15 TCSAMODE \"\ARG\" \"TCS acquisition mode - T/O/G/g for t/o/g coords\""
+    ENDM
+DETCOM_TCSENHA MACRO ARG
+    COBJ "detcom:dheader 580.51 TCSENHA \"\ARG\" \"TCS hour angle encoder bits reading\""
+    ENDM
+DETCOM_TCSENDEC MACRO ARG
+    COBJ "detcom:dheader 580.52 TCSENDEC \"\ARG\" \"TCS declination encoder bits reading\""
+    ENDM
+DETCOM_AOBLOOP MACRO ARG
+    COBJ "detcom:dheader 711.0 AOBLOOP \"\ARG\" \"AOB closed loop Open/Closed\""
+    ENDM
+DETCOM_LOOPNES MACRO ARG
+    COBJ "detcom:dheader 713.0 LOOPNES \"\ARG\" \"Loop type \"Nested\"/\"Tip/Tilt\"/\"Single\"\""
+    ENDM
+DETCOM_LOOPOPT MACRO ARG
+    COBJ "detcom:dheader 715.0 LOOPOPT \"\ARG\" \"Optimized loop control True/False\""
+    ENDM
+DETCOM_WFSGOPT MACRO ARG
+    COBJ "detcom:dheader 716.0 WFSGOPT \"\ARG\" \"WFS optical gain\""
+    ENDM
+DETCOM_WFSCOUNT MACRO ARG
+    COBJ "detcom:dheader 722.0 WFSCOUNT \"\ARG\" \"Total flux count on WFS\""
+    ENDM
+DETCOM_ADCPOS MACRO ARG
+    COBJ "detcom:dheader 751.0 ADCPOS \"\ARG\" \"AOB ADC position In/Out\""
+    ENDM
+DETCOM_BEAMSPID MACRO ARG
+    COBJ "detcom:dheader 754.0 BEAMSPID \"\ARG\" \"Beam splitter ID\""
+    ENDM
+DETCOM_BEAMSP MACRO ARG
+    COBJ "detcom:dheader 755.0 BEAMSP \"\ARG\" \"Beam splitter description\""
+    ENDM
+DETCOM_MIRSLIDE MACRO ARG
+    COBJ "detcom:dheader 756.0 MIRSLIDE \"\ARG\" \"AOB mirror slide \"F/20\"/\"F/8\"\""
+    ENDM
+DETCOM_WFSNDID MACRO ARG
+    COBJ "detcom:dheader 757.0 WFSNDID \"\ARG\" \"WFS ND filter position\""
+    ENDM
+DETCOM_FFLAMPON MACRO ARG
+    COBJ "detcom:dheader 910.0 FFLAMPON \"\ARG\" \"flatfield lamp status ON/OFF\""
+    ENDM
+DETCOM_FFLAMP MACRO ARG
+    COBJ "detcom:dheader 911.0 FFLAMP \"\ARG\" \"flatfield lamp intensity\""
+    ENDM
+DETCOM_CLAMP0ON MACRO ARG
+    COBJ "detcom:dheader 920.0 CLAMP0ON \"\ARG\" \"comparison lamp 0 status ON/OFF\""
+    ENDM
+DETCOM_CLAMP0 MACRO ARG
+    COBJ "detcom:dheader 920.1 CLAMP0 \"\ARG\" \"comparison lamp 0 description\""
+    ENDM
+DETCOM_CLAMP1ON MACRO ARG
+    COBJ "detcom:dheader 921.0 CLAMP1ON \"\ARG\" \"comparison lamp 1 status ON/OFF\""
+    ENDM
+DETCOM_CLAMP1 MACRO ARG
+    COBJ "detcom:dheader 921.1 CLAMP1 \"\ARG\" \"comparison lamp 1 description\""
+    ENDM
+DETCOM_CLAMP2ON MACRO ARG
+    COBJ "detcom:dheader 922.0 CLAMP2ON \"\ARG\" \"comparison lamp 2 status ON/OFF\""
+    ENDM
+DETCOM_CLAMP2 MACRO ARG
+    COBJ "detcom:dheader 922.1 CLAMP2 \"\ARG\" \"comparison lamp 2 description\""
+    ENDM
+DETCOM_CLAMP3ON MACRO ARG
+    COBJ "detcom:dheader 923.0 CLAMP3ON \"\ARG\" \"comparison lamp 3 status ON/OFF\""
+    ENDM
+DETCOM_CLAMP3 MACRO ARG
+    COBJ "detcom:dheader 923.1 CLAMP3 \"\ARG\" \"comparison lamp 3 description\""
+    ENDM
+DETCOM_CALIBL0 MACRO ARG
+    COBJ "detcom:dheader 930.0 CALIBL0 \"\ARG\" \"lamp 0 ON/OFF\""
+    ENDM
+DETCOM_CALIBL1 MACRO ARG
+    COBJ "detcom:dheader 931.0 CALIBL1 \"\ARG\" \"lamp 1 ON/OFF\""
+    ENDM
+DETCOM_CALIBL2 MACRO ARG
+    COBJ "detcom:dheader 932.0 CALIBL2 \"\ARG\" \"lamp 2 ON/OFF\""
+    ENDM
+DETCOM_CALIBL3 MACRO ARG
+    COBJ "detcom:dheader 933.0 CALIBL3 \"\ARG\" \"lamp 3 ON/OFF\""
+    ENDM
+DETCOM_CALIBL4 MACRO ARG
+    COBJ "detcom:dheader 934.0 CALIBL4 \"\ARG\" \"lamp 4 ON/OFF\""
+    ENDM
+DETCOM_CALIBL5 MACRO ARG
+    COBJ "detcom:dheader 935.0 CALIBL5 \"\ARG\" \"lamp 5 ON/OFF\""
+    ENDM
+DETCOM_CALIBL6 MACRO ARG
+    COBJ "detcom:dheader 936.0 CALIBL6 \"\ARG\" \"lamp 6 ON/OFF\""
+    ENDM
+DETCOM_CALIBL7 MACRO ARG
+    COBJ "detcom:dheader 937.0 CALIBL7 \"\ARG\" \"lamp 7 ON/OFF\""
+    ENDM
+DETCOM_CALIBL8 MACRO ARG
+    COBJ "detcom:dheader 938.0 CALIBL8 \"\ARG\" \"lamp 8 ON/OFF\""
+    ENDM
+DETCOM_CALIBL9 MACRO ARG
+    COBJ "detcom:dheader 939.0 CALIBL9 \"\ARG\" \"lamp 9 ON/OFF\""
+    ENDM
+DETCOM_FILTERID MACRO ARG
+    COBJ "detcom:dheader 1010.1 FILTERID \"\ARG\" \"wheel position\""
+    ENDM
+DETCOM_FILTER MACRO ARG
+    COBJ "detcom:dheader 1010.2 FILTER \"\ARG\" \"description of filter\""
+    ENDM
+DETCOM_FILTERBW MACRO ARG
+    COBJ "detcom:dheader 1010.3 FILTERBW \"\ARG\" \"filter bandwidth\""
+    ENDM
+DETCOM_FILTERWL MACRO ARG
+    COBJ "detcom:dheader 1010.4 FILTERWL \"\ARG\" \"filter wavelength\""
+    ENDM
+DETCOM_FILTERLB MACRO ARG
+    COBJ "detcom:dheader 1010.5 FILTERLB \"\ARG\" \"lower bound of filter (units/%?)\""
+    ENDM
+DETCOM_FILTERUB MACRO ARG
+    COBJ "detcom:dheader 1010.6 FILTERUB \"\ARG\" \"upper bound of filter (units/%?)\""
+    ENDM
+DETCOM_FILTSLID MACRO ARG
+    COBJ "detcom:dheader 1010.7 FILTSLID \"\ARG\" \"filter drawer number\""
+    ENDM
+DETCOM_WHEELAID MACRO ARG
+    COBJ "detcom:dheader 1020.1 WHEELAID \"\ARG\" \"'wheel' A position\""
+    ENDM
+DETCOM_WHEELADE MACRO ARG
+    COBJ "detcom:dheader 1020.2 WHEELADE \"\ARG\" \"description of filter\""
+    ENDM
+DETCOM_WHEELALB MACRO ARG
+    COBJ "detcom:dheader 1020.5 WHEELALB \"\ARG\" \"lower bound of filter A (units/%?)\""
+    ENDM
+DETCOM_WHEELAUB MACRO ARG
+    COBJ "detcom:dheader 1020.6 WHEELAUB \"\ARG\" \"upper bound of filter A (units/%?)\""
+    ENDM
+DETCOM_WHEELBID MACRO ARG
+    COBJ "detcom:dheader 1030.1 WHEELBID \"\ARG\" \"'wheel' B position\""
+    ENDM
+DETCOM_WHEELBDE MACRO ARG
+    COBJ "detcom:dheader 1030.2 WHEELBDE \"\ARG\" \"description of filter\""
+    ENDM
+DETCOM_WHEELBLB MACRO ARG
+    COBJ "detcom:dheader 1030.5 WHEELBLB \"\ARG\" \"lower bound of filter B (units/%?)\""
+    ENDM
+DETCOM_WHEELBUB MACRO ARG
+    COBJ "detcom:dheader 1030.6 WHEELBUB \"\ARG\" \"upper bound of filter B (units/%?)\""
+    ENDM
+DETCOM_INSTFOC MACRO ARG
+    COBJ "detcom:dheader 1101.0 INSTFOC \"\ARG\" \"internal instrument focus value\""
+    ENDM
+DETCOM_GRISMID MACRO ARG
+    COBJ "detcom:dheader 4101.0 GRISMID \"\ARG\" \"grism position\""
+    ENDM
+DETCOM_GRISM MACRO ARG
+    COBJ "detcom:dheader 4102.0 GRISM \"\ARG\" \"grism description\""
+    ENDM
+DETCOM_GRISSLID MACRO ARG
+    COBJ "detcom:dheader 4103.0 GRISSLID \"\ARG\" \"grism drawer number\""
+    ENDM
+DETCOM_MASKID MACRO ARG
+    COBJ "detcom:dheader 4111.0 MASKID \"\ARG\" \"mask position\""
+    ENDM
+DETCOM_MASK MACRO ARG
+    COBJ "detcom:dheader 4112.0 MASK \"\ARG\" \"mask description\""
+    ENDM
+DETCOM_MASKSLID MACRO ARG
+    COBJ "detcom:dheader 4113.0 MASKSLID \"\ARG\" \"mask slider number\""
+    ENDM
+DETCOM_DISPEL MACRO ARG
+    COBJ "detcom:dheader 4201.0 DISPEL \"\ARG\" \"grating description\""
+    ENDM
+DETCOM_DISPAXIS MACRO ARG
+    COBJ "detcom:dheader 4202.0 DISPAXIS \"\ARG\" \"dispersion axis (1 or 2)\""
+    ENDM
+DETCOM_DISPANG MACRO ARG
+    COBJ "detcom:dheader 4203.0 DISPANG \"\ARG\" \"grating angle in degrees\""
+    ENDM
+DETCOM_WAVELENG MACRO ARG
+    COBJ "detcom:dheader 4204.0 WAVELENG \"\ARG\" \"central wavelength in angstroms\""
+    ENDM
+DETCOM_ORDER MACRO ARG
+    COBJ "detcom:dheader 4205.0 ORDER \"\ARG\" \"spectral order\""
+    ENDM
+DETCOM_GRSETUP MACRO ARG
+    COBJ "detcom:dheader 4206.0 GRSETUP \"\ARG\" \"grating setup constant in degrees\""
+    ENDM
+DETCOM_OPENANG2 MACRO ARG
+    COBJ "detcom:dheader 4207.0 OPENANG2 \"\ARG\" \"setup const in degrees (opening angle / 2)\""
+    ENDM
+DETCOM_GRISMANG MACRO ARG
+    COBJ "detcom:dheader 4208.0 GRISMANG \"\ARG\" \"rel.angle between prisms in degrees\""
+    ENDM
+DETCOM_SLICER MACRO ARG
+    COBJ "detcom:dheader 4210.0 SLICER \"\ARG\" \"image slicer in place\""
+    ENDM
+DETCOM_HART1A MACRO ARG
+    COBJ "detcom:dheader 4221.0 HART1A \"\ARG\" \"hartman mask 1a position OPEN/CLOSED\""
+    ENDM
+DETCOM_HART1B MACRO ARG
+    COBJ "detcom:dheader 4221.1 HART1B \"\ARG\" \"hartman mask 1b position OPEN/CLOSED\""
+    ENDM
+DETCOM_HART2 MACRO ARG
+    COBJ "detcom:dheader 4222.0 HART2 \"\ARG\" \"hartman mask 2 position OPEN/CLOSED\""
+    ENDM
+DETCOM_HART3 MACRO ARG
+    COBJ "detcom:dheader 4223.0 HART3 \"\ARG\" \"hartman mask 3 position OPEN/CLOSED\""
+    ENDM
+DETCOM_HART4 MACRO ARG
+    COBJ "detcom:dheader 4224.0 HART4 \"\ARG\" \"hartman mask 4 position OPEN/CLOSED\""
+    ENDM
+DETCOM_COUDETRN MACRO ARG
+    COBJ "detcom:dheader 4230.0 COUDETRN \"\ARG\" \"coude train color UV/RED/CAFE\""
+    ENDM
+DETCOM_EMFILTER MACRO ARG
+    COBJ "detcom:dheader 4240.0 EMFILTER \"\ARG\" \"exposure meter filter description\""
+    ENDM
+DETCOM_EMCNTS MACRO ARG
+    COBJ "detcom:dheader 4241.0 EMCNTS \"\ARG\" \"exposure meter counts at end\""
+    ENDM
+DETCOM_MIDEXPTM MACRO ARG
+    COBJ "detcom:dheader 4242.0 MIDEXPTM \"\ARG\" \"mid-exposure time (seconds)\""
+    ENDM
+DETCOM_CAFE MACRO ARG
+    COBJ "detcom:dheader 4290.0 CAFE \"\ARG\" \"CAFE is being used Null/INUSE\""
+    ENDM
+DETCOM_AUXINST MACRO ARG
+    COBJ "detcom:dheader 4301.0 AUXINST \"\ARG\" \"fabry perot etalon description\""
+    ENDM
+DETCOM_NUMCHAN MACRO ARG
+    COBJ "detcom:dheader 4303.0 NUMCHAN \"\ARG\" \"number of channels per scan\""
+    ENDM
+DETCOM_CURCHAN MACRO ARG
+    COBJ "detcom:dheader 4304.0 CURCHAN \"\ARG\" \"current channel\""
+    ENDM
+DETCOM_BINVAL MACRO ARG
+    COBJ "detcom:dheader 4305.0 BINVAL \"\ARG\" \"binary control value\""
+    ENDM
+DETCOM_GRFPPOS MACRO ARG
+    COBJ "detcom:dheader 4320.0 GRFPPOS \"\ARG\" \"GriF position of FP carriage - In/Out\""
+    ENDM
+DETCOM_GRWAVORD MACRO ARG
+    COBJ "detcom:dheader 4321.1 GRWAVORD \"\ARG\" \"GriF wavelength of order used to scan\""
+    ENDM
+DETCOM_GRWAVCAL MACRO ARG
+    COBJ "detcom:dheader 4321.2 GRWAVCAL \"\ARG\" \"GriF wavelength of calibration spectral line\""
+    ENDM
+DETCOM_GRBCVCAL MACRO ARG
+    COBJ "detcom:dheader 4321.3 GRBCVCAL \"\ARG\" \"GriF BCV at calibration line\""
+    ENDM
+DETCOM_GRSCANTY MACRO ARG
+    COBJ "detcom:dheader 4322.0 GRSCANTY \"\ARG\" \"GriF type of scan - bcv, wave, velocity\""
+    ENDM
+DETCOM_GRWAVBEG MACRO ARG
+    COBJ "detcom:dheader 4323.1 GRWAVBEG \"\ARG\" \"GriF wavelength at beginning of scan\""
+    ENDM
+DETCOM_GRWAVSTP MACRO ARG
+    COBJ "detcom:dheader 4323.2 GRWAVSTP \"\ARG\" \"GriF wavelength step\""
+    ENDM
+DETCOM_GRWAVCUR MACRO ARG
+    COBJ "detcom:dheader 4323.3 GRWAVCUR \"\ARG\" \"GriF current observed wavelength\""
+    ENDM
+DETCOM_GRBCVBEG MACRO ARG
+    COBJ "detcom:dheader 4324.1 GRBCVBEG \"\ARG\" \"GriF Binary Contol Value at beginning of scan\""
+    ENDM
+DETCOM_GRBCVSTP MACRO ARG
+    COBJ "detcom:dheader 4324.2 GRBCVSTP \"\ARG\" \"GriF BCV step\""
+    ENDM
+DETCOM_GRBCVCUR MACRO ARG
+    COBJ "detcom:dheader 4324.3 GRBCVCUR \"\ARG\" \"GriF applied BCV\""
+    ENDM
+DETCOM_GRNBCHAN MACRO ARG
+    COBJ "detcom:dheader 4325.1 GRNBCHAN \"\ARG\" \"GriF number of channels in scan\""
+    ENDM
+DETCOM_GRCURRCH MACRO ARG
+    COBJ "detcom:dheader 4325.2 GRCURRCH \"\ARG\" \"GriF current channel\""
+    ENDM
+DETCOM_GRBCV_X MACRO ARG
+    COBJ "detcom:dheader 4326.1 GRBCV_X \"\ARG\" \"GriF X Binary Control Value FP\""
+    ENDM
+DETCOM_GRBCV_Y MACRO ARG
+    COBJ "detcom:dheader 4326.2 GRBCV_Y \"\ARG\" \"GriF Y Binary Control Value FP\""
+    ENDM
+DETCOM_CRUNID MACRO ARG
+    COBJ "detcom:dheader 15101.0 CRUNID \"\ARG\" \"Elixir camera run ID\""
+    ENDM
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.h	(revision 23490)
@@ -0,0 +1,1025 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`fh_registry.h' - A registry of FITS keywords in use at CFHT.
+
+This file is part of version 1 of the FITS Handling Library.
+Read the `License' file for terms of use and distribution.
+Copyright 2001, Canada-France-Hawaii Telescope, daprog@cfht.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+/*
+ * $Id: fh_registry.h,v 1.19 2003/11/25 21:06:28 thomas Exp $
+ *
+ * Documentation: See http://software.cfht.hawaii.edu/fh_registry/
+ */
+
+#ifndef _INCLUDED_fh_registry
+#define _INCLUDED_fh_registry 1
+
+#if defined(__GNUC__) && defined(__STDC__)
+static const char fh_registry_rcs_id[] __attribute__ ((__unused__)) = "@(#) $Id: fh_registry.h,v 1.19 2003/11/25 21:06:28 thomas Exp $" ;
+#else
+static const char fh_registry_rcs_id[] = "@(#) $Id: fh_registry.h,v 1.19 2003/11/25 21:06:28 thomas Exp $";
+#endif
+
+/*
+ * These are environment variables which the CFHT "ccd" process (both
+ * script and older C program) make available to instrument handler programs.
+ */
+#define ENV_FFTEMPLATE	"FFTEMPLATE"
+#define ENV_OBSTYPE	"OBSTYPE"
+#define ENV_INTTIME	"INTTIME"
+#define ENV_EXPNUM	"EXPNUM"
+#define ENV_SEQNUM	"SEQNUM"
+
+/*
+ * This macro is used inside the other macros (ID_FLT, ID_INT, etc.)
+ * so that the keyword names can be referred to as fh_kw_FOO
+ * This can be used as an identifier to fh_get() or any other function
+ * instead of using the string constant "FOO".
+ */
+
+#define ID_FLT(idx, name, keyword, prec, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, double value) \
+{ fh_set_flt(hu, idx, keyword, value, prec, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, double value, const char* new_comment) \
+{ fh_set_flt(hu, idx, keyword, value, prec, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, double* value) \
+{ return fh_get_flt(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_PFL(idx, name, keyword, prec, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, double value) \
+{ fh_set_pfl(hu, idx, keyword, value, prec, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, double value, const char* new_comment) \
+{ fh_set_pfl(hu, idx, keyword, value, prec, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, double* value) \
+{ return fh_get_flt(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_INT(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, int value) \
+{ fh_set_int(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, int value, const char* new_comment) \
+{ fh_set_int(hu, idx, keyword, value, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, int* value) \
+{ return fh_get_int(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_BLN(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, fh_bool value) \
+{ fh_set_bool(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, fh_bool value, const char* new_comment) \
+{ fh_set_bool(hu, idx, keyword, value, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, fh_bool* value) \
+{ return fh_get_bool(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_STR(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, const char* value) \
+{ fh_set_str(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, const char* value, const char* new_comment) \
+{ fh_set_str(hu, idx, keyword, value, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, char* value, int maxlen) \
+{ return fh_get_str(hu, keyword, value, maxlen); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_VAL(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, const char* value, const char* new_comment) \
+{ fh_set_val(hu, idx, keyword, value, new_comment); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_CMT(idx, name, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu) \
+{ fh_set_com(hu, idx, "COMMENT", comment); }
+
+/*
+ * Now the auto-stringified versions of ID_*() ...
+ */
+#define MK_FLT(idx, name, dig, comment) ID_FLT(idx, name, #name, dig, comment)
+#define MK_PFL(idx, name, dec, comment) ID_PFL(idx, name, #name, dec, comment)
+#define MK_INT(idx, name, comment) ID_INT(idx, name, #name, comment)
+#define MK_STR(idx, name, comment) ID_STR(idx, name, #name, comment)
+#define MK_VAL(idx, name, comment) ID_VAL(idx, name, #name, comment)
+#define MK_BLN(idx, name, comment) ID_BLN(idx, name, #name, comment)
+#define MK_CMT(idx, name, comment) ID_CMT(idx, name, comment)
+
+/*
+ * Description of columns:
+ *
+ *      TYPE - MK_BLN, MK_STR, MK_INT, MK_FLT, MK_PFL selects a type for the
+ *             keyword (True/False, 'String  ', integer, or floating point.)
+ *             Any keyword can still be set to any type with fh_setval_*(),
+ *             which takes a pre-formatted character string for the card.
+ *
+ *      IDX  - Index sorting number, which eventually determines the final
+ *             order of keywords in the FITS header.  These are floating point
+ *             values so new keywords can always be inserted in between
+ *             without shifting all the values.
+ *
+ *   KEYWORD - The name of the keyword.  Macros will be generated of the form
+ *             fh_get_KEYWORD(), fh_set_KEYWORD(), and fh_setval_KEYWORD().
+ *
+ *      PRC  - For MK_FLT(), this specifies the (scientific) precision,
+ *             or number of significant digits in the value.  If necessary,
+ *             scientific notation will be used to format the value (see
+ *             rules for printf "%.*G").
+ *             For MK_PFL(), this specifies mathematical precision, or number
+ *             of decimal places in the formatted value (see the rules for
+ *             printf "%.*f").
+ *
+ *             Use MK_PFL() (make "precise float") if that value is always
+ *             precise to an exact number digits after the decimal point.
+ *             Use MK_FLT() if the value might require scientific notation.
+ *             All results are FITS-standard legal.
+ *
+ *   COMMENT - String to be included after the / in the FITS card, if
+ *             there is room within the 80 columns (it may get truncated.)
+ *             Note that in the text below, 80 columns are reached when
+ *             there is still one space between the " and the ) at the end
+ *             of the line.
+ *
+ * FITS Structure : 0.000 to 9.999
+ *
+ * The following keywords give basic information about the structure and
+ * dimensions of the FITS file, and must appear in the specific order
+ * below, usually without any other intervening keywords.
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_BLN( 0.0,	SIMPLE  ,   "Standard FITS"                                   )
+MK_STR( 0.0,	XTENSION,   ""                                                )
+MK_INT( 1.0,	BITPIX  ,   "Bits per pixel"                                  )
+MK_INT( 2.0,	NAXIS   ,   "Number of axes"                                  )
+MK_INT( 2.1,	NAXIS1  ,   "Number of pixel columns"                         )
+MK_INT( 2.2,	NAXIS2  ,   "Number of pixel rows"                            )
+MK_INT( 2.3,	NAXIS3  ,   "Number of stacked frames (cube)"                 )
+MK_BLN( 3.0,	EXTEND  ,   "File contains extensions"                        )
+MK_INT( 3.1,	NEXTEND ,   "Number of extensions"                            )
+MK_BLN( 4.0,	GROUPS  ,   "File contains random groups records"             )
+MK_INT( 5.0,	PCOUNT  ,   "Random parameters before each array in a group"  )
+MK_INT( 6.0,	GCOUNT  ,   "Number of random groups"                         )
+MK_INT( 7.0000,	TFIELDS ,   "Number of fields in a row"                       )
+MK_STR( 7.0011,	TFORM1  ,   "Table format for field 1"                        )
+MK_INT( 7.0012,	TBCOL1  ,   "Start Column for field 1"                        )
+MK_STR( 7.0021,	TFORM2  ,   "Table format for field 2"                        )
+MK_INT( 7.0022,	TBCOL2  ,   "Start Column for field 2"                        )
+MK_STR( 7.0031,	TFORM3  ,   "Table format for field 3"                        )
+MK_INT( 7.0032,	TBCOL3  ,   "Start Column for field 3"                        )
+MK_STR( 7.0041,	TFORM4  ,   "Table format for field 4"                        )
+MK_INT( 7.0042,	TBCOL4  ,   "Start Column for field 4"                        )
+MK_STR( 7.0051,	TFORM5  ,   "Table format for field 5"                        )
+MK_INT( 7.0052,	TBCOL5  ,   "Start Column for field 5"                        )
+MK_PFL( 10.0,   BZERO   ,1, "Zero factor"                                     )
+MK_PFL( 11.0,	BSCALE  ,1, "Scale factor"                                    )
+
+/*
+ * Summary : 50.000 to 59.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(   50.1, CMTSUM1 ,   ""                                                )
+MK_CMT(   50.2, CMTSUM2 ,   "Observation Summary"                             )
+MK_CMT(   50.3, CMTSUM3 ,   "-------------------"                             )
+MK_CMT(   50.4, CMTSUM4 ,   ""                                                )
+MK_CMT(   50.5, CMTSUM5 ,   ""                                                )
+MK_STR(   51.0, CMMTOBS ,   ""                                                )
+MK_STR(   52.0, CMMTSEQ ,   ""                                                )
+MK_STR(   53.0, OBJECT  ,   ""                                                )
+MK_STR(   54.0, OBSERVER,   ""                                                )
+MK_STR(   55.0, PI_NAME ,   ""                                                )
+MK_STR(   56.0, RUNID   ,   ""                                                )
+
+/*
+ * General : 70.000 to 79.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  70.10, CMTGEN1 ,   ""                                                )
+MK_CMT(  70.20, CMTGEN2 ,   "General"                                         )
+MK_CMT(  70.30, CMTGEN3 ,   "-------"                                         )
+MK_CMT(  70.40, CMTGEN4 ,   ""                                                )
+MK_STR(  71.00, FILENAME,   "Base filename at acquisition"                    )
+MK_STR(  71.01, PATHNAME,   "Original directory name at acquisition"          )
+MK_STR(  71.10, EXTNAME ,   "Extension name"                                  )
+MK_INT(  71.20, EXTVER  ,   "Extension version"                               )
+MK_STR(  74.00, DATE    ,   "UTC Date of file creation"                       )
+MK_STR(  74.10, HSTTIME ,   "Local time in Hawaii"                            )
+MK_STR(  77.00, IMAGESWV,   "Image creation software version"                 )
+
+/*
+ * Summary : 90.0 Key stuff from instrument, detector (and other?) sections
+ */
+MK_STR(   91.0,	DETECTOR,   "Science Detector"                                )
+MK_STR(   92.0, INSTRUME,   "Instrument Name"                                 )
+MK_STR(   92.1, INSTMODE,   "Instrument Mode"                                 )
+
+/*
+ * Detector : 100.000 to 199.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  100.1,	CMTDET1	,   ""                                                )
+MK_CMT(  100.2,	CMTDET2	,   "Detector"                                        )
+MK_CMT(  100.3,	CMTDET3	,   "--------"                                        )
+MK_CMT(  100.4,	CMTDET4	,   ""                                                )
+MK_STR(  102.0, DETSIZE	,   "Total data pixels in full mosaic"                )
+MK_STR(  103.0,	RASTER	,   ""                                                )
+MK_STR(  105.0,	CCDSUM	,   "Binning factors"                                 )
+MK_INT(  105.1,	CCDBIN1	,   "Binning factor along first axis"                 )
+MK_INT(  105.2,	CCDBIN2	,   "Binning factor along second axis"                )
+MK_FLT(  110.0,	PIXSIZE ,3, "Pixel size for both axes (microns)"              )
+MK_FLT(  111.1,	PIXSIZE1,3, "Pixel size for axis 1 (microns)"                 )
+MK_FLT(  111.2,	PIXSIZE2,3, "Pixel size for axis 2 (microns)"                 )
+MK_FLT(  112.1,	PIXSCAL1,4, "Pixel scale for axis 1 (arcsec/pixel)"           )
+MK_FLT(  112.2,	PIXSCAL2,4, "Pixel scale for axis 2 (arcsec/pixel)"           )
+MK_STR(  130.0,	AMPLIST	,   "List of amplifiers for this image"               )
+MK_STR(  131.0,	AMPNAME	,   "Amplifier name"                                  )
+MK_STR(  140.0,	CCDSIZE ,   "Detector imaging area size"                      )
+MK_STR(  140.1,	DETSEC  ,   "Mosaic area of the detector"                     )
+MK_STR(  140.11,DETSECA ,   "Mosaic area of the detector from Amp A"          )
+MK_STR(  140.12,DETSECB ,   "Mosaic area of the detector from Amp B"          )
+MK_STR(  140.13,DETSECC ,   "Mosaic area of the detector from Amp C"          )
+MK_STR(  140.14,DETSECD ,   "Mosaic area of the detector from Amp D"          )
+MK_STR(  140.2,	DATASEC ,   "Imaging area of the detector"                    )
+MK_STR(  140.3,	BIASSEC ,   "Overscan (bias) area of the detector"            )
+MK_STR(  141.11,ASECA   ,   "Section from Amp A (non-contig. bias excluded)"  )
+MK_STR(  141.12,ASECB   ,   "Section from Amp B (non-contig. bias excluded)"  )
+MK_STR(  141.13,ASECC   ,   "Section from Amp C (non-contig. bias excluded)"  )
+MK_STR(  141.14,ASECD   ,   "Section from Amp D (non-contig. bias excluded)"  )
+MK_STR(  141.21,BSECA   ,   "Overscan (bias) area from Amp A"                 )
+MK_STR(  141.22,BSECB   ,   "Overscan (bias) area from Amp B"                 )
+MK_STR(  141.23,BSECC   ,   "Overscan (bias) area from Amp C"                 )
+MK_STR(  141.24,BSECD   ,   "Overscan (bias) area from Amp D"                 )
+MK_STR(  141.31,CSECA   ,   "Section in full CCD for DSECA"                   )
+MK_STR(  141.32,CSECB   ,   "Section in full CCD for DSECB"                   )
+MK_STR(  141.33,CSECC   ,   "Section in full CCD for DSECC"                   )
+MK_STR(  141.34,CSECD   ,   "Section in full CCD for DSECD"                   )
+MK_STR(  141.41,DSECA   ,   "Imaging area from Amp A"                         )
+MK_STR(  141.42,DSECB   ,   "Imaging area from Amp B"                         )
+MK_STR(  141.43,DSECC   ,   "Imaging area from Amp C"                         )
+MK_STR(  141.44,DSECD   ,   "Imaging area from Amp D"                         )
+MK_STR(  141.51,TSECA   ,   "Trim section for Amp A"                          )
+MK_STR(  141.52,TSECB   ,   "Trim section for Amp B"                          )
+MK_STR(  141.53,TSECC   ,   "Trim section for Amp C"                          )
+MK_STR(  141.54,TSECD   ,   "Trim section for Amp D"                          )
+MK_STR(  150.1, CCDNAME,    "Name of the CCD (manufacturer reference)"        )
+MK_STR(  150.2, CCDNICK,    "Nickname of the CCD"                             )
+MK_INT(  152.0, MAXLIN  ,   "Maximum linearity value (ADU)"                   )
+MK_INT(  152.01,MAXLINA ,   "Maximum linearity value for Amp A (ADU)"         )
+MK_INT(  152.02,MAXLINB ,   "Maximum linearity value for Amp B (ADU)"         )
+MK_INT(  152.03,MAXLINC ,   "Maximum linearity value for Amp C (ADU)"         )
+MK_INT(  152.04,MAXLIND ,   "Maximum linearity value for Amp D (ADU)"         )
+MK_INT(  152.1, SATURATE,   "Saturation value (ADU)"                          )
+MK_FLT(  155.0,	GAIN    ,3, "Amplifier gain (electrons/ADU)"                  )
+MK_FLT(  155.01,GAINA   ,3, "Amp A gain (electrons/ADU)"                      )
+MK_FLT(  155.02,GAINB   ,3, "Amp B gain (electrons/ADU)"                      )
+MK_FLT(  155.03,GAINC   ,3, "Amp C gain (electrons/ADU)"                      )
+MK_FLT(  155.04,GAIND   ,3, "Amp D gain (electrons/ADU)"                      )
+MK_FLT(  156.0,	RDNOISE ,3, "Read noise (electrons)"                          )
+MK_FLT(  156.01,RDNOISEA,3, "Amp A read noise (electrons)"                    )
+MK_FLT(  156.02,RDNOISEB,3, "Amp B read noise (electrons)"                    )
+MK_FLT(  156.03,RDNOISEC,3, "Amp C read noise (electrons)"                    )
+MK_FLT(  156.04,RDNOISED,3, "Amp D read noise (electrons)"                    )
+MK_FLT(  157.0, DCURRENT,5, "Dark current (ADU/pixel/second)"                 )
+MK_FLT(  157.1, DARKCUR ,5, "Dark current (e-/pixel/hour)"                    )
+MK_STR(  158.0,	QEPOINTS,   "QE%@wavelength in nm"                            )
+MK_STR(  170.0, CONSWV	,   "Controller software DSPID and SERNO versions"    )
+MK_STR(  180.0,	DETSTAT	,   "Detector status"                                 )
+MK_FLT(  190.0, DETTEM  ,3, "Detector temperature"                            )
+
+/* ****************************************************
+ * *** World Coordinate System : 300.000 to 399.999 ***
+ * ****************************************************
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+/*
+ * Telescope : 500.000 to 599.999
+ *
+ * Almost all keywords we define can be generated with the MK_XXX macros.
+ * The only exceptions are those keywords which contain a '-', since the
+ * '-' is not a legal character in a C identifier.  TCS uses four of them
+ * (DATE-OBS, UTC-OBS, MJD-OBS, and LST-OBS.)  The ID_XXX macros are used
+ * and the '-' is translated to a '_' (underscore) for use in C programs.
+ *
+ * NOTE: TELESCOP, TELSTAT, TELCONF, LATITUDE, and LONGITUD are currently
+ * inserted by DetCom and _not_ tcsh.  This should probably be changed.
+ *
+ * Further details on some less obvious keywords:
+ *
+ *   SKYFLUX  - if the guider(s) can generate a reasonable guess for the
+ *              amount of flux currently available for doing flats, that
+ *              number is in this keyword - negative means not available
+ *
+ *   GUIFLUXn - these values are the most recent one minute average of the
+ *              total flux seen in whatever guiding box/area is in use
+ *
+ *   GUIFWH?n - these are the most recent one minute average FWHM values
+ *              for the x/y axes of the guider image(s) recorded at the
+ *              start of the exposure
+ *
+ *   ISUSTDV? - these are the most recent one minute standard deviations
+ *              in the ISU x and y positions in arc seconds recorded
+ *              at the start of the exposure
+ *
+ *   FSAstats - the FSA statistics are for the most recent 10 minutes
+ *              recorded at the start of the exposure
+ *
+ * If there are multiple guiders in use, the unnumbered GUIEQUIN/GUIRADEC
+ * /GUIRA/GUIDEC/GUIRAPM/GUIDECPM values will duplicate the numbered
+ * values for the primary, reference guider.  If there is only one guider
+ * in use, only the unnumbered values should be present.
+ *
+ *TYPE --IDX--  SYMBOL--  KEYWORD-  -----------COMMENT----------------------*/
+ID_STR( 511.1,	DATE_OBS,"DATE-OBS", "Date at start of observation (UTC)"     )
+ID_STR( 512.1,	UTC_OBS ,"UTC-OBS", "Time at start of observation (UTC)"      )
+ID_PFL( 513.1,  MJD_OBS ,"MJD-OBS",7, "Modified Julian Date at start of obs." )
+ID_STR( 514.1,	LST_OBS ,"LST-OBS", "Sidereal time at start of exposure"      )
+
+/*TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  500.1, CMTTCS1 ,   ""                                                )
+MK_CMT(  500.2, CMTTCS2 ,   "Telescope"                                       )
+MK_CMT(  500.3, CMTTCS3 ,   "---------"                                       )
+MK_CMT(  500.4, CMTTCS4 ,   ""                                                )
+MK_STR(  501.1, TELESCOP,   ""                                                )
+MK_STR(  501.2, ORIGIN  ,   "Canada-France-Hawaii Telescope"                  )
+MK_PFL(  502.1, LATITUDE,6, "Latitude (degrees N)"                            )
+MK_PFL(  502.2, LONGITUD,6, "Longitude (degrees E)"                           )
+MK_STR(  503.0, TELSTAT ,   "Telescope Control System status"                 )
+MK_STR(  510.0, TIMESYS ,   "Time System for DATExxxx"                        )
+/* note that the following three have xxx.1 versions above */
+MK_STR(  512.0,	UTIME   ,   "Time at start of observation (UT)"               )
+MK_PFL(  513.0,	MJDATE  ,7 ,"Modified Julian Date at start of observation"    )
+MK_STR(  514.0,	SIDTIME ,   "Sidereal time at start of observation"           )
+MK_VAL(  521.0,	EPOCH   ,   "Equinox of coordinates"                          )
+MK_VAL(  521.1,	EQUINOX ,   "Equinox of coordinates"                          )
+MK_STR(  522.0,	RADECSYS,   "Coordinate system for equinox (FK4/FK5/GAPPT)"   )
+MK_STR(  522.1,	RA      ,   "Object right ascension"                          )
+MK_STR(  522.2,	DEC     ,   "Object declination"                              )
+MK_PFL(  523.1,	RA_DEG  ,6, "Object right ascension in degrees"               )
+MK_PFL(  523.2,	DEC_DEG ,6, "Object declination in degrees"                   )
+
+MK_PFL(525.101,	CRVAL1	,5, "WCS Ref value (RA in decimal degrees)"           )
+MK_PFL(525.102,	CRVAL2	,5, "WCS Ref value (DEC in decimal degrees)"          )
+MK_STR(525.211,	CTYPE1	,   "WCS Coordinate type"                             )
+MK_STR(525.212,	CTYPE2	,   "WCS Coordinate type"                             )
+MK_PFL(525.301,	CRPIX1	,1, "WCS Coordinate reference pixel"                  )
+MK_PFL(525.302,	CRPIX2	,1, "WCS Coordinate reference pixel"                  )
+MK_FLT(525.411,	CD1_1	,6, "WCS Coordinate scale matrix"                     )
+MK_FLT(525.412,	CD1_2	,6, "WCS Coordinate scale matrix"                     )
+MK_FLT(525.421,	CD2_1	,6, "WCS Coordinate scale matrix"                     )
+MK_FLT(525.422,	CD2_2	,6, "WCS Coordinate scale matrix"                     )
+
+MK_INT(  530.0,	NGUIDER	,   "TCS Number of guiders"                           )
+MK_INT( 530.01, NGUISTAR,   "TCS number of guide stars/probes in use"         )
+MK_STR(  530.1, GUINAME ,   "TCS guider name"                                 )
+MK_VAL( 530.21,	GUIEQUIN,   "TCS guider equinox"                              )
+MK_STR( 530.22,	GUIRADEC,   "TCS guider system for equinox"                   )
+MK_STR( 530.23,	GUIRA   ,   "TCS guider right ascension"                      )
+MK_STR( 530.24,	GUIDEC  ,   "TCS guider declination"                          )
+MK_PFL( 530.25, GUIRAPM ,2, "TCS guider right ascension proper motion arcsec" )
+MK_PFL( 530.26, GUIDECPM,2, "TCS guider declination proper motion arcsec"     )
+MK_STR(  530.3, GUIOBJN ,   "TCS guider object name"                          )
+MK_PFL(  530.4, GUIMAGN ,1, "TCS guider object magnitude"                     )
+MK_PFL( 530.51,	XPROBE  ,3 ,"Telescope bonnette guide probe X position"       )
+MK_PFL( 530.52,	YPROBE  ,3 ,"Telescope bonnette guide probe Y position"       )
+MK_PFL( 530.53,	ZPROBE  ,3 ,"Telescope bonnette guide probe Z position"       )
+MK_INT(  530.6, GUIFLUX ,   "TCS guider flux"                                 )
+MK_PFL( 530.71, GUIFWHX ,2, "TCS guider average x FWHM in pixels"             )
+MK_PFL( 530.72, GUIFWHY ,2, "TCS guider average y FWHM in pixels"             )
+MK_INT(  530.8, SKYFLUX ,   "TCS total sky flux"                              )
+
+MK_STR(  531.1,	GUINAME1,   "TCS guider #1 identification"                    )
+MK_VAL( 531.21,	GUIEQUI1,   "TCS guider #1 equinox"                           )
+MK_STR( 531.22,	GUIRADE1,   "TCS guider #1 system for equinox"                )
+MK_STR( 531.23,	GUIRA1  ,   "TCS guider #1 right ascension"                   )
+MK_STR( 531.24,	GUIDEC1 ,   "TCS guider #1 declination"                       )
+MK_PFL( 531.25, GUIRAPM1,2, "TCS guider #1 right ascen proper motion arcsec"  )
+MK_PFL( 531.26, GUIDEPM1,2, "TCS guider #1 declination proper motion arcsec"  )
+MK_STR(  531.3, GUIOBJN1,   "TCS guider #1 object name"                       )
+MK_PFL(	 531.4,	GUIMAGN1,1, "TCS guider #1 object magnitude"                  )
+MK_PFL( 531.51, GUIPOSX1,3, "TCS guider #1 probe x position"                  )
+MK_PFL( 531.52, GUIPOSY1,3, "TCS guider #1 probe y position"                  )
+MK_PFL( 531.53, GUIPOSZ1,3, "TCS guider #1 probe z position"                  )
+MK_INT(  531.6, GUIFLUX1,   "TCS guider #1 flux"                              )
+MK_PFL( 531.71, GUIFWHX1,2, "TCS guider #1 average x FWHM in pixels"          )
+MK_PFL( 531.72, GUIFWHY1,2, "TCS guider #1 average y FWHM in pixels"          )
+
+MK_STR(  532.1,	GUINAME2,   "TCS guider #2 identification"                    )
+MK_VAL( 532.21,	GUIEQUI2,   "TCS guider #2 equinox"                           )
+MK_STR( 532.22,	GUIRADE2,   "TCS guider #2 system for equinox"                )
+MK_STR( 532.23,	GUIRA2  ,   "TCS guider #2 right ascension"                   )
+MK_STR( 532.24,	GUIDEC2 ,   "TCS guider #2 declination"                       )
+MK_PFL( 532.25, GUIRAPM2,2, "TCS guider #2 right ascen proper motion arcsec"  )
+MK_PFL( 532.26, GUIDEPM2,2, "TCS guider #2 declination proper motion arcsec"  )
+MK_STR(  532.3, GUIOBJN2,   "TCS guider #2 object name"                       )
+MK_PFL(	 532.4,	GUIMAGN2,1, "TCS guider #2 object magnitude"                  )
+MK_PFL( 532.51, GUIPOSX2,3, "TCS guider #2 probe x position"                  )
+MK_PFL( 532.52, GUIPOSY2,3, "TCS guider #2 probe y position"                  )
+MK_PFL( 532.53, GUIPOSZ2,3, "TCS guider #2 probe z position"                  )
+MK_INT(  532.6, GUIFLUX2,   "TCS guider #2 flux"                              )
+MK_PFL( 532.71, GUIFWHX2,2, "TCS guider #2 average x FWHM in pixels"          )
+MK_PFL( 532.72, GUIFWHY2,2, "TCS guider #2 average y FWHM in pixels"          )
+
+MK_STR(  533.1,	GUINAME3,   "TCS guider #3 identification"                    )
+MK_VAL( 533.21,	GUIEQUI3,   "TCS guider #3 equinox"                           )
+MK_STR( 533.22,	GUIRADE3,   "TCS guider #3 system for equinox"                )
+MK_STR( 533.23,	GUIRA3  ,   "TCS guider #3 right ascension"                   )
+MK_STR( 533.24,	GUIDEC3 ,   "TCS guider #3 declination"                       )
+MK_PFL( 533.25, GUIRAPM3,2, "TCS guider #3 right ascen proper motion arcsec"  )
+MK_PFL( 533.26, GUIDEPM3,2, "TCS guider #3 declination proper motion arcsec"  )
+MK_STR(  533.3, GUIOBJN3,   "TCS guider #3 object name"                       )
+MK_PFL(	 533.4,	GUIMAGN3,1, "TCS guider #3 object magnitude"                  )
+MK_PFL( 533.51, GUIPOSX3,3, "TCS guider #3 probe x position"                  )
+MK_PFL( 533.52, GUIPOSY3,3, "TCS guider #3 probe y position"                  )
+MK_PFL( 533.53, GUIPOSZ3,3, "TCS guider #3 probe z position"                  )
+MK_INT(  533.6, GUIFLUX3,   "TCS guider #3 flux"                              )
+MK_PFL( 533.71, GUIFWHX3,2, "TCS guider #3 average x FWHM in pixels"          )
+MK_PFL( 533.72, GUIFWHY3,2, "TCS guider #3 average y FWHM in pixels"          )
+
+MK_STR(  534.1,	GUINAME4,   "TCS guider #4 identification"                    )
+MK_VAL( 534.21,	GUIEQUI4,   "TCS guider #4 equinox"                           )
+MK_STR( 534.22,	GUIRADE4,   "TCS guider #4 system for equinox"                )
+MK_STR( 534.23,	GUIRA4  ,   "TCS guider #4 right ascension"                   )
+MK_STR( 534.24,	GUIDEC4 ,   "TCS guider #4 declination"                       )
+MK_PFL( 534.25, GUIRAPM4,2, "TCS guider #4 right ascen proper motion arcsec"  )
+MK_PFL( 534.26, GUIDEPM4,2, "TCS guider #4 declination proper motion arcsec"  )
+MK_STR(  534.3, GUIOBJN4,   "TCS guider #4 object name"                       )
+MK_PFL(	 534.4,	GUIMAGN4,1, "TCS guider #4 object magnitude"                  )
+MK_PFL( 534.51, GUIPOSX4,3, "TCS guider #4 probe x position"                  )
+MK_PFL( 534.52, GUIPOSY4,3, "TCS guider #4 probe y position"                  )
+MK_PFL( 534.53, GUIPOSZ4,3, "TCS guider #4 probe z position"                  )
+MK_INT(  534.6, GUIFLUX4,   "TCS guider #4 flux"                              )
+MK_PFL( 534.71, GUIFWHX4,2, "TCS guider #4 average x FWHM in pixels"          )
+MK_PFL( 534.72, GUIFWHY4,2, "TCS guider #4 average y FWHM in pixels"          )
+
+MK_PFL(  540.1,	AIRMASS ,3, "Airmass at start of observation"                 )
+MK_PFL(  540.2, TELALT  ,2, "Telescope altitude at start of observation, deg" )
+MK_PFL(  540.3, TELAZ   ,2, "Telescope azimuth at start, deg, 0=N 90=E 270=W" )
+MK_PFL(  540.4, MOONANGL,2, "Angle from object to moon at start in degrees"   )
+MK_STR(  550.0,	FOCUSID ,   "Telescope focus in use"                          )
+MK_STR(  550.1, TELCONF ,   "Telescope focus in use"                          )
+MK_INT(  551.0,	FOCUSPOS,   "Telescope focus encoder readout"                 )
+MK_INT(  551.1,	TELFOCUS,   "Telescope focus encoder readout"                 )
+MK_PFL(  552.0,	BONANGLE,2, "Telescope bonnette rotation angle in degrees"    )
+MK_PFL(  552.1,	ROTANGLE,2, "Telescope bonnette rotation angle in degrees"    )
+
+/*
+ * The following values perhaps should have their own section, but they
+ * are also (with some stretch) a part of TCS so for now they are here.
+ * They should only be included in MegaPrime and WIRCam images.
+ */
+
+MK_PFL(  560.1, ISUGAIN ,2, "Instrument Stabilization Unit control gain"      )
+MK_PFL(  560.2, ISURATE ,2, "ISU control rate in Hz"                          )
+MK_PFL(  560.3, ISUTCSOR,2, "ISU offload rate in Hz to telescope position"    )
+MK_STR(  560.4, ISUSTATE,   "ISU control state (Off/Only/TCS/Full/Frozen)"    )
+MK_PFL(  560.5, ISUSTDVX,2, "ISU most recent minute std dev in x in arcsec"   )
+MK_PFL(  560.6, ISUSTDVY,2, "ISU most recent minute std dev in y in arcsec"   )
+
+/*
+ * The following values perhaps should have their own section, but they
+ * are also (with some stretch) a part of TCS so for now they are here.
+ * They should only be included in MegaPrime images.
+ */
+
+MK_PFL(  570.1, FSAGAIN ,2, "Focus Stage Assembly movement control gain"      )
+MK_PFL(  570.2, FSARATE ,2, "FSA control rate in Hz"                          )
+MK_PFL(  570.3, FSATHRES,3, "FSA movement threshold in mm"                    )
+MK_STR(  570.4, FSASTATE,   "FSA control state (Off/On/Paused)"               )
+MK_INT(  570.5, FSANMOVE,   "FSA number of actual moves in last 10 minutes"   )
+MK_PFL( 570.61, FSAMINZ ,3, "FSA minimum position in last 10 minutes"         )
+MK_PFL( 570.62, FSAMAXZ ,3, "FSA maximum position in last 10 minutes"         )
+MK_PFL( 570.63, FSAMEANZ,3, "FSA mean position in last 10 minutes"            )
+MK_PFL( 570.64, FSASTDVZ,3, "FSA position std dev in last 10 minutes"         )
+
+/*
+ * The following values are used to collect data for TCS pointing model
+ * tuning.  Some of the values duplicate numbers elsewhere in the headers,
+ * but where it matters these are all read at the same time in the IOC.
+ */
+
+MK_STR( 580.11, TCSGPSBC,   "TCS GPS read out in BCD"                         )
+MK_PFL( 580.12, TCSGPSTM,5, "TCS GPS clock time in decimal hours"             )
+MK_STR( 580.13, TCSRBUSS,   "TCS RBUSS clock time"                            )
+MK_STR( 580.14, TCSEPICS,   "TCS EPICS clock time"                            )
+MK_STR( 580.15, TCSAMODE,   "TCS acquisition mode - T/O/G/g for t/o/g coords" )
+MK_PFL( 580.21, TCSMJD  ,7, "TCS MJD"                                         )
+MK_PFL( 580.22, TCSLST  ,5, "TCS LST in decimal hours"                        )
+MK_PFL( 580.31, TCSAPHA ,4, "TCS apparent hour angle in degrees"              )
+MK_PFL( 580.32, TCSAPDEC,4, "TCS apparent declination in degrees"             )
+MK_PFL( 580.41, TCSOBHA ,4, "TCS observed hour angle in degrees"              )
+MK_PFL( 580.42, TCSOBDEC,4, "TCS observed declination in degrees"             )
+MK_INT( 580.51, TCSENHA ,   "TCS hour angle encoder bits reading"             )
+MK_INT( 580.52, TCSENDEC,   "TCS declination encoder bits reading"            )
+MK_PFL( 580.61, TCSEDHA ,4, "TCS hour angle encoder in degrees"               )
+MK_PFL( 580.62, TCSEDDEC,4, "TCS declination encoder in degrees"              )
+MK_PFL( 580.71, TCSMVRA ,4, "TCS right ascension acquisition move in arcsec"  )
+MK_PFL( 580.72, TCSMVDEC,4, "TCS declination acquisition move in arcsec"      )
+MK_PFL( 580.81, TCSMVX  ,3, "TCS secondary guider acquisition x move in mm"   )
+MK_PFL( 580.82, TCSMVY  ,3, "TCS secondary guider acquisition y move in mm"   )
+
+/*
+ * Adaptive Optics : 700.000 to 799.999
+ *
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT(  700.1, CMTAOB1 ,   ""                                                )
+MK_CMT(  700.2, CMTAOB2 ,   "Adaptive Optics Bonnette"                        )
+MK_CMT(  700.3, CMTAOB3 ,   "------------------------"                        )
+MK_CMT(  700.4, CMTAOB4 ,   ""                                                )
+
+/* 710 through 719 are input control values to the real time system */
+
+/*
+ * state of AO correction (terms come from original description of loop
+ * operation which was deemed not PC and changed to "correction")
+ */
+MK_STR(  711.0, AOBLOOP ,   "AOB closed loop Open/Closed"                     )
+/*
+ * primary gain in the integrator providing signals to the bimorph
+ */
+MK_PFL(  712.0, LOOPGAIN,1, "Gain of the integrator"                          )
+/*
+ * correction can be fully automatic (all modes, bimorph offloading to
+ * tip/tilt mirror - nested), manual (manually selected modes, tip/tilt
+ * mode if selected only feeds tip/tilt mirror, i.e., not via bimorph
+ * - single), or tip/tilt only (bimorph not used at all, kept flat)
+ */
+MK_STR(  713.0, LOOPNES ,   "Loop type \"Nested\"/\"Tip/Tilt\"/\"Single\""    )
+/*
+ * in automatic correction this is the gain between the bimorph and the
+ * tip/tilt mirror
+ */
+MK_PFL(  714.0, LOOPNESG,1, "Nested loop gain"                                )
+/*
+ * the individual mode gains can be fixed or optimized based on signal
+ * levels
+ */
+MK_STR(  715.0, LOOPOPT ,   "Optimized loop control True/False"               )
+/*
+ * stroke of the membrane mirror (1-256)
+ */
+MK_INT(  716.0, WFSGOPT ,   "WFS optical gain"                                )
+/*
+ * integration time for each calculation cycle
+ */
+MK_PFL(  717.0, WFSSAMP ,3, "WFS sampling period (sec)"                       )
+
+/* 720-729 are measured values calculated by the real time system */
+
+/*
+ * calculated value of R0
+ */
+MK_PFL(  721.0, R0      ,1, "Fried parameter (cm)"                            )
+/*
+ * sum of the photon counts on the 19 APD's, for the most recent integration
+ */
+MK_INT(  722.0, WFSCOUNT,   "Total flux count on WFS"                         )
+
+/* 750-769 are input control values to the bench control ProLog(tm) */
+
+/*
+ * whether the atmospheric dispersion corrector (ADC) is in or out of the
+ * optical path
+ */
+MK_STR(  751.0, ADCPOS  ,   "AOB ADC position In/Out"                         )
+/*
+ * angle of the dispersion caused by the ADC
+ */
+MK_PFL(  752.0, ADCANGLE,2, "AOB ADC angle (degrees)"                         )
+/*
+ * amount of dispersion caused by the relative angle between the ADC prisms
+ */
+MK_PFL(  753.0, ADCPOWER,4, "AOB ADC power"                                   )
+/*
+ * beam splitter id code read from slugs on the splitters
+ */
+MK_INT(  754.0, BEAMSPID,   "Beam splitter ID"                                )
+/*
+ * beam splitter description based on the above codes
+ */
+MK_STR(  755.0, BEAMSP  ,   "Beam splitter description"                       )
+/*
+ * whether the AOB central mirror is in (AO system in light path)
+ * or out (AO system not being used)
+ */
+MK_STR(  756.0, MIRSLIDE,   "AOB mirror slide \"F/20\"/\"F/8\""               )
+/*
+ * neutral density filter position (in optical path to WFS)
+ *   0 == home
+ *   1 == no filter (close but not quite the same physical position as home)
+ *   2 == 1.0 density filter
+ *   3 == 2.0    "      "
+ *   4 == 3.0    "      "
+ */
+MK_INT(  757.0, WFSNDID ,   "WFS ND filter position"                          )
+/*
+ * following 3 are the Wave Front Sensor (WFS) position in a coordinate
+ * system close to having z parallel to the optical path
+ */
+MK_PFL(  761.0, WFSX    ,1, "Translated WFS X coord (steps)"                  )
+MK_PFL(  762.0, WFSY    ,1, "Translated WFS Y coord (steps)"                  )
+MK_PFL(  763.0, WFSZ    ,1, "Translated WFS Z coord (steps)"                  )
+/*
+ * Calibration Sources : 900.000 to 999.999
+ *
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT(  900.1, CMTCAL1 ,   ""                                                )
+MK_CMT(  900.2, CMTCAL2 ,   "Calibration sources"                             )
+MK_CMT(  900.3, CMTCAL3 ,   "-------------------"                             )
+MK_CMT(  900.4, CMTCAL4 ,   ""                                                )
+
+/* 910 - 919 are flat field lamps */
+
+/*
+ * Gecko lamps are computer controlled, these give On/Off status and
+ * intensity
+ */
+MK_STR(  910.0, FFLAMPON,   "flatfield lamp status ON/OFF"                    )
+MK_INT(  911.0, FFLAMP  ,   "flatfield lamp intensity"                        )
+/* add which lamp if get control of dome flat fields */
+
+/* 920-999 are calibration lamp sources */
+
+/*
+ * Gecko has 4 lamps, these give On/Off status and descriptions
+ */
+MK_STR(  920.0, CLAMP0ON,   "comparison lamp 0 status ON/OFF"                 )
+MK_STR(  920.1, CLAMP0  ,   "comparison lamp 0 description"                   )
+MK_STR(  921.0, CLAMP1ON,   "comparison lamp 1 status ON/OFF"                 )
+MK_STR(  921.1, CLAMP1  ,   "comparison lamp 1 description"                   )
+MK_STR(  922.0, CLAMP2ON,   "comparison lamp 2 status ON/OFF"                 )
+MK_STR(  922.1, CLAMP2  ,   "comparison lamp 2 description"                   )
+MK_STR(  923.0, CLAMP3ON,   "comparison lamp 3 status ON/OFF"                 )
+MK_STR(  923.1, CLAMP3  ,   "comparison lamp 3 description"                   )
+
+/*
+ * GumBall has 10 lamps, though the last two are Fabre-Perot lamps sharing
+ * the same light path and cannot be on together, these give On/Off status
+ * for each
+ */
+MK_STR(  930.0, CALIBL0 ,   "lamp 0 ON/OFF"                                   )
+MK_STR(  931.0, CALIBL1 ,   "lamp 1 ON/OFF"                                   )
+MK_STR(  932.0, CALIBL2 ,   "lamp 2 ON/OFF"                                   )
+MK_STR(  933.0, CALIBL3 ,   "lamp 3 ON/OFF"                                   )
+MK_STR(  934.0, CALIBL4 ,   "lamp 4 ON/OFF"                                   )
+MK_STR(  935.0, CALIBL5 ,   "lamp 5 ON/OFF"                                   )
+MK_STR(  936.0, CALIBL6 ,   "lamp 6 ON/OFF"                                   )
+MK_STR(  937.0, CALIBL7 ,   "lamp 7 ON/OFF"                                   )
+MK_STR(  938.0, CALIBL8 ,   "lamp 8 ON/OFF"                                   )
+MK_STR(  939.0, CALIBL9 ,   "lamp 9 ON/OFF"                                   )
+
+/*
+ * Instrument : 1000.000 to 1999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT( 1000.1, CMTINST1,   ""                                                )
+MK_CMT( 1000.2, CMTINST2,   "Instrument Description"                          )
+MK_CMT( 1000.3, CMTINST3,   "----------------------"                          )
+MK_CMT( 1000.4, CMTINST4,   ""                                                )
+
+/*
+ * There are lots of shared keywords among the instruments and spectrographs.
+ * Where the keywords are really general purpose (e.g., FILTER) they are
+ * separated from the instrument areas.  Where the keywords are more specific,
+ * they are associated with the "first" (arbitrarily defined as starting about
+ * 1992 :-) instrument that used them.
+ */
+
+/* 1010 through 1099 are filter wheel info */
+
+/*
+ * Somewhere in the optical train there be filters.  If there is one filter
+ * use the FILTER sequence, whether it is actually in the detector or the
+ * instrument.  If there are two filters (usual case for IR), use the WHEEL
+ * sequence.  For an IR camera on an instrument with a filter, use both.
+ */
+
+/*
+ * code descriptions for all wheel identifiers
+ *
+ *  ID - numeric position number of wheel
+ *  <null> or DE - text description of filter mounted in that position
+ *  LB - lower bound of filter transmission - units Angstrom or microns?
+ *  UB - upper bound of filter transmission - units Angstrom or microns?
+ *  BW - bandwidth of filter transmission - units Angstrom or microns?
+ *  WL - center wave length of filter transmission - units Angstrom or microns?
+ */
+
+/* single filter wheel */
+MK_INT( 1010.1, FILTERID,   "wheel position"                                  )
+MK_STR( 1010.2, FILTER  ,   "description of filter"                           )
+MK_FLT( 1010.3, FILTERBW,3, "filter bandwidth"                                )
+MK_FLT( 1010.4, FILTERWL,3, "filter wavelength"                               )
+MK_FLT( 1010.5, FILTERLB,5, "lower bound of filter (units/%?)"                )
+MK_FLT( 1010.6, FILTERUB,5, "upper bound of filter (units/%?)"                )
+/* MOS/SIS have coded filter wheels, this is the code for the installed one */
+MK_INT( 1010.7, FILTSLID,   "filter drawer number"                            )
+
+/* first filter wheel of two */
+MK_INT( 1020.1, WHEELAID,   "'wheel' A position"                              )
+MK_STR( 1020.2, WHEELADE,   "description of filter"                           )
+MK_FLT( 1020.5, WHEELALB,4, "lower bound of filter A (units/%?)"              )
+MK_FLT( 1020.6, WHEELAUB,4, "upper bound of filter A (units/%?)"              )
+/* second filter wheel of two */
+MK_INT( 1030.1, WHEELBID,   "'wheel' B position"                              )
+MK_STR( 1030.2, WHEELBDE,   "description of filter"                           )
+MK_FLT( 1030.5, WHEELBLB,4, "lower bound of filter B (units/%?)"              )
+MK_FLT( 1030.6, WHEELBUB,4, "upper bound of filter B (units/%?)"              )
+
+/* 1100 through 1199 are general instrument set up values */
+
+/*
+ * For instruments that have an internal focus adjustment, this records
+ * the current position
+ */
+MK_FLT( 1101.0, INSTFOC ,7, "internal instrument focus value"                 )
+
+
+/*
+ * Spectrograph : 4000.000 to 4999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT( 4000.1, CMTSPEC1,   ""                                                )
+MK_CMT( 4000.2, CMTSPEC2,   "Spectrograph Description"                        )
+MK_CMT( 4000.3, CMTSPEC3,   "------------------------"                        )
+MK_CMT( 4000.4, CMTSPEC4,   ""                                                )
+
+/* 4100 through 4199 are MOS/SIS */
+
+/*
+ * There are a grism wheel and a mask slide on each side.  By analogy with
+ * the filter wheel names:
+ *  ID     - numeric position number of wheel or slide
+ *  <null> - text description of filter mounted in that position
+ *  SLID   - the grism wheels and mask slides have codes, this is the
+ *           number of the installed wheel or slide
+ */
+MK_INT( 4101.0, GRISMID ,   "grism position"                                  )
+MK_STR( 4102.0, GRISM   ,   "grism description"                               )
+MK_INT( 4103.0, GRISSLID,   "grism drawer number"                             )
+MK_INT( 4111.0, MASKID  ,   "mask position"                                   )
+MK_STR( 4112.0, MASK    ,   "mask description"                                )
+MK_INT( 4113.0, MASKSLID,   "mask slider number"                              )
+
+/* 4200 through 4299 are GECKO */
+
+/*
+ * Description of the grating installed
+ */
+MK_STR( 4201.0, DISPEL  ,   "grating description"                             )
+/*
+ * Dispersion axis used, always 2 now
+ */
+MK_INT( 4202.0, DISPAXIS,   "dispersion axis (1 or 2)"                        )
+/*
+ * Incidence angle
+ */
+MK_FLT( 4203.0, DISPANG ,6, "grating angle in degrees"                        )
+/*
+ * Resulting center wavelength
+ */
+MK_FLT( 4204.0, WAVELENG,10,"central wavelength in angstroms"                 )
+/*
+ * In this order
+ */
+MK_INT( 4205.0, ORDER   ,   "spectral order"                                  )
+/*
+ * Magic number
+ */
+MK_FLT( 4206.0, GRSETUP ,5, "grating setup constant in degrees"               )
+/*
+ * Another magic number
+ */
+MK_FLT( 4207.0, OPENANG2,7, "setup const in degrees (opening angle / 2)"      )
+/*
+ * Why "grism angle" if it's the angle between 2 prisms ???
+ */
+MK_FLT( 4208.0, GRISMANG,5, "rel.angle between prisms in degrees"             )
+
+/*
+ * unimplemented description of slicer used
+ */
+MK_STR( 4210.0, SLICER  ,   "image slicer in place"                           )
+
+/*
+ * OPEN or CLOSED for each hartman mask
+ */
+MK_STR( 4221.0, HART1A  ,   "hartman mask 1a position OPEN/CLOSED"            )
+MK_STR( 4221.1, HART1B  ,   "hartman mask 1b position OPEN/CLOSED"            )
+MK_STR( 4222.0, HART2   ,   "hartman mask 2 position OPEN/CLOSED"             )
+MK_STR( 4223.0, HART3   ,   "hartman mask 3 position OPEN/CLOSED"             )
+MK_STR( 4224.0, HART4   ,   "hartman mask 4 position OPEN/CLOSED"             )
+
+/*
+ * unimplemented description of train used
+ * could be UV/RED/CAFE
+ */
+MK_STR( 4230.0, COUDETRN,   "coude train color UV/RED/CAFE"                   )
+
+/*
+ * unimplemented exposure meter info
+ */
+MK_STR( 4240.0, EMFILTER,   "exposure meter filter description"               )
+MK_INT( 4241.0, EMCNTS  ,   "exposure meter counts at end"                    )
+MK_INT( 4242.0, MIDEXPTM,   "mid-exposure time (seconds)"                     )
+
+/*
+ * CAFE mode added an additional card indicating that the Coude train was
+ * not being used - this ought to be added to Gecko files with NOTUSED
+ * as the value
+ */
+MK_STR( 4290.0, CAFE    ,   "CAFE is being used Null/INUSE"                   )
+
+
+/* 4300 through 4399 are for Fabre-Perot etalons */
+
+/*
+ * Description of the etalon in use
+ */
+MK_STR( 4301.0, AUXINST ,   "fabry perot etalon description"                  )
+/*
+ * Number used to figure something
+ */
+MK_PFL( 4302.0, CONST   ,2, "fabry perot constant"                            )
+/*
+ * Number of scan positions
+ */
+MK_INT( 4303.0, NUMCHAN ,   "number of channels per scan"                     )
+/*
+ * Current scan position
+ */
+MK_INT( 4304.0, CURCHAN ,   "current channel"                                 )
+/*
+ * Actual control value sent to etalon for this position
+ */
+MK_INT( 4305.0, BINVAL  ,   "binary control value"                            )
+
+/*
+ * GriF needed a bunch more values so some of these are duplicates :-(
+ */
+/*
+ * GriF adds a Fabre-Perot etalon between AOB and KIR.  This value indicates
+ * the position of the slide holding the etalon.
+ */
+MK_STR( 4320.0, GRFPPOS ,   "GriF position of FP carriage - In/Out"           )
+/*
+ * Etalon calibration values, order and standard wavelength, and BCV at
+ * standard wavelength
+ */
+MK_FLT( 4321.1, GRWAVORD,6, "GriF wavelength of order used to scan"           )
+MK_FLT( 4321.2, GRWAVCAL,6, "GriF wavelength of calibration spectral line"    )
+MK_FLT( 4321.3, GRBCVCAL,6, "GriF BCV at calibration line"                    )
+/*
+ * This records what the driver for the scan is
+ *   bcv      - specific BCV positions given
+ *   wave     - a wavelength range given and BCV's calculated
+ *   velocity - a range of delta velocities given and BCV's calculated
+ */
+MK_STR( 4322.0, GRSCANTY,   "GriF type of scan - bcv, wave, velocity"         )
+/*
+ * Wavelength values for scan, beginning, delta, and current
+ */
+MK_FLT( 4323.1, GRWAVBEG,6, "GriF wavelength at beginning of scan"            )
+MK_FLT( 4323.2, GRWAVSTP,6, "GriF wavelength step"                            )
+MK_FLT( 4323.3, GRWAVCUR,6, "GriF current observed wavelength"                )
+/*
+ * BCV equivalents (well, these are calculated from the desired wavelengths
+ * initially, but since the etalon is integral, the current wavelength value
+ * above is a conversion back from the BCV position)
+ */
+MK_FLT( 4324.1, GRBCVBEG,6, "GriF Binary Contol Value at beginning of scan"   )
+MK_FLT( 4324.2, GRBCVSTP,6, "GriF BCV step"                                   )
+MK_INT( 4324.3, GRBCVCUR,   "GriF applied BCV"                                )
+/*
+ * The scan itself is a sequence of etalon positions rounded from the
+ * desired wavelength range and step.  These are the count and current
+ * position in the scan.  (How is GRCURRCH different from GRBCVCUR ??? )
+ */
+MK_INT( 4325.1, GRNBCHAN,   "GriF number of channels in scan"                 )
+MK_INT( 4325.2, GRCURRCH,   "GriF current channel"                            )
+/*
+ * GriF also controls the plate parallelism.  These record the x and y
+ * commands
+ */
+MK_INT( 4326.1, GRBCV_X ,   "GriF X Binary Control Value FP"                  )
+MK_INT( 4326.2, GRBCV_Y ,   "GriF Y Binary Control Value FP"                  )
+
+/*
+ * Environment : 9000.000 to 9999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+/*
+ * Data logger probe readings.  NOTE: The first two columns of the comment
+ * for these make up the authoritative probe numbers.  "loggerh" MUST BE
+ * RECOMPILED to have these changes take effect.  It takes whatever is
+ * currently in the first two columns of the COMMENT and adds /p/logger/.
+ */
+MK_PFL( 9101.0, TESPMIRE,2, "03 temp, surface, primary mirror east deg C"     )
+MK_PFL( 9102.0, TESPMIRW,2, "02 temp, surface, primary mirror west deg C"     )
+MK_PFL( 9103.0, TESPMIRS,2, "01 temp, surface, primary mirror west side degC" )
+MK_PFL( 9104.0, TEAPMCLW,2, "54 temp, air, primary mirror cell west deg C"    )
+MK_PFL( 9105.0, TEAMIRCI,2, "58 temp, air, mirror cooling in at unit deg C"   )
+MK_PFL( 9106.0, TEAMIRCO,2, "27 temp, air, mirror cooling out at cell deg C"  )
+MK_PFL( 9107.0, TEAPMSPN,2, "65 temp, air, mirror spigot north cass deg C"    )
+MK_PFL( 9108.0, TEAPMSPS,2, "64 temp, air, mirror spigot nouth M3 deg C"      )
+MK_PFL( 9109.0, TEATRNGE,2, "23 temp, air, top ring east deg C"               )
+MK_PFL( 9110.0, TEATRNGW,2, "06 temp, air, top ring west deg C"               )
+MK_PFL( 9111.0, TEANRLSB,2, "19 temp, air, north rail support beam deg C"     )
+MK_PFL( 9112.0, TESHRSET,2, "08 temp, surface, horseshoe east top deg C"      )
+MK_PFL( 9113.0, TESTELTL,2, "49 temp, surface, telescope truss low deg C"     )
+MK_PFL( 9114.0, TESTELTH,2, "52 temp, surface, telescope truss high deg C"    )
+MK_PFL( 9115.0, TEALOWWS,2, "38 temp, air, dome lower weather stat side degC" )
+MK_PFL( 9116.0, TEATOPWS,2, "36 temp, air, dome top weather stat side deg C"  )
+MK_PFL( 9117.0, TEATOPOP,2, "37 temp, air, dome top opposite weath side degC" )
+MK_PFL( 9118.0, TEA2INCH,2, "45 temp, air, two inches above fifth floor degC" )
+MK_PFL( 9119.0, TEA2INEB,2, "53 temp, air, two inches up by electronics degC" )
+MK_PFL( 9120.0, TEA6FOOT,2, "43 temp, air, six feet above fifth floor deg C"  )
+MK_PFL( 9121.0, TESCONRM,2, "61 temp, surface, floor above control room degC" )
+MK_PFL( 9122.0, TESPIERN,2, "59 temp, surface, floor by north pier deg C"     )
+MK_PFL( 9123.0, TESPIERS,2, "60 temp, surface, floor by south pier deg C"     )
+MK_PFL( 9124.0, TEAWTHRT,2, "35 temp, air, weathertron deg C"                 )
+MK_PFL( 9125.0, TEMPERAT,2, "86 temp, air, weather tower deg C"               )
+MK_PFL( 9126.0, WINDSPED,2, "84 wind speed, weather tower knots"              )
+MK_PFL( 9127.0, WINDDIR ,2, "85 wind direction, weather tower deg (N=0 E=90)" )
+MK_PFL( 9128.0, RELHUMID,2, "87 relative humidity, weather tower %"           )
+MK_PFL( 9129.0, PRESSURE,2, "31 barometric pressure, control room mb"         )
+
+/*
+ * Queue Scheduled Observing : 11000.000 to 11999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+/*
+ * Processing Pipeline : 15000.000 to 15999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT(15000.1, CMTPROC1,   ""                                                )
+MK_CMT(15000.2, CMTPROC2,   "Processing Pipeline"                             )
+MK_CMT(15000.3, CMTPROC3,   "-------------------"                             )
+MK_CMT(15000.4, CMTPROC4,   ""                                                )
+MK_STR(15101.0, CRUNID,     "Elixir camera run ID"                            )
+/*
+ * Archive System : 90000.000 to 99999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+#endif /* !_INCLUDED_fh_registry */
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.h.new
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.h.new	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry.h.new	(revision 23490)
@@ -0,0 +1,719 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`fh_registry.h' - A registry of FITS keywords in use at CFHT.
+
+This file is part of version 1 of the FITS Handling Library.
+Read the `License' file for terms of use and distribution.
+Copyright 2001, Canada-France-Hawaii Telescope, daprog@cfht.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+/*
+ * $Id: fh_registry.h,v 1.4 2002/02/09 04:01:51 thomas Exp isani $
+ *
+ * Documentation: See http://software.cfht.hawaii.edu/fh_registry/
+ */
+
+#ifndef _INCLUDED_fh_registry
+#define _INCLUDED_fh_registry 1
+
+#if defined(__GNUC__) && defined(__STDC__)
+static const char fh_registry_rcs_id[] __attribute__ ((__unused__)) = "@(#) $Id: fh_registry.h,v 1.4 2002/02/09 04:01:51 thomas Exp isani $" ;
+#else
+static const char fh_registry_rcs_id[] = "@(#) $Id: fh_registry.h,v 1.4 2002/02/09 04:01:51 thomas Exp isani $";
+#endif
+
+/*
+ * These are environment variables which the CFHT "ccd" process (both
+ * script and older C program) make available to instrument handler programs.
+ */
+#define ENV_FFTEMPLATE	"FFTEMPLATE"
+#define ENV_OBSTYPE	"OBSTYPE"
+#define ENV_INTTIME	"INTTIME"
+#define ENV_EXPNUM	"EXPNUM"
+#define ENV_SEQNUM	"SEQNUM"
+
+/*
+ * This macro is used inside the other macros (ID_FLT, ID_INT, etc.)
+ * so that the keyword names can be referred to as fh_kw_FOO
+ * This can be used as an identifier to fh_get() or any other function
+ * instead of using the string constant "FOO".
+ */
+
+#define ID_FLT(idx, name, keyword, prec, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, double value) \
+{ fh_set_flt(hu, idx, keyword, value, prec, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, double value, const char* new_comment) \
+{ fh_set_flt(hu, idx, keyword, value, prec, new_comment); } \
+static inline void \
+fh_get_##name (HeaderUnit hu, double* value) \
+{ fh_get_flt(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; }
+
+#define ID_INT(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, int value) \
+{ fh_set_int(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, int value, const char* new_comment) \
+{ fh_set_int(hu, idx, keyword, value, new_comment); } \
+static inline void \
+fh_get_##name (HeaderUnit hu, int* value) \
+{ fh_get_int(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; }
+
+#define ID_BLN(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, fh_bool value) \
+{ fh_set_bool(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, fh_bool value, const char* new_comment) \
+{ fh_set_bool(hu, idx, keyword, value, new_comment); } \
+static inline void \
+fh_get_##name (HeaderUnit hu, fh_bool* value) \
+{ fh_get_bool(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; }
+
+#define ID_STR(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, const char* value) \
+{ fh_set_str(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, const char* value, const char* new_comment) \
+{ fh_set_str(hu, idx, keyword, value, new_comment); } \
+static inline void \
+fh_get_##name (HeaderUnit hu, char* value, int maxlen) \
+{ fh_get_str(hu, keyword, value, maxlen); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; }
+
+#define ID_VAL(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, const char* value, const char* new_comment) \
+{ fh_set_val(hu, idx, keyword, value, new_comment); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; }
+
+#define ID_CMT(idx, name, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu) \
+{ fh_set_com(hu, idx, "COMMENT", comment); }
+
+/*
+ * Now the auto-stringified versions of ID_*() ...
+ */
+#define MK_FLT(idx, name, prec, comment) ID_FLT(idx, name, #name, prec, comment)
+#define MK_INT(idx, name, comment) ID_INT(idx, name, #name, comment)
+#define MK_STR(idx, name, comment) ID_STR(idx, name, #name, comment)
+#define MK_VAL(idx, name, comment) ID_VAL(idx, name, #name, comment)
+#define MK_BLN(idx, name, comment) ID_BLN(idx, name, #name, comment)
+#define MK_CMT(idx, name, comment) ID_CMT(idx, name, comment)
+
+/*
+ * FITS Structure : 0.000 to 9.999
+ *
+ * The following keywords give basic information about the structure and
+ * dimensions of the FITS file, and must appear in the specific order
+ * below, usually without any other intervening keywords.
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_BLN( 0.0,	SIMPLE  ,   "Standard FITS"                                   )
+MK_STR( 0.0,	XTENSION,   ""                                                )
+MK_INT( 1.0,	BITPIX  ,   "Bits per pixel"                                  )
+MK_INT( 2.0,	NAXIS   ,   "Number of axes"                                  )
+MK_INT( 2.1,	NAXIS1  ,   "Number of pixel columns"                         )
+MK_INT( 2.2,	NAXIS2  ,   "Number of pixel rows"                            )
+MK_INT( 2.3,	NAXIS3  ,   "Number of stacked frames (cube)"                 )
+MK_BLN( 3.0,	EXTEND  ,   "File contains extensions"                        )
+MK_INT( 3.1,	NEXTEND ,   "Number of extensions"                            )
+MK_BLN( 4.0,	GROUPS  ,   "File contains random groups records"             )
+MK_INT( 5.0,	PCOUNT  ,   "Random parameters before each array in a group"  )
+MK_INT( 6.0,	GCOUNT  ,   "Number of random groups"                         )
+MK_INT( 7.0000,	TFIELDS ,   "Number of fields in a row"                       )
+MK_STR( 7.0011,	TFORM1  ,   "Table format for field 1"                        )
+MK_INT( 7.0012,	TBCOL1  ,   "Start Column for field 1"                        )
+MK_STR( 7.0021,	TFORM2  ,   "Table format for field 2"                        )
+MK_INT( 7.0022,	TBCOL2  ,   "Start Column for field 2"                        )
+MK_STR( 7.0031,	TFORM3  ,   "Table format for field 3"                        )
+MK_INT( 7.0032,	TBCOL3  ,   "Start Column for field 3"                        )
+MK_STR( 7.0041,	TFORM4  ,   "Table format for field 4"                        )
+MK_INT( 7.0042,	TBCOL4  ,   "Start Column for field 4"                        )
+MK_STR( 7.0051,	TFORM5  ,   "Table format for field 5"                        )
+MK_INT( 7.0052,	TBCOL5  ,   "Start Column for field 5"                        )
+
+/*
+ * Summary : 50.000 to 59.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(   50.1, CMTSUM1 ,   ""                                                )
+MK_CMT(   50.2, CMTSUM2 ,   "Observation Summary"                             )
+MK_CMT(   50.3, CMTSUM3 ,   "-------------------"                             )
+MK_CMT(   50.4, CMTSUM4 ,   ""                                                )
+MK_CMT(   50.5, CMTSUM5 ,   ""                                                )
+MK_STR(   51.0, CMMTOBS ,   ""                                                )
+MK_STR(   52.0, CMMTSEQ ,   ""                                                )
+MK_STR(   53.0, OBJECT  ,   ""                                                )
+MK_STR(   54.0, OBSERVER,   ""                                                )
+MK_STR(   55.0, PI_NAME ,   ""                                                )
+MK_STR(   56.0, RUNID   ,   ""                                                )
+
+/*
+ * General : 70.000 to 79.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(   70.1, CMTGEN1 ,   ""                                                )
+MK_CMT(   70.2, CMTGEN2 ,   "General"                                         )
+MK_CMT(   70.3, CMTGEN3 ,   "-------"                                         )
+MK_CMT(   70.4, CMTGEN4 ,   ""                                                )
+MK_STR(   71.0, FILENAME,   "Base filename at acquisition"                    )
+MK_STR(   71.1, EXTNAME ,   "Extension name"                                  )
+MK_INT(   71.2, EXTVER  ,   "Extension version"                               )
+MK_STR(   74.0, DATE    ,   "UTC Date of file creation"                       )
+MK_STR(   74.1, HSTTIME ,   "Local time in Hawaii"                            )
+MK_STR(   75.0, ORIGIN  ,   "Canada-France-Hawaii Telescope"                  )
+MK_STR(   77.0, IMAGESWV,   "Image creation software version"                 )
+
+/*
+ * Detector : 100.000 to 199.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  100.1,	CMTDET1	,   ""                                                )
+MK_CMT(  100.2,	CMTDET2	,   "Detector"                                        )
+MK_CMT(  100.3,	CMTDET3	,   "--------"                                        )
+MK_CMT(  100.4,	CMTDET4	,   ""                                                )
+MK_STR(  101.0,	DETECTOR,   ""                                                )
+MK_STR(  102.0, DETSIZE	,   "Total data pixels in full mosaic"                )
+MK_STR(  103.0,	RASTER	,   ""                                                )
+MK_STR(  105.0,	CCDSUM	,   "Binning factors"                                 )
+MK_INT(  105.1,	CCDBIN1	,   "Binning factor along first axis"                 )
+MK_INT(  105.2,	CCDBIN2	,   "Binning factor along second axis"                )
+MK_FLT(  110.0,	PIXSIZE ,3, "Pixel size for both axes (microns)"              )
+MK_FLT(  111.1,	PIXSIZE1,3, "Pixel size for axis 1 (microns)"                 )
+MK_FLT(  111.2,	PIXSIZE2,3, "Pixel size for axis 2 (microns)"                 )
+MK_FLT(  112.1,	PIXSCAL1,4, "Pixel scale for axis 1 (arcsec/pixel)"           )
+MK_FLT(  112.2,	PIXSCAL2,4, "Pixel scale for axis 2 (arcsec/pixel)"           )
+MK_STR(  130.0,	AMPLIST	,   "List of amplifiers"                              )
+MK_STR(  131.0,	AMPNAME	,   "Amplifier name"                                  )
+MK_STR(  140.0, CONSWV	,   "Controller software DSPID and SERNO versions"    )
+MK_STR(  150.0,	DETSTAT	,   "Detector status"                                 )
+MK_FLT(  150.1, DETTEM  ,3, "Detector temperature"                            )
+MK_INT(  152.0, MAXLIN  ,   "Maximum linearity value (ADU)"                   )
+MK_INT(  152.1, SATURATE,   "Saturation value (ADU)"                          )
+MK_FLT(  155.0,	GAIN    ,3, "Amplifier gain (electrons/ADU)"                  )
+MK_FLT(  156.0,	RDNOISE ,3, "Read noise (electrons)"                          )
+MK_FLT(  157.0, DCURRENT,5, "Dark current (ADU/pixel/second)"                 )
+
+/* ****************************************************
+ * *** World Coordinate System : 300.000 to 399.999 ***
+ * ****************************************************
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+/*
+ * Telescope : 500.000 to 599.999
+ *
+ * Almost all keywords we define can be generated with the MK_XXX macros.
+ * The only exceptions are those keywords which contain a '-', since the
+ * '-' is not a legal character in a C identifier.  TCS uses four of them
+ * (DATE-OBS, UTC-OBS, MJD-OBS, and LST-OBS.)  The ID_XXX macros are used
+ * and the '-' is translated to a '_' (underscore) for use in C programs.
+ *
+ * NOTE: TELESCOP, TELSTAT, TELCONF, LATITUDE, and LONGITUD are currently
+ * inserted by DetCom and _not_ tcsh.  This should probably be changed.
+ *
+ *TYPE --IDX--  SYMBOL--  KEYWORD-  -----------COMMENT----------------------*/
+ID_STR( 511.1,	DATE_OBS,"DATE-OBS", "Date at start of observation (UTC)"     )
+ID_STR( 512.1,	UTC_OBS ,"UTC-OBS", "Time at start of observation (UTC)"      )
+ID_FLT( 513.1,MJD_OBS,"MJD-OBS",12,"Modified Julian Date at start of obs."    )
+ID_STR( 514.1,	LST_OBS ,"LST-OBS", "Sidereal time at start of exposure"      )
+
+/*TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  500.1, CMTTCS1 ,   ""                                                )
+MK_CMT(  500.2, CMTTCS2 ,   "Telescope"                                       )
+MK_CMT(  500.3, CMTTCS3 ,   "---------"                                       )
+MK_CMT(  500.4, CMTTCS4 ,   ""                                                )
+MK_STR(  501.0, TELESCOP,   ""                                                )
+MK_FLT(  502.1, LATITUDE,7, "Latitude (degrees N)"                            )
+MK_FLT(  502.2, LONGITUD,7, "Longitude (degrees E)"                           )
+MK_STR(  503.0, TELSTAT ,   "Telescope Control System status"                 )
+MK_STR(  510.0, TIMESYS ,   "Time System for DATExxxx"                        )
+MK_STR(  512.0,	UTIME   ,   "Time at start of observation (UT)"               )
+MK_FLT(  513.0,	MJDATE  ,12,"Modified Julian Date at start of observation"    )
+MK_STR(  514.0,	SIDTIME ,   "Sidereal time at start of observation"           )
+MK_VAL(  521.0,	EPOCH   ,   "Equinox of coordinates"                          )
+MK_VAL(  521.1,	EQUINOX ,   "Equinox of coordinates"                          )
+MK_STR(  522.0,	RADECSYS,   "Coordinate system for equinox (FK4/FK5/GAPPT)"   )
+MK_STR(  522.1,	RA      ,   "Object right ascension"                          )
+MK_STR(  522.2,	DEC     ,   "Object declination"                              )
+MK_FLT(  523.1,	RA_DEG  ,8, "Object right ascension in degrees"               )
+MK_FLT(  523.2,	DEC_DEG ,8, "Object declination in degrees"                   )
+MK_INT(  530.0,	NGUIDER	,   "Number of guiders"                               )
+MK_VAL(  530.2,	GUIEQUIN,   "TCS guider equinox"                              )
+MK_STR(  530.3,	GUIRADEC,   "TCS guider system for equinox"                   )
+MK_STR(  530.4,	GUIRA   ,   "TCS guider right ascension"                      )
+MK_STR(  530.5,	GUIDEC  ,   "TCS guider declination"                          )
+
+MK_STR(  531.1,	GUINAME1,   "TCS guider #1 identification"                    )
+MK_VAL(  531.2,	GUIEQUI1,   "TCS guider #1 equinox"                           )
+MK_STR(  531.3,	GUIRADE1,   "TCS guider #1 system for equinox"                )
+MK_STR(  531.4,	GUIRA1  ,   "TCS guider #1 right ascension"                   )
+MK_STR(  531.5,	GUIDEC1 ,   "TCS guider #1 declination"                       )
+MK_STR(  531.6, GUIOBJN1,   "TCS guider #1 object name"                       )
+MK_FLT(	 531.7,	GUIMAGN1,2, "TCS guider #1 object magnitude"                  )
+
+MK_STR(  532.1,	GUINAME2,   "TCS guider #2 identification"                    )
+MK_VAL(  531.0,	GUIEQUI2,   "TCS guider #2 equinox"                           )
+MK_STR(  532.0,	GUIRADE2,   "TCS guider #2 system for equinox"                )
+MK_STR(  532.1,	GUIRA2  ,   "TCS guider #2 right ascension"                   )
+MK_STR(  532.2,	GUIDEC2 ,   "TCS guider #2 declination"                       )
+MK_STR(  532.6, GUIOBJN2,   "TCS guider #2 object name"                       )
+MK_FLT(	 532.7,	GUIMAGN2,2, "TCS guider #2 object magnitude"                  )
+
+MK_STR(  533.1,	GUINAME3,   "TCS guider #3 identification"                    )
+MK_VAL(  533.2,	GUIEQUI3,   "TCS guider #3 equinox"                           )
+MK_STR(  533.3,	GUIRADE3,   "TCS guider #3 system for equinox"                )
+MK_STR(  533.4,	GUIRA3  ,   "TCS guider #3 right ascension"                   )
+MK_STR(  533.5,	GUIDEC3 ,   "TCS guider #3 declination"                       )
+MK_STR(  533.6, GUIOBJN3,   "TCS guider #3 object name"                       )
+MK_FLT(	 533.7,	GUIMAGN3,2, "TCS guider #3 object magnitude"                  )
+
+MK_STR(  534.1,	GUINAME4,   "TCS guider #4 identification"                    )
+MK_VAL(  534.2,	GUIEQUI4,   "TCS guider #4 equinox"                           )
+MK_STR(  534.3,	GUIRADE4,   "TCS guider #4 system for equinox"                )
+MK_STR(  534.4,	GUIRA4  ,   "TCS guider #4 right ascension"                   )
+MK_STR(  534.5,	GUIDEC4 ,   "TCS guider #4 declination"                       )
+MK_STR(  534.6, GUIOBJN4,   "TCS guider #4 object name"                       )
+MK_FLT(	 534.7,	GUIMAGN4,2, "TCS guider #4 object magnitude"                  )
+
+MK_FLT(  540.0,	AIRMASS ,4, "Airmass at start of observation"                 )
+MK_STR(  550.0,	FOCUSID ,   "Telescope focus in use"                          )
+MK_STR(  550.1, TELCONF ,   "Telescope focus in use"                          )
+MK_INT(  551.0,	FOCUSPOS,   "Telescope focus encoder readout"                 )
+MK_INT(  551.1,	TELFOCUS,   "Telescope focus encoder readout"                 )
+MK_FLT(  560.0,	BONANGLE,5, "Telescope bonnette rotation angle in degrees"    )
+MK_FLT(  560.1,	ROTANGLE,5, "Telescope bonnette rotation angle in degrees"    )
+MK_FLT(  561.1,	XPROBE  ,5, "Telescope bonnette guide probe X position"       )
+MK_FLT(  561.2,	YPROBE  ,5, "Telescope bonnette guide probe Y position"       )
+MK_FLT(  561.3,	ZPROBE  ,5, "Telescope bonnette guide probe Z position"       )
+
+/*
+ * Adaptive Optics : 700.000 to 799.999
+ *
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT(  700.1, CMTAOB1 ,   ""                                                )
+MK_CMT(  700.2, CMTAOB2 ,   "Adaptive Optics Bonnette"                        )
+MK_CMT(  700.3, CMTAOB3 ,   "------------------------"                        )
+MK_CMT(  700.4, CMTAOB4 ,   ""                                                )
+
+/* 710 through 719 are input control values to the real time system */
+
+/*
+ * state of AO correction (terms come from original description of loop
+ * operation which was deemed not PC and changed to "correction")
+ */
+MK_STR(  711.0, AOBLOOP ,   "AOB closed loop Open/Closed"                     )
+/*
+ * primary gain in the integrator providing signals to the bimorph
+ */
+MK_FLT(  712.0, LOOPGAIN,1, "Gain of the integrator"                          )
+/*
+ * correction can be fully automatic (all modes, bimorph offloading to
+ * tip/tilt mirror - nested), manual (manually selected modes, tip/tilt
+ * mode if selected only feeds tip/tilt mirror, i.e., not via bimorph
+ * - single), or tip/tilt only (bimorph not used at all, kept flat)
+ */
+MK_STR(  713.0, LOOPNES ,   "Loop type \"Nested\"/\"Tip/Tilt\"/\"Single\""    )
+/*
+ * in automatic correction this is the gain between the bimorph and the
+ * tip/tilt mirror
+ */
+MK_FLT(  714.0, LOOPNESG,1, "Nested loop gain"                                )
+/*
+ * the individual mode gains can be fixed or optimized based on signal
+ * levels
+ */
+MK_STR(  715.0, LOOPOPT ,   "Optimized loop control True/False"               )
+/*
+ * stroke of the membrane mirror (1-256)
+ */
+MK_INT(  716.0, WFSGOPT ,   "WFS optical gain"                                )
+/*
+ * integration time for each calculation cycle
+ */
+MK_FLT(  717.0, WFSSAMP ,3, "WFS sampling period (sec)"                       )
+
+/* 720-729 are measured values calculated by the real time system */
+
+/*
+ * calculated value of R0
+ */
+MK_FLT(  721.0, R0      ,1, "Fried parameter (cm)"                            )
+/*
+ * sum of the photon counts on the 19 APD's, for the most recent integration
+ */
+MK_INT(  722.0, WFSCOUNT,   "Total flux count on WFS"                         )
+
+/* 750-769 are input control values to the bench control ProLog(tm) */
+
+/*
+ * whether the atmospheric dispersion corrector (ADC) is in or out of the
+ * optical path
+ */
+MK_STR(  751.0, ADCPOS  ,   "AOB ADC position In/Out"                         )
+/*
+ * angle of the dispersion caused by the ADC
+ */
+MK_FLT(  752.0, ADCANGLE,2, "AOB ADC angle (degrees)"                         )
+/*
+ * amount of dispersion caused by the relative angle between the ADC prisms
+ */
+MK_FLT(  753.0, ADCPOWER,4, "AOB ADC power"                                   )
+/*
+ * beam splitter id code read from slugs on the splitters
+ */
+MK_INT(  754.0, BEAMSPID,   "Beam splitter ID"                                )
+/*
+ * beam splitter description based on the above codes
+ */
+MK_STR(  755.0, BEAMSP  ,   "Beam splitter description"                       )
+/*
+ * whether the AOB central mirror is in (AO system in light path)
+ * or out (AO system not being used)
+ */
+MK_STR(  756.0, MIRSLIDE,   "AOB mirror slide \"F/20\"/\"F/8\""               )
+/*
+ * neutral density filter position (in optical path to WFS)
+ *   0 == home
+ *   1 == no filter (close but not quite the same physical position as home)
+ *   2 == 1.0 density filter
+ *   3 == 2.0    "      "
+ *   4 == 3.0    "      "
+ */
+MK_INT(  757.0, WFSNDID ,   "WFS ND filter position"                          )
+/*
+ * following 3 are the Wave Front Sensor (WFS) position in a coordinate
+ * system close to having z parallel to the optical path
+ */
+MK_FLT(  761.0, WFSX    ,1, "Translated WFS X coord (steps)"                  )
+MK_FLT(  762.0, WFSY    ,1, "Translated WFS Y coord (steps)"                  )
+MK_FLT(  763.0, WFSZ    ,1, "Translated WFS Z coord (steps)"                  )
+/*
+ * Calibration Sources : 900.000 to 999.999
+ *
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT(  900.1, CMTCAL1 ,   ""                                                )
+MK_CMT(  900.2, CMTCAL2 ,   "Calibration sources"                             )
+MK_CMT(  900.3, CMTCAL3 ,   "-------------------"                             )
+MK_CMT(  900.4, CMTCAL4 ,   ""                                                )
+
+/* 910 - 919 are flat field lamps */
+
+/*
+ * Gecko lamps are computer controlled, these give On/Off status and
+ * intensity
+ */
+MK_STR(  910.0, FFLAMPON,   "flatfield lamp status ON/OFF"                    )
+MK_INT(  911.0, FFLAMP  ,   "flatfield lamp intensity"                        )
+/* add which lamp if get control of dome flat fields */
+
+/* 920-999 are calibration lamp sources */
+
+/*
+ * Gecko has 4 lamps, these give On/Off status and descriptions
+ */
+MK_STR(  920.0, CLAMP0ON,   "comparison lamp 0 status ON/OFF"                 )
+MK_STR(  920.1, CLAMP0  ,   "comparison lamp 0 description"                   )
+MK_STR(  921.0, CLAMP1ON,   "comparison lamp 1 status ON/OFF"                 )
+MK_STR(  921.1, CLAMP1  ,   "comparison lamp 1 description"                   )
+MK_STR(  922.0, CLAMP2ON,   "comparison lamp 2 status ON/OFF"                 )
+MK_STR(  922.1, CLAMP2  ,   "comparison lamp 2 description"                   )
+MK_STR(  923.0, CLAMP3ON,   "comparison lamp 3 status ON/OFF"                 )
+MK_STR(  923.1, CLAMP3  ,   "comparison lamp 3 description"                   )
+
+/*
+ * GumBall has 10 lamps, though the last two are Fabre-Perot lamps sharing
+ * the same light path and cannot be on together, these give On/Off status
+ * for each
+ */
+MK_STR(  930.0, CALIBL0 ,   "lamp 0 ON/OFF"                                   )
+MK_STR(  931.0, CALIBL1 ,   "lamp 1 ON/OFF"                                   )
+MK_STR(  932.0, CALIBL2 ,   "lamp 2 ON/OFF"                                   )
+MK_STR(  933.0, CALIBL3 ,   "lamp 3 ON/OFF"                                   )
+MK_STR(  934.0, CALIBL4 ,   "lamp 4 ON/OFF"                                   )
+MK_STR(  935.0, CALIBL5 ,   "lamp 5 ON/OFF"                                   )
+MK_STR(  936.0, CALIBL6 ,   "lamp 6 ON/OFF"                                   )
+MK_STR(  937.0, CALIBL7 ,   "lamp 7 ON/OFF"                                   )
+MK_STR(  938.0, CALIBL8 ,   "lamp 8 ON/OFF"                                   )
+MK_STR(  939.0, CALIBL9 ,   "lamp 9 ON/OFF"                                   )
+
+/*
+ * Instrument : 1000.000 to 1999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT( 1000.1, CMTINST1,   ""                                                )
+MK_CMT( 1000.2, CMTINST2,   "Instrument Description"                          )
+MK_CMT( 1000.3, CMTINST3,   "----------------------"                          )
+MK_CMT( 1000.4, CMTINST4,   ""                                                )
+
+/*
+ * There are lots of shared keywords among the instruments and spectrographs.
+ * Where the keywords are really general purpose (e.g., FILTER) they are
+ * separated from the instrument areas.  Where the keywords are more specific,
+ * they are associated with the "first" (arbitrarily defined as starting about
+ * 1992 :-) instrument that used them.
+ */
+
+/* 1010 through 1099 are filter wheel info */
+
+/*
+ * Somewhere in the optical train there be filters.  If there is one filter
+ * use the FILTER sequence, whether it is actually in the detector or the
+ * instrument.  If there are two filters (usual case for IR), use the WHEEL
+ * sequence.  For an IR camera on an instrument with a filter, use both.
+ */
+
+/*
+ * code descriptions for all wheel identifiers
+ *
+ *  ID - numeric position number of wheel
+ *  <null> or DE - text description of filter mounted in that position
+ *  LB - lower bound of filter transmission - units Angstrom or microns?
+ *  UB - upper bound of filter transmission - units Angstrom or microns?
+ *  BW - bandwidth of filter transmission - units Angstrom or microns?
+ *  WL - center wave length of filter transmission - units Angstrom or microns?
+ */
+
+/* single filter wheel */
+MK_INT( 1010.1, FILTERID,   "wheel position"                                  )
+MK_STR( 1010.2, FILTER  ,   "description of filter"                           )
+MK_FLT( 1010.3, FILTERBW,3, "filter bandwidth"                                )
+MK_FLT( 1010.4, FILTERWL,3, "filter wavelength"                               )
+MK_FLT( 1010.5, FILTERLB,5, "lower bound of filter (units/%?)"                )
+MK_FLT( 1010.6, FILTERUB,5, "upper bound of filter (units/%?)"                )
+/* MOS/SIS have coded filter wheels, this is the code for the installed one */
+MK_INT( 1010.7, FILTSLID,   "filter drawer number"                            )
+
+/* first filter wheel of two */
+MK_INT( 1020.1, WHEELAID,   "'wheel' A position"                              )
+MK_STR( 1020.2, WHEELADE,   "description of filter"                           )
+MK_FLT( 1020.5, WHEELALB,4, "lower bound of filter A (units/%?)"              )
+MK_FLT( 1020.6, WHEELAUB,4, "upper bound of filter A (units/%?)"              )
+/* second filter wheel of two */
+MK_INT( 1030.1, WHEELBID,   "'wheel' B position"                              )
+MK_STR( 1030.2, WHEELBDE,   "description of filter"                           )
+MK_FLT( 1030.5, WHEELBLB,4, "lower bound of filter B (units/%?)"              )
+MK_FLT( 1030.6, WHEELBUB,4, "upper bound of filter B (units/%?)"              )
+
+/* 1100 through 1199 are general instrument set up values */
+
+/*
+ * For instruments that have an internal focus adjustment, this records
+ * the current position
+ */
+MK_FLT( 1101.0, INSTFOC ,7, "internal instrument focus value"                 )
+
+
+/*
+ * Spectrograph : 4000.000 to 4999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT( 4000.1, CMTSPEC1,   ""                                                )
+MK_CMT( 4000.2, CMTSPEC2,   "Spectrograph Description"                        )
+MK_CMT( 4000.3, CMTSPEC3,   "------------------------"                        )
+MK_CMT( 4000.4, CMTSPEC4,   ""                                                )
+
+/* 4100 through 4199 are MOS/SIS */
+
+/*
+ * There are a grism wheel and a mask slide on each side.  By analogy with
+ * the filter wheel names:
+ *  ID     - numeric position number of wheel or slide
+ *  <null> - text description of filter mounted in that position
+ *  SLID   - the grism wheels and mask slides have codes, this is the
+ *           number of the installed wheel or slide
+ */
+MK_INT( 4101.0, GRISMID ,   "grism position"                                  )
+MK_STR( 4102.0, GRISM   ,   "grism description"                               )
+MK_INT( 4103.0, GRISSLID,   "grism drawer number"                             )
+MK_INT( 4111.0, MASKID  ,   "mask position"                                   )
+MK_STR( 4112.0, MASK    ,   "mask description"                                )
+MK_INT( 4113.0, MASKSLID,   "mask slider number"                              )
+
+/* 4200 through 4299 are GECKO */
+
+/*
+ * Description of the grating installed
+ */
+MK_STR( 4201.0, DISPEL  ,   "grating description"                             )
+/*
+ * Dispersion axis used, always 2 now
+ */
+MK_INT( 4202.0, DISPAXIS,   "dispersion axis (1 or 2)"                        )
+/*
+ * Incidence angle
+ */
+MK_FLT( 4203.0, DISPANG ,6, "grating angle in degrees"                        )
+/*
+ * Resulting center wavelength
+ */
+MK_FLT( 4204.0, WAVELENG,10,"central wavelength in angstroms"                 )
+/*
+ * In this order
+ */
+MK_INT( 4205.0, ORDER   ,   "spectral order"                                  )
+/*
+ * Magic number
+ */
+MK_FLT( 4206.0, GRSETUP ,5, "grating setup constant in degrees"               )
+/*
+ * Another magic number
+ */
+MK_FLT( 4207.0, OPENANG2,7, "setup const in degrees (opening angle / 2)"      )
+/*
+ * Why "grism angle" if it's the angle between 2 prisms ???
+ */
+MK_FLT( 4208.0, GRISMANG,5, "rel.angle between prisms in degrees"             )
+
+/*
+ * unimplemented description of slicer used
+ */
+MK_STR( 4210.0, SLICER  ,   "image slicer in place"                           )
+
+/*
+ * OPEN or CLOSED for each hartman mask
+ */
+MK_STR( 4221.0, HART1A  ,   "hartman mask 1a position OPEN/CLOSED"            )
+MK_STR( 4221.1, HART1B  ,   "hartman mask 1b position OPEN/CLOSED"            )
+MK_STR( 4222.0, HART2   ,   "hartman mask 2 position OPEN/CLOSED"             )
+MK_STR( 4223.0, HART3   ,   "hartman mask 3 position OPEN/CLOSED"             )
+MK_STR( 4224.0, HART4   ,   "hartman mask 4 position OPEN/CLOSED"             )
+
+/*
+ * unimplemented description of train used
+ * could be UV/RED/CAFE
+ */
+MK_STR( 4230.0, COUDETRN,   "coude train color UV/RED/CAFE"                   )
+
+/*
+ * unimplemented exposure meter info
+ */
+MK_STR( 4240.0, EMFILTER,   "exposure meter filter description"               )
+MK_INT( 4241.0, EMCNTS  ,   "exposure meter counts at end"                    )
+MK_INT( 4242.0, MIDEXPTM,   "mid-exposure time (seconds)"                     )
+
+/*
+ * CAFE mode added an additional card indicating that the Coude train was
+ * not being used - this ought to be added to Gecko files with NOTUSED
+ * as the value
+ */
+MK_STR( 4290.0, CAFE    ,   "CAFE is being used Null/INUSE"                   )
+
+
+/* 4300 through 4399 are for Fabre-Perot etalons */
+
+/*
+ * Description of the etalon in use
+ */
+MK_STR( 4301.0, AUXINST ,   "fabry perot etalon description"                  )
+/*
+ * Number used to figure something
+ */
+MK_FLT( 4302.0, CONST   ,2, "fabry perot constant"                            )
+/*
+ * Number of scan positions
+ */
+MK_INT( 4303.0, NUMCHAN ,   "number of channels per scan"                     )
+/*
+ * Current scan position
+ */
+MK_INT( 4304.0, CURCHAN ,   "current channel"                                 )
+/*
+ * Actual control value sent to etalon for this position
+ */
+MK_INT( 4305.0, BINVAL  ,   "binary control value"                            )
+
+/*
+ * GriF needed a bunch more values so some of these are duplicates :-(
+ */
+/*
+ * GriF adds a Fabre-Perot etalon between AOB and KIR.  This value indicates
+ * the position of the slide holding the etalon.
+ */
+MK_STR( 4320.0, GRFPPOS ,   "GriF position of FP carriage - In/Out"           )
+/*
+ * Etalon calibration values, order and standard wavelength, and BCV at
+ * standard wavelength
+ */
+MK_FLT( 4321.1, GRWAVORD,6, "GriF wavelength of order used to scan"           )
+MK_FLT( 4321.2, GRWAVCAL,6, "GriF wavelength of calibration spectral line"    )
+MK_FLT( 4321.3, GRBCVCAL,6, "GriF BCV at calibration line"                    )
+/*
+ * This records what the driver for the scan is
+ *   bcv      - specific BCV positions given
+ *   wave     - a wavelength range given and BCV's calculated
+ *   velocity - a range of delta velocities given and BCV's calculated
+ */
+MK_STR( 4322.0, GRSCANTY,   "GriF type of scan - bcv, wave, velocity"         )
+/*
+ * Wavelength values for scan, beginning, delta, and current
+ */
+MK_FLT( 4323.1, GRWAVBEG,6, "GriF wavelength at beginning of scan"            )
+MK_FLT( 4323.2, GRWAVSTP,6, "GriF wavelength step"                            )
+MK_FLT( 4323.3, GRWAVCUR,6, "GriF current observed wavelength"                )
+/*
+ * BCV equivalents (well, these are calculated from the desired wavelengths
+ * initially, but since the etalon is integral, the current wavelength value
+ * above is a conversion back from the BCV position)
+ */
+MK_FLT( 4324.1, GRBCVBEG,6, "GriF Binary Contol Value at beginning of scan"   )
+MK_FLT( 4324.2, GRBCVSTP,6, "GriF BCV step"                                   )
+MK_INT( 4324.3, GRBCVCUR,   "GriF applied BCV"                                )
+/*
+ * The scan itself is a sequence of etalon positions rounded from the
+ * desired wavelength range and step.  These are the count and current
+ * position in the scan.  (How is GRCURRCH different from GRBCVCUR ??? )
+ */
+MK_INT( 4325.1, GRNBCHAN,   "GriF number of channels in scan"                 )
+MK_INT( 4325.2, GRCURRCH,   "GriF current channel"                            )
+/*
+ * GriF also controls the plate parallelism.  These record the x and y
+ * commands
+ */
+MK_INT( 4326.1, GRBCV_X ,   "GriF X Binary Control Value FP"                  )
+MK_INT( 4326.2, GRBCV_Y ,   "GriF Y Binary Control Value FP"                  )
+
+/*
+ * Environment : 9000.000 to 9999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+/*
+ * Queue Scheduled Observing : 11000.000 to 11999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+/*
+ * Processing Pipeline : 15000.000 to 15999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+/*
+ * Archive System : 90000.000 to 99999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+#endif /* !_INCLUDED_fh_registry */
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry_detcom_notes
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry_detcom_notes	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry_detcom_notes	(revision 23490)
@@ -0,0 +1,191 @@
+Block
+0	PHU
+1	PHU
+2	EHU1
+3	EHU1
+4	EHU1
+5	DATA(1)
+6	DATA(2)
+...
+5967	DATA(5963)
+5968	EHU2
+5969	EHU2
+5970	EHU2
+5971	DATA(1)
+...
+11933	DATA(5963)
+11934	EHU3
+11935	EHU3
+11936	EHU3
+11937	DATA(1)
+...
+17900	EHU4
+23866	EHU5
+29832	EHU6
+35798	EHU7
+41764	EHU8
+47730	EHU9
+53696	EHU10
+59662	EHU11
+65628	EHU12
+65629	EHU12
+65630	EHU12
+65631	DATA(1)
+71593	DATA(5963)
+EOF
+
+Index	Header name	Example Value
+
+0	SIMPLE		T
+0	XTENSION	'IMAGE   '
+1	BITPIX		16 / Values from 0..65535 (BZERO=32768)
+2	NAXIS		2
+2.1	NAXIS1		2080
+2.2	NAXIS2		4128
+3	EXTEND		T
+3.1	NEXTEND		12
+4	GROUPS		T
+5	PCOUNT		0
+6	GCOUNT		1
+7	TFIELDS		10
+7.100	TFORM1
+7.101	TBCOL1		
+7.200	TFORM2		
+7.201	TBCOL2	
+100.0	COMMENT
+100.1	COMMENT  General Information
+100.2	COMMENT  -------------------
+101	FILENAME	'12345o  '
+102	AUTHOR
+103	REFERENC	
+104	DATE		'1999-02-05-12:00:53'
+105	ORIGIN		'CFHT    '
+110	IMAGESWV	'12kcom version 1.2'
+111	IMAGEHWV
+	CHECKVER
+	CHECKSUM
+	DATASUM
+100.0	COMMENT                              06 07 08 09 10 11
+100.1	COMMENT  Image Extension for Chip 2  
+100.2	COMMENT  --------------------------  00 01[02]03 04 05
+101.1	EXTNAME		'chip02'
+101.2	EXTVER		2
+101.3	EXTLEVEL	1
+199	INHERIT		F
+200.0	COMMENT
+200.1	COMMENT	Info about Observations
+200.2	COMMENT -----------------------
+201	TIMESYS		'UTC     '
+202	DATE-OBS	'1999-02-05'
+203	UTC-OBS
+204	MJD-OBS
+205	LST-OBS
+210	OBSTYPE
+220	EXPTYPE
+221	EXPTIME
+1000.0	COMMENT
+1000.1	COMMENT  Detector array and CCD Information
+1000.2	COMMENT	 ----------------------------------
+1001	DETECTOR  	'CFH12K'
+1002	DETSIZE   	'[1:12450,1:8230]'
+1003	NCCDS	  	12
+1004	NAMPS		12
+1005	CCDSUM		'2 2'
+1005.1	CCDBIN1		2
+1005.2	CCDBIN2		2
+1006	RASTER
+1010.1	PIXSIZE1
+1010.2	PIXSIZE2
+1011.1	PIXSCAL1
+1011.2	PIXSCAL2
+1101	BZERO		32768
+1102	BSCALE		1
+1103	BUNIT
+1110	BLANK
+1201.n	CTYPEn
+1202.n	CRPIXn
+1202.n	CRVALn
+1203.n	CDELTn
+1204.n	CROTAn
+1205.ioj	CDi_j
+1211.ioj	LIMi_j
+1212.
+
+1301	DATAMAX
+1302	DATAMIN
+
+	OBSERVAT	'CFHT    '
+	TELESCOP	'CFHT 3.6m'
+	TELCONF
+	TELTCS
+	TELFOCUS
+	INSTRUME	'CFH12K Mosaic'
+	OBSERVER
+	OBJECT		
+
+	OBJNAME
+	OBJTYPE
+	OBJRA
+	OBJDEC
+
+	EQUINOX
+	EPOCH		(depr.)
+
+	RADECSYS	'FK5     '
+	RA
+	DEC
+	
+
+	OBSID
+	IMAGEID
+
+	OBSTYPE
+	EXPTIME
+	DARKTIME
+	NSUBEXPS
+	EXPREQ
+	OBSSTAT
+	OBSEQUIN
+	OBSRA
+	OBSDEC
+	
+	AIRMASS
+	AIRMASSn
+	AMMJDn
+	
+	FOCNEXPO
+
+	FOCSTART
+	FOCSTEP
+	FOCSHIFT
+	
+	LAMP
+	LAMPTYPE
+
+NOAO's major groups
+
+Image	BSCALE, NEXTEND, TIMESYS, DATE
+Site	OBSERVAT SEEING WEATHER ENVIRONMENT
+Dome	WIND TEMP
+Telescope TELESCOP TELCONF CHOP AO, etc.
+TV
+Guider
+Adapter
+Observation OBSID, OBJECT FOCNEXPO LAMP
+Object	OBJxxx
+Observer	OBSERVER
+Instrument INSTRUME INSTCONF INSFOCUS
+Detector DETECTOR DETSIZE NCCDS NAMPS PIXSCALi DISPAXIS DISPWC 
+           CCDNAME PIXSIZEi CCDSIZE CCDPSIZE CCDNAMPS AMPSIZE CCDSEC CCDSUM BAISSEC TRIMSEC DATASEC AMPSEC DETSEC
+		CTYPE CRVALi CRPIXi CDi_j 
+Aperture
+Disperser
+Filter	FILTERn FILPOSn
+Camera	CAMERA CAMCONF CAMFOCUS
+Shutter	SHUTSTAT SHUTOPEN SHUTCLOS
+Processing	PROCSTAT PIPELINE
+Archive		ARCHIVE
+
+
+
+	
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry_to_asm.sh
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry_to_asm.sh	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_registry_to_asm.sh	(revision 23490)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+cat - | \
+egrep -e '^MK_(FLT|INT|BLN|STR|VAL)' | \
+sed -e 's/^MK_....[^!-~]*\([0-9][0-9.]*\)[^!-~]*,[^!-~]*\([A-Z0-9_][A-Z0-9_]*\)[^"]*"\(.*\)"[^"]*$/DETCOM_\2 MACRO ARG\
+    COBJ "detcom:dheader \1 \2 \\"\\ARG\\" \\"\3\\""\
+    ENDM/'
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_rt.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_rt.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_rt.c	(revision 23490)
@@ -0,0 +1,47 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`fh_rt.c' - FITS RealTime routines
+
+This file is part of version 1 of the FITS Handling Library.
+Read the `License' file for terms of use and distribution.
+Copyright 2001, Canada-France-Hawaii Telescope, daprog@cfht.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include "fh.h"
+#include "fh_rt.h"
+
+fh_bool
+fh_rt_present(HeaderUnit hu)
+{
+}
+
+fh_bool
+fh_rt_active(HeaderUnit hu)
+{
+   if (fh_rt_present(hu) == FH_FALSE) then return FH_FALSE;
+}
+
+int
+fh_rt_version(HeaderUnit hu)
+{
+   if (fh_rt_active(hu) == FH_FALSE)
+      return ...;
+}
+
+int
+fh_rt_plane_completed(HeaderUnit hu)
+{
+   if (fh_rt_active(hu) == FH_FALSE)
+
+}
+
+int
+fh_rt_plane_latest(HeaderUnit hu)
+{
+}
+
+int
+fh_rt_plane_row_latest(HeaderUnit hu, int plane)
+{
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_rt.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_rt.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_rt.h	(revision 23490)
@@ -0,0 +1,20 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`fh_rt.h' - FITS RealTime routines
+
+This file is part of version 1 of the FITS Handling Library.
+Read the `License' file for terms of use and distribution.
+Copyright 2001, Canada-France-Hawaii Telescope, daprog@cfht.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+#ifndef _INCLUDED_fh_rt
+#define _INCLUDED_fh_rt 1
+
+fh_bool fh_rt_present(HeaderUnit hu);
+fh_bool fh_rt_active(HeaderUnit hu);
+int     fh_rt_version(HeaderUnit hu);
+int     fh_rt_plane_completed(HeaderUnit hu); /* Returns 0..(NAXIS3-1) */
+int     fh_rt_plane_latest(HeaderUnit hu);    /* Returns 0..(NAXIS3-1) */
+int     fh_rt_plane_row_latest(HeaderUnit hu, int plane); /* 0..(NAXIS2-1) */
+
+#endif
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_validate.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_validate.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/fh_validate.c	(revision 23490)
@@ -0,0 +1,233 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`fh_validate.c' - A routine to validate the completeness of header.
+
+This file is part of version 1 of the FITS Handling Library.
+Read the `License' file for terms of use and distribution.
+Copyright 2001, Canada-France-Hawaii Telescope, daprog@cfht.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "fh.h"
+
+fh_result
+fh_validate(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+   fh_result rtn = FH_SUCCESS;
+   int i, xtension=0, naxis=0, bitpix=0;
+   int warned_comment = 0;
+   char* s;
+
+   fh_sort(list);
+
+   for (i=0; i<list->len; i++)
+   {
+      s = list->hdr[i]->card;
+
+      if (fix_characters(s, /*repair=*/1) != FH_SUCCESS)
+      {
+	 if (rtn == FH_SUCCESS) rtn = FH_BAD_VALUE;
+	 fprintf(stderr, "error: libfh: Illegal character(s) in FITS card [%.8s]\n", s);
+      }
+      else
+      {
+	 if (!memcmp(s, "COMMENT ", 8) ||
+	     !memcmp(s, "HISTORY ", 8) ||
+	     !memcmp(s, "        ", 8))
+	 {
+	    if (s[8] == '=')
+	    {
+	       rtn = FH_BAD_VALUE;
+	       if (!warned_comment++)
+		  fprintf(stderr,
+			  "warning: libfh: FITS standard recommends COMMENT/HISTORY not begin with '='\n");
+	    }
+	 }
+	 else
+	 {
+	    if (s[8] == '=')
+	    {
+	       int j;
+	       fh_bool k;
+	       char tmp[80];
+
+	       if (s[9] != ' ')
+	       {
+		  rtn = FH_INVALID;
+		  fprintf(stderr,
+			  "error: libfh: Missing ' ' character after [%.9s]; Not correcting.\n", s);
+	       }
+	       /*
+		* Search for duplicated cards
+		*/
+	       for (j = i-1; j>=0; j--)
+	       {
+		  if (!memcmp(s, list->hdr[j]->card, 8))
+		  {
+		     rtn = FH_INVALID;
+		     fprintf(stderr,
+			     "error: libfh: Line %d:[%.80s] duplicates previous line %d:[%.80s]\n",
+			     i, s, j, list->hdr[j]->card);
+		  }
+	       }
+	       for (j = 10; j < 80; j++)
+		  if (s[j] != ' ') break;
+
+	       if (j < 80) switch (s[j])
+	       {
+		  case '\'': /* Check for fixed format string */
+		  {
+		     if (j != 10 || fh_get_str(list, s, tmp, sizeof(tmp)) != FH_SUCCESS)
+		     {
+			rtn = FH_BAD_VALUE;
+			fprintf(stderr, "warning: libfh: String [%.80s] is not in \"fixed\" format.\n", s);
+		     }
+		     break;
+		  }
+		  case 'T': /* Check for fixed format boolean */
+		  case 'F':
+		  {
+		     if (j != 29 || fh_get_bool(list, s, &k) != FH_SUCCESS)
+		     {
+			rtn = FH_BAD_VALUE;
+			fprintf(stderr, "error: libfh: Boolean [%.8s] is not in \"fixed\" format.\n", s);
+		     }
+		     for (j = 31; j < 80; j++)
+			if (s[j] != ' ') break;
+		     if (j < 80 && s[j] != '/')
+		     {
+			rtn = FH_BAD_VALUE;
+			fprintf(stderr, "error: libfh: Garbage after boolean [%.8s] value field.\n", s);
+		     }
+		     break;
+		  }
+		  case '/': /* No value, only comment field */
+		  {
+		     if (j < 31)
+		     {
+			rtn = FH_BAD_VALUE;
+			fprintf(stderr, "error: libfh: Comment field for [%.8s] begins before column 32\n", s);
+		     }
+		     break;
+		  }
+		  case '(': /* Complex value.  No checking (no fixed format either.) */
+		     break;
+		  default:
+		  {
+		     for (k=j; k < 80; k++) /* Find the end of the value. */
+			if (s[k] == ' ') break;
+		     if ((j > 10 && k != 30) || (k < 30))
+		     {
+			rtn = FH_BAD_VALUE;
+			fprintf(stderr, "error: libfh: Value of [%.8s] is not in \"fixed\" format.\n", s);
+		     }
+		  }
+	       } /* switch (s[j]) */
+	    }
+	    else
+	    {
+	       /*
+		* The '=' sign is missing, so this should be treated as a comment
+		* line.  However, since we do not use any other comment cards
+		* in our files other than COMMENT HISTORY or "        ", this is
+		* probably an error.
+		*/
+	       rtn = FH_INVALID;
+	       fprintf(stderr,
+		       "warning: libfh: Treating [%.8s] as a comment card (No '=' in column 9)\n", s);
+	    }
+	 }
+
+	 switch (i)
+	 {
+	    case 0: /* must be SIMPLE T or XTENSION */
+	    {
+	       if (!memcmp(s, "XTENSION", 8))
+		  xtension=1;
+	       else
+	       {
+		  if (memcmp(s, "SIMPLE  =                    T ", 31))
+		  {
+		     rtn = FH_INVALID;
+		     fprintf(stderr, "error: libfh: First card is not \"SIMPLE  = ... T\"\n");
+		  }
+	       }
+	       break;
+	    }
+            case 1: /* must be BITPIX */
+	    {
+	       if (memcmp(s, "BITPIX  ", 8) || fh_get_int(list, "BITPIX", &bitpix) != FH_SUCCESS)
+	       {
+		  rtn = FH_INVALID;
+		  fprintf(stderr, "error: libfh: Second card is not \"BITPIX  = \"\n");
+		  bitpix = 0;
+	       }
+	       else switch (bitpix)
+	       {
+		  case 8:
+		  case 16:
+		  case 32:
+		  case -32:
+		  case -64: break; /* Valid */
+		  case 0: if (xtension) break;
+		  default:
+		  {
+		     rtn = FH_INVALID;
+		     fprintf(stderr, "error: libfh: Non-standard BITPIX: %d\n", bitpix);
+		  }
+	       }
+	       break;
+	    }
+	    case 2: /* must be NAXIS */
+	    {
+	       if (memcmp(s, "NAXIS   ", 8) || fh_get_int(list, "NAXIS", &naxis) != FH_SUCCESS)
+	       {
+		  rtn = FH_INVALID;
+		  fprintf(stderr, "error: libfh: Third card is not \"NAXIS   = \"\n");
+	       }
+	       break;
+	    }
+            default: /* NAXIS??? must be next, then PCOUNT, GCOUNT if XTENSION */
+	    {
+	       if (i <= naxis + 2)
+	       {
+		  char name[9] = "        ";
+		  
+		  sprintf(name, "NAXIS%d", i - 2);
+		  if (fh_cmp(s, name) < MATCH_KEYWORD)
+		  {
+		     rtn = FH_INVALID;
+		     fprintf(stderr, "error: libfh: Found [%.8s] instead of [%s].\n",
+			     s, name);
+		  }
+	       }
+	       else if (xtension && i == naxis + 2 + 1)
+	       {
+		  if (memcmp(s, "PCOUNT  ", 8))
+		  {
+		     rtn = FH_INVALID;
+		     fprintf(stderr,
+			     "error: libfh: Extension has [%.8s] where PCOUNT should be.\n",
+			     s);
+		  }
+	       }
+	       else if (xtension && i == naxis + 2 + 2)
+	       {
+		  if (memcmp(s, "GCOUNT  ", 8))
+		  {
+		     rtn = FH_INVALID;
+		     fprintf(stderr, "error: libfh: Extension has [%.8s] where GCOUNT should be.\n",
+			     s);
+		  }
+	       }
+	    }
+	 }
+      }
+   }
+
+   return rtn;
+}
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.c	(revision 23490)
@@ -0,0 +1,2 @@
+#include "../fh.h"
+#include "../fh_registry.h"
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.log
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.log	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.log	(revision 23490)
@@ -0,0 +1,2345 @@
+../fh_registry.h:203: warning: `fh_set_SIMPLE' defined but not used
+../fh_registry.h:203: warning: `fh_setval_SIMPLE' defined but not used
+../fh_registry.h:203: warning: `fh_setcmt_SIMPLE' defined but not used
+../fh_registry.h:203: warning: `fh_get_SIMPLE' defined but not used
+../fh_registry.h:203: warning: `fh_kw_SIMPLE' defined but not used
+../fh_registry.h:203: warning: `fh_cmt_SIMPLE' defined but not used
+../fh_registry.h:204: warning: `fh_set_XTENSION' defined but not used
+../fh_registry.h:204: warning: `fh_setval_XTENSION' defined but not used
+../fh_registry.h:204: warning: `fh_setcmt_XTENSION' defined but not used
+../fh_registry.h:204: warning: `fh_get_XTENSION' defined but not used
+../fh_registry.h:204: warning: `fh_kw_XTENSION' defined but not used
+../fh_registry.h:204: warning: `fh_cmt_XTENSION' defined but not used
+../fh_registry.h:205: warning: `fh_set_BITPIX' defined but not used
+../fh_registry.h:205: warning: `fh_setval_BITPIX' defined but not used
+../fh_registry.h:205: warning: `fh_setcmt_BITPIX' defined but not used
+../fh_registry.h:205: warning: `fh_get_BITPIX' defined but not used
+../fh_registry.h:205: warning: `fh_kw_BITPIX' defined but not used
+../fh_registry.h:205: warning: `fh_cmt_BITPIX' defined but not used
+../fh_registry.h:206: warning: `fh_set_NAXIS' defined but not used
+../fh_registry.h:206: warning: `fh_setval_NAXIS' defined but not used
+../fh_registry.h:206: warning: `fh_setcmt_NAXIS' defined but not used
+../fh_registry.h:206: warning: `fh_get_NAXIS' defined but not used
+../fh_registry.h:206: warning: `fh_kw_NAXIS' defined but not used
+../fh_registry.h:206: warning: `fh_cmt_NAXIS' defined but not used
+../fh_registry.h:207: warning: `fh_set_NAXIS1' defined but not used
+../fh_registry.h:207: warning: `fh_setval_NAXIS1' defined but not used
+../fh_registry.h:207: warning: `fh_setcmt_NAXIS1' defined but not used
+../fh_registry.h:207: warning: `fh_get_NAXIS1' defined but not used
+../fh_registry.h:207: warning: `fh_kw_NAXIS1' defined but not used
+../fh_registry.h:207: warning: `fh_cmt_NAXIS1' defined but not used
+../fh_registry.h:208: warning: `fh_set_NAXIS2' defined but not used
+../fh_registry.h:208: warning: `fh_setval_NAXIS2' defined but not used
+../fh_registry.h:208: warning: `fh_setcmt_NAXIS2' defined but not used
+../fh_registry.h:208: warning: `fh_get_NAXIS2' defined but not used
+../fh_registry.h:208: warning: `fh_kw_NAXIS2' defined but not used
+../fh_registry.h:208: warning: `fh_cmt_NAXIS2' defined but not used
+../fh_registry.h:209: warning: `fh_set_NAXIS3' defined but not used
+../fh_registry.h:209: warning: `fh_setval_NAXIS3' defined but not used
+../fh_registry.h:209: warning: `fh_setcmt_NAXIS3' defined but not used
+../fh_registry.h:209: warning: `fh_get_NAXIS3' defined but not used
+../fh_registry.h:209: warning: `fh_kw_NAXIS3' defined but not used
+../fh_registry.h:209: warning: `fh_cmt_NAXIS3' defined but not used
+../fh_registry.h:210: warning: `fh_set_EXTEND' defined but not used
+../fh_registry.h:210: warning: `fh_setval_EXTEND' defined but not used
+../fh_registry.h:210: warning: `fh_setcmt_EXTEND' defined but not used
+../fh_registry.h:210: warning: `fh_get_EXTEND' defined but not used
+../fh_registry.h:210: warning: `fh_kw_EXTEND' defined but not used
+../fh_registry.h:210: warning: `fh_cmt_EXTEND' defined but not used
+../fh_registry.h:211: warning: `fh_set_NEXTEND' defined but not used
+../fh_registry.h:211: warning: `fh_setval_NEXTEND' defined but not used
+../fh_registry.h:211: warning: `fh_setcmt_NEXTEND' defined but not used
+../fh_registry.h:211: warning: `fh_get_NEXTEND' defined but not used
+../fh_registry.h:211: warning: `fh_kw_NEXTEND' defined but not used
+../fh_registry.h:211: warning: `fh_cmt_NEXTEND' defined but not used
+../fh_registry.h:212: warning: `fh_set_GROUPS' defined but not used
+../fh_registry.h:212: warning: `fh_setval_GROUPS' defined but not used
+../fh_registry.h:212: warning: `fh_setcmt_GROUPS' defined but not used
+../fh_registry.h:212: warning: `fh_get_GROUPS' defined but not used
+../fh_registry.h:212: warning: `fh_kw_GROUPS' defined but not used
+../fh_registry.h:212: warning: `fh_cmt_GROUPS' defined but not used
+../fh_registry.h:213: warning: `fh_set_PCOUNT' defined but not used
+../fh_registry.h:213: warning: `fh_setval_PCOUNT' defined but not used
+../fh_registry.h:213: warning: `fh_setcmt_PCOUNT' defined but not used
+../fh_registry.h:213: warning: `fh_get_PCOUNT' defined but not used
+../fh_registry.h:213: warning: `fh_kw_PCOUNT' defined but not used
+../fh_registry.h:213: warning: `fh_cmt_PCOUNT' defined but not used
+../fh_registry.h:214: warning: `fh_set_GCOUNT' defined but not used
+../fh_registry.h:214: warning: `fh_setval_GCOUNT' defined but not used
+../fh_registry.h:214: warning: `fh_setcmt_GCOUNT' defined but not used
+../fh_registry.h:214: warning: `fh_get_GCOUNT' defined but not used
+../fh_registry.h:214: warning: `fh_kw_GCOUNT' defined but not used
+../fh_registry.h:214: warning: `fh_cmt_GCOUNT' defined but not used
+../fh_registry.h:215: warning: `fh_set_TFIELDS' defined but not used
+../fh_registry.h:215: warning: `fh_setval_TFIELDS' defined but not used
+../fh_registry.h:215: warning: `fh_setcmt_TFIELDS' defined but not used
+../fh_registry.h:215: warning: `fh_get_TFIELDS' defined but not used
+../fh_registry.h:215: warning: `fh_kw_TFIELDS' defined but not used
+../fh_registry.h:215: warning: `fh_cmt_TFIELDS' defined but not used
+../fh_registry.h:216: warning: `fh_set_TFORM1' defined but not used
+../fh_registry.h:216: warning: `fh_setval_TFORM1' defined but not used
+../fh_registry.h:216: warning: `fh_setcmt_TFORM1' defined but not used
+../fh_registry.h:216: warning: `fh_get_TFORM1' defined but not used
+../fh_registry.h:216: warning: `fh_kw_TFORM1' defined but not used
+../fh_registry.h:216: warning: `fh_cmt_TFORM1' defined but not used
+../fh_registry.h:217: warning: `fh_set_TBCOL1' defined but not used
+../fh_registry.h:217: warning: `fh_setval_TBCOL1' defined but not used
+../fh_registry.h:217: warning: `fh_setcmt_TBCOL1' defined but not used
+../fh_registry.h:217: warning: `fh_get_TBCOL1' defined but not used
+../fh_registry.h:217: warning: `fh_kw_TBCOL1' defined but not used
+../fh_registry.h:217: warning: `fh_cmt_TBCOL1' defined but not used
+../fh_registry.h:218: warning: `fh_set_TFORM2' defined but not used
+../fh_registry.h:218: warning: `fh_setval_TFORM2' defined but not used
+../fh_registry.h:218: warning: `fh_setcmt_TFORM2' defined but not used
+../fh_registry.h:218: warning: `fh_get_TFORM2' defined but not used
+../fh_registry.h:218: warning: `fh_kw_TFORM2' defined but not used
+../fh_registry.h:218: warning: `fh_cmt_TFORM2' defined but not used
+../fh_registry.h:219: warning: `fh_set_TBCOL2' defined but not used
+../fh_registry.h:219: warning: `fh_setval_TBCOL2' defined but not used
+../fh_registry.h:219: warning: `fh_setcmt_TBCOL2' defined but not used
+../fh_registry.h:219: warning: `fh_get_TBCOL2' defined but not used
+../fh_registry.h:219: warning: `fh_kw_TBCOL2' defined but not used
+../fh_registry.h:219: warning: `fh_cmt_TBCOL2' defined but not used
+../fh_registry.h:220: warning: `fh_set_TFORM3' defined but not used
+../fh_registry.h:220: warning: `fh_setval_TFORM3' defined but not used
+../fh_registry.h:220: warning: `fh_setcmt_TFORM3' defined but not used
+../fh_registry.h:220: warning: `fh_get_TFORM3' defined but not used
+../fh_registry.h:220: warning: `fh_kw_TFORM3' defined but not used
+../fh_registry.h:220: warning: `fh_cmt_TFORM3' defined but not used
+../fh_registry.h:221: warning: `fh_set_TBCOL3' defined but not used
+../fh_registry.h:221: warning: `fh_setval_TBCOL3' defined but not used
+../fh_registry.h:221: warning: `fh_setcmt_TBCOL3' defined but not used
+../fh_registry.h:221: warning: `fh_get_TBCOL3' defined but not used
+../fh_registry.h:221: warning: `fh_kw_TBCOL3' defined but not used
+../fh_registry.h:221: warning: `fh_cmt_TBCOL3' defined but not used
+../fh_registry.h:222: warning: `fh_set_TFORM4' defined but not used
+../fh_registry.h:222: warning: `fh_setval_TFORM4' defined but not used
+../fh_registry.h:222: warning: `fh_setcmt_TFORM4' defined but not used
+../fh_registry.h:222: warning: `fh_get_TFORM4' defined but not used
+../fh_registry.h:222: warning: `fh_kw_TFORM4' defined but not used
+../fh_registry.h:222: warning: `fh_cmt_TFORM4' defined but not used
+../fh_registry.h:223: warning: `fh_set_TBCOL4' defined but not used
+../fh_registry.h:223: warning: `fh_setval_TBCOL4' defined but not used
+../fh_registry.h:223: warning: `fh_setcmt_TBCOL4' defined but not used
+../fh_registry.h:223: warning: `fh_get_TBCOL4' defined but not used
+../fh_registry.h:223: warning: `fh_kw_TBCOL4' defined but not used
+../fh_registry.h:223: warning: `fh_cmt_TBCOL4' defined but not used
+../fh_registry.h:224: warning: `fh_set_TFORM5' defined but not used
+../fh_registry.h:224: warning: `fh_setval_TFORM5' defined but not used
+../fh_registry.h:224: warning: `fh_setcmt_TFORM5' defined but not used
+../fh_registry.h:224: warning: `fh_get_TFORM5' defined but not used
+../fh_registry.h:224: warning: `fh_kw_TFORM5' defined but not used
+../fh_registry.h:224: warning: `fh_cmt_TFORM5' defined but not used
+../fh_registry.h:225: warning: `fh_set_TBCOL5' defined but not used
+../fh_registry.h:225: warning: `fh_setval_TBCOL5' defined but not used
+../fh_registry.h:225: warning: `fh_setcmt_TBCOL5' defined but not used
+../fh_registry.h:225: warning: `fh_get_TBCOL5' defined but not used
+../fh_registry.h:225: warning: `fh_kw_TBCOL5' defined but not used
+../fh_registry.h:225: warning: `fh_cmt_TBCOL5' defined but not used
+../fh_registry.h:226: warning: `fh_set_BZERO' defined but not used
+../fh_registry.h:226: warning: `fh_setval_BZERO' defined but not used
+../fh_registry.h:226: warning: `fh_setcmt_BZERO' defined but not used
+../fh_registry.h:226: warning: `fh_get_BZERO' defined but not used
+../fh_registry.h:226: warning: `fh_kw_BZERO' defined but not used
+../fh_registry.h:226: warning: `fh_cmt_BZERO' defined but not used
+../fh_registry.h:227: warning: `fh_set_BSCALE' defined but not used
+../fh_registry.h:227: warning: `fh_setval_BSCALE' defined but not used
+../fh_registry.h:227: warning: `fh_setcmt_BSCALE' defined but not used
+../fh_registry.h:227: warning: `fh_get_BSCALE' defined but not used
+../fh_registry.h:227: warning: `fh_kw_BSCALE' defined but not used
+../fh_registry.h:227: warning: `fh_cmt_BSCALE' defined but not used
+../fh_registry.h:233: warning: `fh_set_CMTSUM1' defined but not used
+../fh_registry.h:234: warning: `fh_set_CMTSUM2' defined but not used
+../fh_registry.h:235: warning: `fh_set_CMTSUM3' defined but not used
+../fh_registry.h:236: warning: `fh_set_CMTSUM4' defined but not used
+../fh_registry.h:237: warning: `fh_set_CMTSUM5' defined but not used
+../fh_registry.h:238: warning: `fh_set_CMMTOBS' defined but not used
+../fh_registry.h:238: warning: `fh_setval_CMMTOBS' defined but not used
+../fh_registry.h:238: warning: `fh_setcmt_CMMTOBS' defined but not used
+../fh_registry.h:238: warning: `fh_get_CMMTOBS' defined but not used
+../fh_registry.h:238: warning: `fh_kw_CMMTOBS' defined but not used
+../fh_registry.h:238: warning: `fh_cmt_CMMTOBS' defined but not used
+../fh_registry.h:239: warning: `fh_set_CMMTSEQ' defined but not used
+../fh_registry.h:239: warning: `fh_setval_CMMTSEQ' defined but not used
+../fh_registry.h:239: warning: `fh_setcmt_CMMTSEQ' defined but not used
+../fh_registry.h:239: warning: `fh_get_CMMTSEQ' defined but not used
+../fh_registry.h:239: warning: `fh_kw_CMMTSEQ' defined but not used
+../fh_registry.h:239: warning: `fh_cmt_CMMTSEQ' defined but not used
+../fh_registry.h:240: warning: `fh_set_OBJECT' defined but not used
+../fh_registry.h:240: warning: `fh_setval_OBJECT' defined but not used
+../fh_registry.h:240: warning: `fh_setcmt_OBJECT' defined but not used
+../fh_registry.h:240: warning: `fh_get_OBJECT' defined but not used
+../fh_registry.h:240: warning: `fh_kw_OBJECT' defined but not used
+../fh_registry.h:240: warning: `fh_cmt_OBJECT' defined but not used
+../fh_registry.h:241: warning: `fh_set_OBSERVER' defined but not used
+../fh_registry.h:241: warning: `fh_setval_OBSERVER' defined but not used
+../fh_registry.h:241: warning: `fh_setcmt_OBSERVER' defined but not used
+../fh_registry.h:241: warning: `fh_get_OBSERVER' defined but not used
+../fh_registry.h:241: warning: `fh_kw_OBSERVER' defined but not used
+../fh_registry.h:241: warning: `fh_cmt_OBSERVER' defined but not used
+../fh_registry.h:242: warning: `fh_set_PI_NAME' defined but not used
+../fh_registry.h:242: warning: `fh_setval_PI_NAME' defined but not used
+../fh_registry.h:242: warning: `fh_setcmt_PI_NAME' defined but not used
+../fh_registry.h:242: warning: `fh_get_PI_NAME' defined but not used
+../fh_registry.h:242: warning: `fh_kw_PI_NAME' defined but not used
+../fh_registry.h:242: warning: `fh_cmt_PI_NAME' defined but not used
+../fh_registry.h:243: warning: `fh_set_RUNID' defined but not used
+../fh_registry.h:243: warning: `fh_setval_RUNID' defined but not used
+../fh_registry.h:243: warning: `fh_setcmt_RUNID' defined but not used
+../fh_registry.h:243: warning: `fh_get_RUNID' defined but not used
+../fh_registry.h:243: warning: `fh_kw_RUNID' defined but not used
+../fh_registry.h:243: warning: `fh_cmt_RUNID' defined but not used
+../fh_registry.h:249: warning: `fh_set_CMTGEN1' defined but not used
+../fh_registry.h:250: warning: `fh_set_CMTGEN2' defined but not used
+../fh_registry.h:251: warning: `fh_set_CMTGEN3' defined but not used
+../fh_registry.h:252: warning: `fh_set_CMTGEN4' defined but not used
+../fh_registry.h:253: warning: `fh_set_FILENAME' defined but not used
+../fh_registry.h:253: warning: `fh_setval_FILENAME' defined but not used
+../fh_registry.h:253: warning: `fh_setcmt_FILENAME' defined but not used
+../fh_registry.h:253: warning: `fh_get_FILENAME' defined but not used
+../fh_registry.h:253: warning: `fh_kw_FILENAME' defined but not used
+../fh_registry.h:253: warning: `fh_cmt_FILENAME' defined but not used
+../fh_registry.h:254: warning: `fh_set_PATHNAME' defined but not used
+../fh_registry.h:254: warning: `fh_setval_PATHNAME' defined but not used
+../fh_registry.h:254: warning: `fh_setcmt_PATHNAME' defined but not used
+../fh_registry.h:254: warning: `fh_get_PATHNAME' defined but not used
+../fh_registry.h:254: warning: `fh_kw_PATHNAME' defined but not used
+../fh_registry.h:254: warning: `fh_cmt_PATHNAME' defined but not used
+../fh_registry.h:255: warning: `fh_set_EXTNAME' defined but not used
+../fh_registry.h:255: warning: `fh_setval_EXTNAME' defined but not used
+../fh_registry.h:255: warning: `fh_setcmt_EXTNAME' defined but not used
+../fh_registry.h:255: warning: `fh_get_EXTNAME' defined but not used
+../fh_registry.h:255: warning: `fh_kw_EXTNAME' defined but not used
+../fh_registry.h:255: warning: `fh_cmt_EXTNAME' defined but not used
+../fh_registry.h:256: warning: `fh_set_EXTVER' defined but not used
+../fh_registry.h:256: warning: `fh_setval_EXTVER' defined but not used
+../fh_registry.h:256: warning: `fh_setcmt_EXTVER' defined but not used
+../fh_registry.h:256: warning: `fh_get_EXTVER' defined but not used
+../fh_registry.h:256: warning: `fh_kw_EXTVER' defined but not used
+../fh_registry.h:256: warning: `fh_cmt_EXTVER' defined but not used
+../fh_registry.h:257: warning: `fh_set_DATE' defined but not used
+../fh_registry.h:257: warning: `fh_setval_DATE' defined but not used
+../fh_registry.h:257: warning: `fh_setcmt_DATE' defined but not used
+../fh_registry.h:257: warning: `fh_get_DATE' defined but not used
+../fh_registry.h:257: warning: `fh_kw_DATE' defined but not used
+../fh_registry.h:257: warning: `fh_cmt_DATE' defined but not used
+../fh_registry.h:258: warning: `fh_set_HSTTIME' defined but not used
+../fh_registry.h:258: warning: `fh_setval_HSTTIME' defined but not used
+../fh_registry.h:258: warning: `fh_setcmt_HSTTIME' defined but not used
+../fh_registry.h:258: warning: `fh_get_HSTTIME' defined but not used
+../fh_registry.h:258: warning: `fh_kw_HSTTIME' defined but not used
+../fh_registry.h:258: warning: `fh_cmt_HSTTIME' defined but not used
+../fh_registry.h:259: warning: `fh_set_IMAGESWV' defined but not used
+../fh_registry.h:259: warning: `fh_setval_IMAGESWV' defined but not used
+../fh_registry.h:259: warning: `fh_setcmt_IMAGESWV' defined but not used
+../fh_registry.h:259: warning: `fh_get_IMAGESWV' defined but not used
+../fh_registry.h:259: warning: `fh_kw_IMAGESWV' defined but not used
+../fh_registry.h:259: warning: `fh_cmt_IMAGESWV' defined but not used
+../fh_registry.h:264: warning: `fh_set_DETECTOR' defined but not used
+../fh_registry.h:264: warning: `fh_setval_DETECTOR' defined but not used
+../fh_registry.h:264: warning: `fh_setcmt_DETECTOR' defined but not used
+../fh_registry.h:264: warning: `fh_get_DETECTOR' defined but not used
+../fh_registry.h:264: warning: `fh_kw_DETECTOR' defined but not used
+../fh_registry.h:264: warning: `fh_cmt_DETECTOR' defined but not used
+../fh_registry.h:265: warning: `fh_set_INSTRUME' defined but not used
+../fh_registry.h:265: warning: `fh_setval_INSTRUME' defined but not used
+../fh_registry.h:265: warning: `fh_setcmt_INSTRUME' defined but not used
+../fh_registry.h:265: warning: `fh_get_INSTRUME' defined but not used
+../fh_registry.h:265: warning: `fh_kw_INSTRUME' defined but not used
+../fh_registry.h:265: warning: `fh_cmt_INSTRUME' defined but not used
+../fh_registry.h:266: warning: `fh_set_INSTMODE' defined but not used
+../fh_registry.h:266: warning: `fh_setval_INSTMODE' defined but not used
+../fh_registry.h:266: warning: `fh_setcmt_INSTMODE' defined but not used
+../fh_registry.h:266: warning: `fh_get_INSTMODE' defined but not used
+../fh_registry.h:266: warning: `fh_kw_INSTMODE' defined but not used
+../fh_registry.h:266: warning: `fh_cmt_INSTMODE' defined but not used
+../fh_registry.h:272: warning: `fh_set_CMTDET1' defined but not used
+../fh_registry.h:273: warning: `fh_set_CMTDET2' defined but not used
+../fh_registry.h:274: warning: `fh_set_CMTDET3' defined but not used
+../fh_registry.h:275: warning: `fh_set_CMTDET4' defined but not used
+../fh_registry.h:276: warning: `fh_set_DETSIZE' defined but not used
+../fh_registry.h:276: warning: `fh_setval_DETSIZE' defined but not used
+../fh_registry.h:276: warning: `fh_setcmt_DETSIZE' defined but not used
+../fh_registry.h:276: warning: `fh_get_DETSIZE' defined but not used
+../fh_registry.h:276: warning: `fh_kw_DETSIZE' defined but not used
+../fh_registry.h:276: warning: `fh_cmt_DETSIZE' defined but not used
+../fh_registry.h:277: warning: `fh_set_RASTER' defined but not used
+../fh_registry.h:277: warning: `fh_setval_RASTER' defined but not used
+../fh_registry.h:277: warning: `fh_setcmt_RASTER' defined but not used
+../fh_registry.h:277: warning: `fh_get_RASTER' defined but not used
+../fh_registry.h:277: warning: `fh_kw_RASTER' defined but not used
+../fh_registry.h:277: warning: `fh_cmt_RASTER' defined but not used
+../fh_registry.h:278: warning: `fh_set_CCDSUM' defined but not used
+../fh_registry.h:278: warning: `fh_setval_CCDSUM' defined but not used
+../fh_registry.h:278: warning: `fh_setcmt_CCDSUM' defined but not used
+../fh_registry.h:278: warning: `fh_get_CCDSUM' defined but not used
+../fh_registry.h:278: warning: `fh_kw_CCDSUM' defined but not used
+../fh_registry.h:278: warning: `fh_cmt_CCDSUM' defined but not used
+../fh_registry.h:279: warning: `fh_set_CCDBIN1' defined but not used
+../fh_registry.h:279: warning: `fh_setval_CCDBIN1' defined but not used
+../fh_registry.h:279: warning: `fh_setcmt_CCDBIN1' defined but not used
+../fh_registry.h:279: warning: `fh_get_CCDBIN1' defined but not used
+../fh_registry.h:279: warning: `fh_kw_CCDBIN1' defined but not used
+../fh_registry.h:279: warning: `fh_cmt_CCDBIN1' defined but not used
+../fh_registry.h:280: warning: `fh_set_CCDBIN2' defined but not used
+../fh_registry.h:280: warning: `fh_setval_CCDBIN2' defined but not used
+../fh_registry.h:280: warning: `fh_setcmt_CCDBIN2' defined but not used
+../fh_registry.h:280: warning: `fh_get_CCDBIN2' defined but not used
+../fh_registry.h:280: warning: `fh_kw_CCDBIN2' defined but not used
+../fh_registry.h:280: warning: `fh_cmt_CCDBIN2' defined but not used
+../fh_registry.h:281: warning: `fh_set_PIXSIZE' defined but not used
+../fh_registry.h:281: warning: `fh_setval_PIXSIZE' defined but not used
+../fh_registry.h:281: warning: `fh_setcmt_PIXSIZE' defined but not used
+../fh_registry.h:281: warning: `fh_get_PIXSIZE' defined but not used
+../fh_registry.h:281: warning: `fh_kw_PIXSIZE' defined but not used
+../fh_registry.h:281: warning: `fh_cmt_PIXSIZE' defined but not used
+../fh_registry.h:282: warning: `fh_set_PIXSIZE1' defined but not used
+../fh_registry.h:282: warning: `fh_setval_PIXSIZE1' defined but not used
+../fh_registry.h:282: warning: `fh_setcmt_PIXSIZE1' defined but not used
+../fh_registry.h:282: warning: `fh_get_PIXSIZE1' defined but not used
+../fh_registry.h:282: warning: `fh_kw_PIXSIZE1' defined but not used
+../fh_registry.h:282: warning: `fh_cmt_PIXSIZE1' defined but not used
+../fh_registry.h:283: warning: `fh_set_PIXSIZE2' defined but not used
+../fh_registry.h:283: warning: `fh_setval_PIXSIZE2' defined but not used
+../fh_registry.h:283: warning: `fh_setcmt_PIXSIZE2' defined but not used
+../fh_registry.h:283: warning: `fh_get_PIXSIZE2' defined but not used
+../fh_registry.h:283: warning: `fh_kw_PIXSIZE2' defined but not used
+../fh_registry.h:283: warning: `fh_cmt_PIXSIZE2' defined but not used
+../fh_registry.h:284: warning: `fh_set_PIXSCAL1' defined but not used
+../fh_registry.h:284: warning: `fh_setval_PIXSCAL1' defined but not used
+../fh_registry.h:284: warning: `fh_setcmt_PIXSCAL1' defined but not used
+../fh_registry.h:284: warning: `fh_get_PIXSCAL1' defined but not used
+../fh_registry.h:284: warning: `fh_kw_PIXSCAL1' defined but not used
+../fh_registry.h:284: warning: `fh_cmt_PIXSCAL1' defined but not used
+../fh_registry.h:285: warning: `fh_set_PIXSCAL2' defined but not used
+../fh_registry.h:285: warning: `fh_setval_PIXSCAL2' defined but not used
+../fh_registry.h:285: warning: `fh_setcmt_PIXSCAL2' defined but not used
+../fh_registry.h:285: warning: `fh_get_PIXSCAL2' defined but not used
+../fh_registry.h:285: warning: `fh_kw_PIXSCAL2' defined but not used
+../fh_registry.h:285: warning: `fh_cmt_PIXSCAL2' defined but not used
+../fh_registry.h:286: warning: `fh_set_AMPLIST' defined but not used
+../fh_registry.h:286: warning: `fh_setval_AMPLIST' defined but not used
+../fh_registry.h:286: warning: `fh_setcmt_AMPLIST' defined but not used
+../fh_registry.h:286: warning: `fh_get_AMPLIST' defined but not used
+../fh_registry.h:286: warning: `fh_kw_AMPLIST' defined but not used
+../fh_registry.h:286: warning: `fh_cmt_AMPLIST' defined but not used
+../fh_registry.h:287: warning: `fh_set_AMPNAME' defined but not used
+../fh_registry.h:287: warning: `fh_setval_AMPNAME' defined but not used
+../fh_registry.h:287: warning: `fh_setcmt_AMPNAME' defined but not used
+../fh_registry.h:287: warning: `fh_get_AMPNAME' defined but not used
+../fh_registry.h:287: warning: `fh_kw_AMPNAME' defined but not used
+../fh_registry.h:287: warning: `fh_cmt_AMPNAME' defined but not used
+../fh_registry.h:288: warning: `fh_set_CCDSIZE' defined but not used
+../fh_registry.h:288: warning: `fh_setval_CCDSIZE' defined but not used
+../fh_registry.h:288: warning: `fh_setcmt_CCDSIZE' defined but not used
+../fh_registry.h:288: warning: `fh_get_CCDSIZE' defined but not used
+../fh_registry.h:288: warning: `fh_kw_CCDSIZE' defined but not used
+../fh_registry.h:288: warning: `fh_cmt_CCDSIZE' defined but not used
+../fh_registry.h:289: warning: `fh_set_DETSEC' defined but not used
+../fh_registry.h:289: warning: `fh_setval_DETSEC' defined but not used
+../fh_registry.h:289: warning: `fh_setcmt_DETSEC' defined but not used
+../fh_registry.h:289: warning: `fh_get_DETSEC' defined but not used
+../fh_registry.h:289: warning: `fh_kw_DETSEC' defined but not used
+../fh_registry.h:289: warning: `fh_cmt_DETSEC' defined but not used
+../fh_registry.h:290: warning: `fh_set_DETSECA' defined but not used
+../fh_registry.h:290: warning: `fh_setval_DETSECA' defined but not used
+../fh_registry.h:290: warning: `fh_setcmt_DETSECA' defined but not used
+../fh_registry.h:290: warning: `fh_get_DETSECA' defined but not used
+../fh_registry.h:290: warning: `fh_kw_DETSECA' defined but not used
+../fh_registry.h:290: warning: `fh_cmt_DETSECA' defined but not used
+../fh_registry.h:291: warning: `fh_set_DETSECB' defined but not used
+../fh_registry.h:291: warning: `fh_setval_DETSECB' defined but not used
+../fh_registry.h:291: warning: `fh_setcmt_DETSECB' defined but not used
+../fh_registry.h:291: warning: `fh_get_DETSECB' defined but not used
+../fh_registry.h:291: warning: `fh_kw_DETSECB' defined but not used
+../fh_registry.h:291: warning: `fh_cmt_DETSECB' defined but not used
+../fh_registry.h:292: warning: `fh_set_DETSECC' defined but not used
+../fh_registry.h:292: warning: `fh_setval_DETSECC' defined but not used
+../fh_registry.h:292: warning: `fh_setcmt_DETSECC' defined but not used
+../fh_registry.h:292: warning: `fh_get_DETSECC' defined but not used
+../fh_registry.h:292: warning: `fh_kw_DETSECC' defined but not used
+../fh_registry.h:292: warning: `fh_cmt_DETSECC' defined but not used
+../fh_registry.h:293: warning: `fh_set_DETSECD' defined but not used
+../fh_registry.h:293: warning: `fh_setval_DETSECD' defined but not used
+../fh_registry.h:293: warning: `fh_setcmt_DETSECD' defined but not used
+../fh_registry.h:293: warning: `fh_get_DETSECD' defined but not used
+../fh_registry.h:293: warning: `fh_kw_DETSECD' defined but not used
+../fh_registry.h:293: warning: `fh_cmt_DETSECD' defined but not used
+../fh_registry.h:294: warning: `fh_set_DATASEC' defined but not used
+../fh_registry.h:294: warning: `fh_setval_DATASEC' defined but not used
+../fh_registry.h:294: warning: `fh_setcmt_DATASEC' defined but not used
+../fh_registry.h:294: warning: `fh_get_DATASEC' defined but not used
+../fh_registry.h:294: warning: `fh_kw_DATASEC' defined but not used
+../fh_registry.h:294: warning: `fh_cmt_DATASEC' defined but not used
+../fh_registry.h:295: warning: `fh_set_BIASSEC' defined but not used
+../fh_registry.h:295: warning: `fh_setval_BIASSEC' defined but not used
+../fh_registry.h:295: warning: `fh_setcmt_BIASSEC' defined but not used
+../fh_registry.h:295: warning: `fh_get_BIASSEC' defined but not used
+../fh_registry.h:295: warning: `fh_kw_BIASSEC' defined but not used
+../fh_registry.h:295: warning: `fh_cmt_BIASSEC' defined but not used
+../fh_registry.h:296: warning: `fh_set_ASECA' defined but not used
+../fh_registry.h:296: warning: `fh_setval_ASECA' defined but not used
+../fh_registry.h:296: warning: `fh_setcmt_ASECA' defined but not used
+../fh_registry.h:296: warning: `fh_get_ASECA' defined but not used
+../fh_registry.h:296: warning: `fh_kw_ASECA' defined but not used
+../fh_registry.h:296: warning: `fh_cmt_ASECA' defined but not used
+../fh_registry.h:297: warning: `fh_set_ASECB' defined but not used
+../fh_registry.h:297: warning: `fh_setval_ASECB' defined but not used
+../fh_registry.h:297: warning: `fh_setcmt_ASECB' defined but not used
+../fh_registry.h:297: warning: `fh_get_ASECB' defined but not used
+../fh_registry.h:297: warning: `fh_kw_ASECB' defined but not used
+../fh_registry.h:297: warning: `fh_cmt_ASECB' defined but not used
+../fh_registry.h:298: warning: `fh_set_ASECC' defined but not used
+../fh_registry.h:298: warning: `fh_setval_ASECC' defined but not used
+../fh_registry.h:298: warning: `fh_setcmt_ASECC' defined but not used
+../fh_registry.h:298: warning: `fh_get_ASECC' defined but not used
+../fh_registry.h:298: warning: `fh_kw_ASECC' defined but not used
+../fh_registry.h:298: warning: `fh_cmt_ASECC' defined but not used
+../fh_registry.h:299: warning: `fh_set_ASECD' defined but not used
+../fh_registry.h:299: warning: `fh_setval_ASECD' defined but not used
+../fh_registry.h:299: warning: `fh_setcmt_ASECD' defined but not used
+../fh_registry.h:299: warning: `fh_get_ASECD' defined but not used
+../fh_registry.h:299: warning: `fh_kw_ASECD' defined but not used
+../fh_registry.h:299: warning: `fh_cmt_ASECD' defined but not used
+../fh_registry.h:300: warning: `fh_set_BSECA' defined but not used
+../fh_registry.h:300: warning: `fh_setval_BSECA' defined but not used
+../fh_registry.h:300: warning: `fh_setcmt_BSECA' defined but not used
+../fh_registry.h:300: warning: `fh_get_BSECA' defined but not used
+../fh_registry.h:300: warning: `fh_kw_BSECA' defined but not used
+../fh_registry.h:300: warning: `fh_cmt_BSECA' defined but not used
+../fh_registry.h:301: warning: `fh_set_BSECB' defined but not used
+../fh_registry.h:301: warning: `fh_setval_BSECB' defined but not used
+../fh_registry.h:301: warning: `fh_setcmt_BSECB' defined but not used
+../fh_registry.h:301: warning: `fh_get_BSECB' defined but not used
+../fh_registry.h:301: warning: `fh_kw_BSECB' defined but not used
+../fh_registry.h:301: warning: `fh_cmt_BSECB' defined but not used
+../fh_registry.h:302: warning: `fh_set_BSECC' defined but not used
+../fh_registry.h:302: warning: `fh_setval_BSECC' defined but not used
+../fh_registry.h:302: warning: `fh_setcmt_BSECC' defined but not used
+../fh_registry.h:302: warning: `fh_get_BSECC' defined but not used
+../fh_registry.h:302: warning: `fh_kw_BSECC' defined but not used
+../fh_registry.h:302: warning: `fh_cmt_BSECC' defined but not used
+../fh_registry.h:303: warning: `fh_set_BSECD' defined but not used
+../fh_registry.h:303: warning: `fh_setval_BSECD' defined but not used
+../fh_registry.h:303: warning: `fh_setcmt_BSECD' defined but not used
+../fh_registry.h:303: warning: `fh_get_BSECD' defined but not used
+../fh_registry.h:303: warning: `fh_kw_BSECD' defined but not used
+../fh_registry.h:303: warning: `fh_cmt_BSECD' defined but not used
+../fh_registry.h:304: warning: `fh_set_CSECA' defined but not used
+../fh_registry.h:304: warning: `fh_setval_CSECA' defined but not used
+../fh_registry.h:304: warning: `fh_setcmt_CSECA' defined but not used
+../fh_registry.h:304: warning: `fh_get_CSECA' defined but not used
+../fh_registry.h:304: warning: `fh_kw_CSECA' defined but not used
+../fh_registry.h:304: warning: `fh_cmt_CSECA' defined but not used
+../fh_registry.h:305: warning: `fh_set_CSECB' defined but not used
+../fh_registry.h:305: warning: `fh_setval_CSECB' defined but not used
+../fh_registry.h:305: warning: `fh_setcmt_CSECB' defined but not used
+../fh_registry.h:305: warning: `fh_get_CSECB' defined but not used
+../fh_registry.h:305: warning: `fh_kw_CSECB' defined but not used
+../fh_registry.h:305: warning: `fh_cmt_CSECB' defined but not used
+../fh_registry.h:306: warning: `fh_set_CSECC' defined but not used
+../fh_registry.h:306: warning: `fh_setval_CSECC' defined but not used
+../fh_registry.h:306: warning: `fh_setcmt_CSECC' defined but not used
+../fh_registry.h:306: warning: `fh_get_CSECC' defined but not used
+../fh_registry.h:306: warning: `fh_kw_CSECC' defined but not used
+../fh_registry.h:306: warning: `fh_cmt_CSECC' defined but not used
+../fh_registry.h:307: warning: `fh_set_CSECD' defined but not used
+../fh_registry.h:307: warning: `fh_setval_CSECD' defined but not used
+../fh_registry.h:307: warning: `fh_setcmt_CSECD' defined but not used
+../fh_registry.h:307: warning: `fh_get_CSECD' defined but not used
+../fh_registry.h:307: warning: `fh_kw_CSECD' defined but not used
+../fh_registry.h:307: warning: `fh_cmt_CSECD' defined but not used
+../fh_registry.h:308: warning: `fh_set_DSECA' defined but not used
+../fh_registry.h:308: warning: `fh_setval_DSECA' defined but not used
+../fh_registry.h:308: warning: `fh_setcmt_DSECA' defined but not used
+../fh_registry.h:308: warning: `fh_get_DSECA' defined but not used
+../fh_registry.h:308: warning: `fh_kw_DSECA' defined but not used
+../fh_registry.h:308: warning: `fh_cmt_DSECA' defined but not used
+../fh_registry.h:309: warning: `fh_set_DSECB' defined but not used
+../fh_registry.h:309: warning: `fh_setval_DSECB' defined but not used
+../fh_registry.h:309: warning: `fh_setcmt_DSECB' defined but not used
+../fh_registry.h:309: warning: `fh_get_DSECB' defined but not used
+../fh_registry.h:309: warning: `fh_kw_DSECB' defined but not used
+../fh_registry.h:309: warning: `fh_cmt_DSECB' defined but not used
+../fh_registry.h:310: warning: `fh_set_DSECC' defined but not used
+../fh_registry.h:310: warning: `fh_setval_DSECC' defined but not used
+../fh_registry.h:310: warning: `fh_setcmt_DSECC' defined but not used
+../fh_registry.h:310: warning: `fh_get_DSECC' defined but not used
+../fh_registry.h:310: warning: `fh_kw_DSECC' defined but not used
+../fh_registry.h:310: warning: `fh_cmt_DSECC' defined but not used
+../fh_registry.h:311: warning: `fh_set_DSECD' defined but not used
+../fh_registry.h:311: warning: `fh_setval_DSECD' defined but not used
+../fh_registry.h:311: warning: `fh_setcmt_DSECD' defined but not used
+../fh_registry.h:311: warning: `fh_get_DSECD' defined but not used
+../fh_registry.h:311: warning: `fh_kw_DSECD' defined but not used
+../fh_registry.h:311: warning: `fh_cmt_DSECD' defined but not used
+../fh_registry.h:312: warning: `fh_set_TSECA' defined but not used
+../fh_registry.h:312: warning: `fh_setval_TSECA' defined but not used
+../fh_registry.h:312: warning: `fh_setcmt_TSECA' defined but not used
+../fh_registry.h:312: warning: `fh_get_TSECA' defined but not used
+../fh_registry.h:312: warning: `fh_kw_TSECA' defined but not used
+../fh_registry.h:312: warning: `fh_cmt_TSECA' defined but not used
+../fh_registry.h:313: warning: `fh_set_TSECB' defined but not used
+../fh_registry.h:313: warning: `fh_setval_TSECB' defined but not used
+../fh_registry.h:313: warning: `fh_setcmt_TSECB' defined but not used
+../fh_registry.h:313: warning: `fh_get_TSECB' defined but not used
+../fh_registry.h:313: warning: `fh_kw_TSECB' defined but not used
+../fh_registry.h:313: warning: `fh_cmt_TSECB' defined but not used
+../fh_registry.h:314: warning: `fh_set_TSECC' defined but not used
+../fh_registry.h:314: warning: `fh_setval_TSECC' defined but not used
+../fh_registry.h:314: warning: `fh_setcmt_TSECC' defined but not used
+../fh_registry.h:314: warning: `fh_get_TSECC' defined but not used
+../fh_registry.h:314: warning: `fh_kw_TSECC' defined but not used
+../fh_registry.h:314: warning: `fh_cmt_TSECC' defined but not used
+../fh_registry.h:315: warning: `fh_set_TSECD' defined but not used
+../fh_registry.h:315: warning: `fh_setval_TSECD' defined but not used
+../fh_registry.h:315: warning: `fh_setcmt_TSECD' defined but not used
+../fh_registry.h:315: warning: `fh_get_TSECD' defined but not used
+../fh_registry.h:315: warning: `fh_kw_TSECD' defined but not used
+../fh_registry.h:315: warning: `fh_cmt_TSECD' defined but not used
+../fh_registry.h:316: warning: `fh_set_CCDNAME' defined but not used
+../fh_registry.h:316: warning: `fh_setval_CCDNAME' defined but not used
+../fh_registry.h:316: warning: `fh_setcmt_CCDNAME' defined but not used
+../fh_registry.h:316: warning: `fh_get_CCDNAME' defined but not used
+../fh_registry.h:316: warning: `fh_kw_CCDNAME' defined but not used
+../fh_registry.h:316: warning: `fh_cmt_CCDNAME' defined but not used
+../fh_registry.h:317: warning: `fh_set_CCDNICK' defined but not used
+../fh_registry.h:317: warning: `fh_setval_CCDNICK' defined but not used
+../fh_registry.h:317: warning: `fh_setcmt_CCDNICK' defined but not used
+../fh_registry.h:317: warning: `fh_get_CCDNICK' defined but not used
+../fh_registry.h:317: warning: `fh_kw_CCDNICK' defined but not used
+../fh_registry.h:317: warning: `fh_cmt_CCDNICK' defined but not used
+../fh_registry.h:318: warning: `fh_set_MAXLIN' defined but not used
+../fh_registry.h:318: warning: `fh_setval_MAXLIN' defined but not used
+../fh_registry.h:318: warning: `fh_setcmt_MAXLIN' defined but not used
+../fh_registry.h:318: warning: `fh_get_MAXLIN' defined but not used
+../fh_registry.h:318: warning: `fh_kw_MAXLIN' defined but not used
+../fh_registry.h:318: warning: `fh_cmt_MAXLIN' defined but not used
+../fh_registry.h:319: warning: `fh_set_MAXLINA' defined but not used
+../fh_registry.h:319: warning: `fh_setval_MAXLINA' defined but not used
+../fh_registry.h:319: warning: `fh_setcmt_MAXLINA' defined but not used
+../fh_registry.h:319: warning: `fh_get_MAXLINA' defined but not used
+../fh_registry.h:319: warning: `fh_kw_MAXLINA' defined but not used
+../fh_registry.h:319: warning: `fh_cmt_MAXLINA' defined but not used
+../fh_registry.h:320: warning: `fh_set_MAXLINB' defined but not used
+../fh_registry.h:320: warning: `fh_setval_MAXLINB' defined but not used
+../fh_registry.h:320: warning: `fh_setcmt_MAXLINB' defined but not used
+../fh_registry.h:320: warning: `fh_get_MAXLINB' defined but not used
+../fh_registry.h:320: warning: `fh_kw_MAXLINB' defined but not used
+../fh_registry.h:320: warning: `fh_cmt_MAXLINB' defined but not used
+../fh_registry.h:321: warning: `fh_set_MAXLINC' defined but not used
+../fh_registry.h:321: warning: `fh_setval_MAXLINC' defined but not used
+../fh_registry.h:321: warning: `fh_setcmt_MAXLINC' defined but not used
+../fh_registry.h:321: warning: `fh_get_MAXLINC' defined but not used
+../fh_registry.h:321: warning: `fh_kw_MAXLINC' defined but not used
+../fh_registry.h:321: warning: `fh_cmt_MAXLINC' defined but not used
+../fh_registry.h:322: warning: `fh_set_MAXLIND' defined but not used
+../fh_registry.h:322: warning: `fh_setval_MAXLIND' defined but not used
+../fh_registry.h:322: warning: `fh_setcmt_MAXLIND' defined but not used
+../fh_registry.h:322: warning: `fh_get_MAXLIND' defined but not used
+../fh_registry.h:322: warning: `fh_kw_MAXLIND' defined but not used
+../fh_registry.h:322: warning: `fh_cmt_MAXLIND' defined but not used
+../fh_registry.h:323: warning: `fh_set_SATURATE' defined but not used
+../fh_registry.h:323: warning: `fh_setval_SATURATE' defined but not used
+../fh_registry.h:323: warning: `fh_setcmt_SATURATE' defined but not used
+../fh_registry.h:323: warning: `fh_get_SATURATE' defined but not used
+../fh_registry.h:323: warning: `fh_kw_SATURATE' defined but not used
+../fh_registry.h:323: warning: `fh_cmt_SATURATE' defined but not used
+../fh_registry.h:324: warning: `fh_set_GAIN' defined but not used
+../fh_registry.h:324: warning: `fh_setval_GAIN' defined but not used
+../fh_registry.h:324: warning: `fh_setcmt_GAIN' defined but not used
+../fh_registry.h:324: warning: `fh_get_GAIN' defined but not used
+../fh_registry.h:324: warning: `fh_kw_GAIN' defined but not used
+../fh_registry.h:324: warning: `fh_cmt_GAIN' defined but not used
+../fh_registry.h:325: warning: `fh_set_GAINA' defined but not used
+../fh_registry.h:325: warning: `fh_setval_GAINA' defined but not used
+../fh_registry.h:325: warning: `fh_setcmt_GAINA' defined but not used
+../fh_registry.h:325: warning: `fh_get_GAINA' defined but not used
+../fh_registry.h:325: warning: `fh_kw_GAINA' defined but not used
+../fh_registry.h:325: warning: `fh_cmt_GAINA' defined but not used
+../fh_registry.h:326: warning: `fh_set_GAINB' defined but not used
+../fh_registry.h:326: warning: `fh_setval_GAINB' defined but not used
+../fh_registry.h:326: warning: `fh_setcmt_GAINB' defined but not used
+../fh_registry.h:326: warning: `fh_get_GAINB' defined but not used
+../fh_registry.h:326: warning: `fh_kw_GAINB' defined but not used
+../fh_registry.h:326: warning: `fh_cmt_GAINB' defined but not used
+../fh_registry.h:327: warning: `fh_set_GAINC' defined but not used
+../fh_registry.h:327: warning: `fh_setval_GAINC' defined but not used
+../fh_registry.h:327: warning: `fh_setcmt_GAINC' defined but not used
+../fh_registry.h:327: warning: `fh_get_GAINC' defined but not used
+../fh_registry.h:327: warning: `fh_kw_GAINC' defined but not used
+../fh_registry.h:327: warning: `fh_cmt_GAINC' defined but not used
+../fh_registry.h:328: warning: `fh_set_GAIND' defined but not used
+../fh_registry.h:328: warning: `fh_setval_GAIND' defined but not used
+../fh_registry.h:328: warning: `fh_setcmt_GAIND' defined but not used
+../fh_registry.h:328: warning: `fh_get_GAIND' defined but not used
+../fh_registry.h:328: warning: `fh_kw_GAIND' defined but not used
+../fh_registry.h:328: warning: `fh_cmt_GAIND' defined but not used
+../fh_registry.h:329: warning: `fh_set_RDNOISE' defined but not used
+../fh_registry.h:329: warning: `fh_setval_RDNOISE' defined but not used
+../fh_registry.h:329: warning: `fh_setcmt_RDNOISE' defined but not used
+../fh_registry.h:329: warning: `fh_get_RDNOISE' defined but not used
+../fh_registry.h:329: warning: `fh_kw_RDNOISE' defined but not used
+../fh_registry.h:329: warning: `fh_cmt_RDNOISE' defined but not used
+../fh_registry.h:330: warning: `fh_set_RDNOISEA' defined but not used
+../fh_registry.h:330: warning: `fh_setval_RDNOISEA' defined but not used
+../fh_registry.h:330: warning: `fh_setcmt_RDNOISEA' defined but not used
+../fh_registry.h:330: warning: `fh_get_RDNOISEA' defined but not used
+../fh_registry.h:330: warning: `fh_kw_RDNOISEA' defined but not used
+../fh_registry.h:330: warning: `fh_cmt_RDNOISEA' defined but not used
+../fh_registry.h:331: warning: `fh_set_RDNOISEB' defined but not used
+../fh_registry.h:331: warning: `fh_setval_RDNOISEB' defined but not used
+../fh_registry.h:331: warning: `fh_setcmt_RDNOISEB' defined but not used
+../fh_registry.h:331: warning: `fh_get_RDNOISEB' defined but not used
+../fh_registry.h:331: warning: `fh_kw_RDNOISEB' defined but not used
+../fh_registry.h:331: warning: `fh_cmt_RDNOISEB' defined but not used
+../fh_registry.h:332: warning: `fh_set_RDNOISEC' defined but not used
+../fh_registry.h:332: warning: `fh_setval_RDNOISEC' defined but not used
+../fh_registry.h:332: warning: `fh_setcmt_RDNOISEC' defined but not used
+../fh_registry.h:332: warning: `fh_get_RDNOISEC' defined but not used
+../fh_registry.h:332: warning: `fh_kw_RDNOISEC' defined but not used
+../fh_registry.h:332: warning: `fh_cmt_RDNOISEC' defined but not used
+../fh_registry.h:333: warning: `fh_set_RDNOISED' defined but not used
+../fh_registry.h:333: warning: `fh_setval_RDNOISED' defined but not used
+../fh_registry.h:333: warning: `fh_setcmt_RDNOISED' defined but not used
+../fh_registry.h:333: warning: `fh_get_RDNOISED' defined but not used
+../fh_registry.h:333: warning: `fh_kw_RDNOISED' defined but not used
+../fh_registry.h:333: warning: `fh_cmt_RDNOISED' defined but not used
+../fh_registry.h:334: warning: `fh_set_DCURRENT' defined but not used
+../fh_registry.h:334: warning: `fh_setval_DCURRENT' defined but not used
+../fh_registry.h:334: warning: `fh_setcmt_DCURRENT' defined but not used
+../fh_registry.h:334: warning: `fh_get_DCURRENT' defined but not used
+../fh_registry.h:334: warning: `fh_kw_DCURRENT' defined but not used
+../fh_registry.h:334: warning: `fh_cmt_DCURRENT' defined but not used
+../fh_registry.h:335: warning: `fh_set_DARKCUR' defined but not used
+../fh_registry.h:335: warning: `fh_setval_DARKCUR' defined but not used
+../fh_registry.h:335: warning: `fh_setcmt_DARKCUR' defined but not used
+../fh_registry.h:335: warning: `fh_get_DARKCUR' defined but not used
+../fh_registry.h:335: warning: `fh_kw_DARKCUR' defined but not used
+../fh_registry.h:335: warning: `fh_cmt_DARKCUR' defined but not used
+../fh_registry.h:336: warning: `fh_set_QEPOINTS' defined but not used
+../fh_registry.h:336: warning: `fh_setval_QEPOINTS' defined but not used
+../fh_registry.h:336: warning: `fh_setcmt_QEPOINTS' defined but not used
+../fh_registry.h:336: warning: `fh_get_QEPOINTS' defined but not used
+../fh_registry.h:336: warning: `fh_kw_QEPOINTS' defined but not used
+../fh_registry.h:336: warning: `fh_cmt_QEPOINTS' defined but not used
+../fh_registry.h:337: warning: `fh_set_CONSWV' defined but not used
+../fh_registry.h:337: warning: `fh_setval_CONSWV' defined but not used
+../fh_registry.h:337: warning: `fh_setcmt_CONSWV' defined but not used
+../fh_registry.h:337: warning: `fh_get_CONSWV' defined but not used
+../fh_registry.h:337: warning: `fh_kw_CONSWV' defined but not used
+../fh_registry.h:337: warning: `fh_cmt_CONSWV' defined but not used
+../fh_registry.h:338: warning: `fh_set_DETSTAT' defined but not used
+../fh_registry.h:338: warning: `fh_setval_DETSTAT' defined but not used
+../fh_registry.h:338: warning: `fh_setcmt_DETSTAT' defined but not used
+../fh_registry.h:338: warning: `fh_get_DETSTAT' defined but not used
+../fh_registry.h:338: warning: `fh_kw_DETSTAT' defined but not used
+../fh_registry.h:338: warning: `fh_cmt_DETSTAT' defined but not used
+../fh_registry.h:339: warning: `fh_set_DETTEM' defined but not used
+../fh_registry.h:339: warning: `fh_setval_DETTEM' defined but not used
+../fh_registry.h:339: warning: `fh_setcmt_DETTEM' defined but not used
+../fh_registry.h:339: warning: `fh_get_DETTEM' defined but not used
+../fh_registry.h:339: warning: `fh_kw_DETTEM' defined but not used
+../fh_registry.h:339: warning: `fh_cmt_DETTEM' defined but not used
+../fh_registry.h:385: warning: `fh_set_DATE_OBS' defined but not used
+../fh_registry.h:385: warning: `fh_setval_DATE_OBS' defined but not used
+../fh_registry.h:385: warning: `fh_setcmt_DATE_OBS' defined but not used
+../fh_registry.h:385: warning: `fh_get_DATE_OBS' defined but not used
+../fh_registry.h:385: warning: `fh_kw_DATE_OBS' defined but not used
+../fh_registry.h:385: warning: `fh_cmt_DATE_OBS' defined but not used
+../fh_registry.h:386: warning: `fh_set_UTC_OBS' defined but not used
+../fh_registry.h:386: warning: `fh_setval_UTC_OBS' defined but not used
+../fh_registry.h:386: warning: `fh_setcmt_UTC_OBS' defined but not used
+../fh_registry.h:386: warning: `fh_get_UTC_OBS' defined but not used
+../fh_registry.h:386: warning: `fh_kw_UTC_OBS' defined but not used
+../fh_registry.h:386: warning: `fh_cmt_UTC_OBS' defined but not used
+../fh_registry.h:387: warning: `fh_set_MJD_OBS' defined but not used
+../fh_registry.h:387: warning: `fh_setval_MJD_OBS' defined but not used
+../fh_registry.h:387: warning: `fh_setcmt_MJD_OBS' defined but not used
+../fh_registry.h:387: warning: `fh_get_MJD_OBS' defined but not used
+../fh_registry.h:387: warning: `fh_kw_MJD_OBS' defined but not used
+../fh_registry.h:387: warning: `fh_cmt_MJD_OBS' defined but not used
+../fh_registry.h:388: warning: `fh_set_LST_OBS' defined but not used
+../fh_registry.h:388: warning: `fh_setval_LST_OBS' defined but not used
+../fh_registry.h:388: warning: `fh_setcmt_LST_OBS' defined but not used
+../fh_registry.h:388: warning: `fh_get_LST_OBS' defined but not used
+../fh_registry.h:388: warning: `fh_kw_LST_OBS' defined but not used
+../fh_registry.h:388: warning: `fh_cmt_LST_OBS' defined but not used
+../fh_registry.h:391: warning: `fh_set_CMTTCS1' defined but not used
+../fh_registry.h:392: warning: `fh_set_CMTTCS2' defined but not used
+../fh_registry.h:393: warning: `fh_set_CMTTCS3' defined but not used
+../fh_registry.h:394: warning: `fh_set_CMTTCS4' defined but not used
+../fh_registry.h:395: warning: `fh_set_TELESCOP' defined but not used
+../fh_registry.h:395: warning: `fh_setval_TELESCOP' defined but not used
+../fh_registry.h:395: warning: `fh_setcmt_TELESCOP' defined but not used
+../fh_registry.h:395: warning: `fh_get_TELESCOP' defined but not used
+../fh_registry.h:395: warning: `fh_kw_TELESCOP' defined but not used
+../fh_registry.h:395: warning: `fh_cmt_TELESCOP' defined but not used
+../fh_registry.h:396: warning: `fh_set_ORIGIN' defined but not used
+../fh_registry.h:396: warning: `fh_setval_ORIGIN' defined but not used
+../fh_registry.h:396: warning: `fh_setcmt_ORIGIN' defined but not used
+../fh_registry.h:396: warning: `fh_get_ORIGIN' defined but not used
+../fh_registry.h:396: warning: `fh_kw_ORIGIN' defined but not used
+../fh_registry.h:396: warning: `fh_cmt_ORIGIN' defined but not used
+../fh_registry.h:397: warning: `fh_set_LATITUDE' defined but not used
+../fh_registry.h:397: warning: `fh_setval_LATITUDE' defined but not used
+../fh_registry.h:397: warning: `fh_setcmt_LATITUDE' defined but not used
+../fh_registry.h:397: warning: `fh_get_LATITUDE' defined but not used
+../fh_registry.h:397: warning: `fh_kw_LATITUDE' defined but not used
+../fh_registry.h:397: warning: `fh_cmt_LATITUDE' defined but not used
+../fh_registry.h:398: warning: `fh_set_LONGITUD' defined but not used
+../fh_registry.h:398: warning: `fh_setval_LONGITUD' defined but not used
+../fh_registry.h:398: warning: `fh_setcmt_LONGITUD' defined but not used
+../fh_registry.h:398: warning: `fh_get_LONGITUD' defined but not used
+../fh_registry.h:398: warning: `fh_kw_LONGITUD' defined but not used
+../fh_registry.h:398: warning: `fh_cmt_LONGITUD' defined but not used
+../fh_registry.h:399: warning: `fh_set_TELSTAT' defined but not used
+../fh_registry.h:399: warning: `fh_setval_TELSTAT' defined but not used
+../fh_registry.h:399: warning: `fh_setcmt_TELSTAT' defined but not used
+../fh_registry.h:399: warning: `fh_get_TELSTAT' defined but not used
+../fh_registry.h:399: warning: `fh_kw_TELSTAT' defined but not used
+../fh_registry.h:399: warning: `fh_cmt_TELSTAT' defined but not used
+../fh_registry.h:400: warning: `fh_set_TIMESYS' defined but not used
+../fh_registry.h:400: warning: `fh_setval_TIMESYS' defined but not used
+../fh_registry.h:400: warning: `fh_setcmt_TIMESYS' defined but not used
+../fh_registry.h:400: warning: `fh_get_TIMESYS' defined but not used
+../fh_registry.h:400: warning: `fh_kw_TIMESYS' defined but not used
+../fh_registry.h:400: warning: `fh_cmt_TIMESYS' defined but not used
+../fh_registry.h:402: warning: `fh_set_UTIME' defined but not used
+../fh_registry.h:402: warning: `fh_setval_UTIME' defined but not used
+../fh_registry.h:402: warning: `fh_setcmt_UTIME' defined but not used
+../fh_registry.h:402: warning: `fh_get_UTIME' defined but not used
+../fh_registry.h:402: warning: `fh_kw_UTIME' defined but not used
+../fh_registry.h:402: warning: `fh_cmt_UTIME' defined but not used
+../fh_registry.h:403: warning: `fh_set_MJDATE' defined but not used
+../fh_registry.h:403: warning: `fh_setval_MJDATE' defined but not used
+../fh_registry.h:403: warning: `fh_setcmt_MJDATE' defined but not used
+../fh_registry.h:403: warning: `fh_get_MJDATE' defined but not used
+../fh_registry.h:403: warning: `fh_kw_MJDATE' defined but not used
+../fh_registry.h:403: warning: `fh_cmt_MJDATE' defined but not used
+../fh_registry.h:404: warning: `fh_set_SIDTIME' defined but not used
+../fh_registry.h:404: warning: `fh_setval_SIDTIME' defined but not used
+../fh_registry.h:404: warning: `fh_setcmt_SIDTIME' defined but not used
+../fh_registry.h:404: warning: `fh_get_SIDTIME' defined but not used
+../fh_registry.h:404: warning: `fh_kw_SIDTIME' defined but not used
+../fh_registry.h:404: warning: `fh_cmt_SIDTIME' defined but not used
+../fh_registry.h:405: warning: `fh_set_EPOCH' defined but not used
+../fh_registry.h:405: warning: `fh_setcmt_EPOCH' defined but not used
+../fh_registry.h:405: warning: `fh_kw_EPOCH' defined but not used
+../fh_registry.h:405: warning: `fh_cmt_EPOCH' defined but not used
+../fh_registry.h:406: warning: `fh_set_EQUINOX' defined but not used
+../fh_registry.h:406: warning: `fh_setcmt_EQUINOX' defined but not used
+../fh_registry.h:406: warning: `fh_kw_EQUINOX' defined but not used
+../fh_registry.h:406: warning: `fh_cmt_EQUINOX' defined but not used
+../fh_registry.h:407: warning: `fh_set_RADECSYS' defined but not used
+../fh_registry.h:407: warning: `fh_setval_RADECSYS' defined but not used
+../fh_registry.h:407: warning: `fh_setcmt_RADECSYS' defined but not used
+../fh_registry.h:407: warning: `fh_get_RADECSYS' defined but not used
+../fh_registry.h:407: warning: `fh_kw_RADECSYS' defined but not used
+../fh_registry.h:407: warning: `fh_cmt_RADECSYS' defined but not used
+../fh_registry.h:408: warning: `fh_set_RA' defined but not used
+../fh_registry.h:408: warning: `fh_setval_RA' defined but not used
+../fh_registry.h:408: warning: `fh_setcmt_RA' defined but not used
+../fh_registry.h:408: warning: `fh_get_RA' defined but not used
+../fh_registry.h:408: warning: `fh_kw_RA' defined but not used
+../fh_registry.h:408: warning: `fh_cmt_RA' defined but not used
+../fh_registry.h:409: warning: `fh_set_DEC' defined but not used
+../fh_registry.h:409: warning: `fh_setval_DEC' defined but not used
+../fh_registry.h:409: warning: `fh_setcmt_DEC' defined but not used
+../fh_registry.h:409: warning: `fh_get_DEC' defined but not used
+../fh_registry.h:409: warning: `fh_kw_DEC' defined but not used
+../fh_registry.h:409: warning: `fh_cmt_DEC' defined but not used
+../fh_registry.h:410: warning: `fh_set_RA_DEG' defined but not used
+../fh_registry.h:410: warning: `fh_setval_RA_DEG' defined but not used
+../fh_registry.h:410: warning: `fh_setcmt_RA_DEG' defined but not used
+../fh_registry.h:410: warning: `fh_get_RA_DEG' defined but not used
+../fh_registry.h:410: warning: `fh_kw_RA_DEG' defined but not used
+../fh_registry.h:410: warning: `fh_cmt_RA_DEG' defined but not used
+../fh_registry.h:411: warning: `fh_set_DEC_DEG' defined but not used
+../fh_registry.h:411: warning: `fh_setval_DEC_DEG' defined but not used
+../fh_registry.h:411: warning: `fh_setcmt_DEC_DEG' defined but not used
+../fh_registry.h:411: warning: `fh_get_DEC_DEG' defined but not used
+../fh_registry.h:411: warning: `fh_kw_DEC_DEG' defined but not used
+../fh_registry.h:411: warning: `fh_cmt_DEC_DEG' defined but not used
+../fh_registry.h:413: warning: `fh_set_CRVAL1' defined but not used
+../fh_registry.h:413: warning: `fh_setval_CRVAL1' defined but not used
+../fh_registry.h:413: warning: `fh_setcmt_CRVAL1' defined but not used
+../fh_registry.h:413: warning: `fh_get_CRVAL1' defined but not used
+../fh_registry.h:413: warning: `fh_kw_CRVAL1' defined but not used
+../fh_registry.h:413: warning: `fh_cmt_CRVAL1' defined but not used
+../fh_registry.h:414: warning: `fh_set_CRVAL2' defined but not used
+../fh_registry.h:414: warning: `fh_setval_CRVAL2' defined but not used
+../fh_registry.h:414: warning: `fh_setcmt_CRVAL2' defined but not used
+../fh_registry.h:414: warning: `fh_get_CRVAL2' defined but not used
+../fh_registry.h:414: warning: `fh_kw_CRVAL2' defined but not used
+../fh_registry.h:414: warning: `fh_cmt_CRVAL2' defined but not used
+../fh_registry.h:415: warning: `fh_set_CTYPE1' defined but not used
+../fh_registry.h:415: warning: `fh_setval_CTYPE1' defined but not used
+../fh_registry.h:415: warning: `fh_setcmt_CTYPE1' defined but not used
+../fh_registry.h:415: warning: `fh_get_CTYPE1' defined but not used
+../fh_registry.h:415: warning: `fh_kw_CTYPE1' defined but not used
+../fh_registry.h:415: warning: `fh_cmt_CTYPE1' defined but not used
+../fh_registry.h:416: warning: `fh_set_CTYPE2' defined but not used
+../fh_registry.h:416: warning: `fh_setval_CTYPE2' defined but not used
+../fh_registry.h:416: warning: `fh_setcmt_CTYPE2' defined but not used
+../fh_registry.h:416: warning: `fh_get_CTYPE2' defined but not used
+../fh_registry.h:416: warning: `fh_kw_CTYPE2' defined but not used
+../fh_registry.h:416: warning: `fh_cmt_CTYPE2' defined but not used
+../fh_registry.h:417: warning: `fh_set_CRPIX1' defined but not used
+../fh_registry.h:417: warning: `fh_setval_CRPIX1' defined but not used
+../fh_registry.h:417: warning: `fh_setcmt_CRPIX1' defined but not used
+../fh_registry.h:417: warning: `fh_get_CRPIX1' defined but not used
+../fh_registry.h:417: warning: `fh_kw_CRPIX1' defined but not used
+../fh_registry.h:417: warning: `fh_cmt_CRPIX1' defined but not used
+../fh_registry.h:418: warning: `fh_set_CRPIX2' defined but not used
+../fh_registry.h:418: warning: `fh_setval_CRPIX2' defined but not used
+../fh_registry.h:418: warning: `fh_setcmt_CRPIX2' defined but not used
+../fh_registry.h:418: warning: `fh_get_CRPIX2' defined but not used
+../fh_registry.h:418: warning: `fh_kw_CRPIX2' defined but not used
+../fh_registry.h:418: warning: `fh_cmt_CRPIX2' defined but not used
+../fh_registry.h:419: warning: `fh_set_CD1_1' defined but not used
+../fh_registry.h:419: warning: `fh_setval_CD1_1' defined but not used
+../fh_registry.h:419: warning: `fh_setcmt_CD1_1' defined but not used
+../fh_registry.h:419: warning: `fh_get_CD1_1' defined but not used
+../fh_registry.h:419: warning: `fh_kw_CD1_1' defined but not used
+../fh_registry.h:419: warning: `fh_cmt_CD1_1' defined but not used
+../fh_registry.h:420: warning: `fh_set_CD1_2' defined but not used
+../fh_registry.h:420: warning: `fh_setval_CD1_2' defined but not used
+../fh_registry.h:420: warning: `fh_setcmt_CD1_2' defined but not used
+../fh_registry.h:420: warning: `fh_get_CD1_2' defined but not used
+../fh_registry.h:420: warning: `fh_kw_CD1_2' defined but not used
+../fh_registry.h:420: warning: `fh_cmt_CD1_2' defined but not used
+../fh_registry.h:421: warning: `fh_set_CD2_1' defined but not used
+../fh_registry.h:421: warning: `fh_setval_CD2_1' defined but not used
+../fh_registry.h:421: warning: `fh_setcmt_CD2_1' defined but not used
+../fh_registry.h:421: warning: `fh_get_CD2_1' defined but not used
+../fh_registry.h:421: warning: `fh_kw_CD2_1' defined but not used
+../fh_registry.h:421: warning: `fh_cmt_CD2_1' defined but not used
+../fh_registry.h:422: warning: `fh_set_CD2_2' defined but not used
+../fh_registry.h:422: warning: `fh_setval_CD2_2' defined but not used
+../fh_registry.h:422: warning: `fh_setcmt_CD2_2' defined but not used
+../fh_registry.h:422: warning: `fh_get_CD2_2' defined but not used
+../fh_registry.h:422: warning: `fh_kw_CD2_2' defined but not used
+../fh_registry.h:422: warning: `fh_cmt_CD2_2' defined but not used
+../fh_registry.h:424: warning: `fh_set_NGUIDER' defined but not used
+../fh_registry.h:424: warning: `fh_setval_NGUIDER' defined but not used
+../fh_registry.h:424: warning: `fh_setcmt_NGUIDER' defined but not used
+../fh_registry.h:424: warning: `fh_get_NGUIDER' defined but not used
+../fh_registry.h:424: warning: `fh_kw_NGUIDER' defined but not used
+../fh_registry.h:424: warning: `fh_cmt_NGUIDER' defined but not used
+../fh_registry.h:425: warning: `fh_set_NGUISTAR' defined but not used
+../fh_registry.h:425: warning: `fh_setval_NGUISTAR' defined but not used
+../fh_registry.h:425: warning: `fh_setcmt_NGUISTAR' defined but not used
+../fh_registry.h:425: warning: `fh_get_NGUISTAR' defined but not used
+../fh_registry.h:425: warning: `fh_kw_NGUISTAR' defined but not used
+../fh_registry.h:425: warning: `fh_cmt_NGUISTAR' defined but not used
+../fh_registry.h:426: warning: `fh_set_GUINAME' defined but not used
+../fh_registry.h:426: warning: `fh_setval_GUINAME' defined but not used
+../fh_registry.h:426: warning: `fh_setcmt_GUINAME' defined but not used
+../fh_registry.h:426: warning: `fh_get_GUINAME' defined but not used
+../fh_registry.h:426: warning: `fh_kw_GUINAME' defined but not used
+../fh_registry.h:426: warning: `fh_cmt_GUINAME' defined but not used
+../fh_registry.h:427: warning: `fh_set_GUIEQUIN' defined but not used
+../fh_registry.h:427: warning: `fh_setcmt_GUIEQUIN' defined but not used
+../fh_registry.h:427: warning: `fh_kw_GUIEQUIN' defined but not used
+../fh_registry.h:427: warning: `fh_cmt_GUIEQUIN' defined but not used
+../fh_registry.h:428: warning: `fh_set_GUIRADEC' defined but not used
+../fh_registry.h:428: warning: `fh_setval_GUIRADEC' defined but not used
+../fh_registry.h:428: warning: `fh_setcmt_GUIRADEC' defined but not used
+../fh_registry.h:428: warning: `fh_get_GUIRADEC' defined but not used
+../fh_registry.h:428: warning: `fh_kw_GUIRADEC' defined but not used
+../fh_registry.h:428: warning: `fh_cmt_GUIRADEC' defined but not used
+../fh_registry.h:429: warning: `fh_set_GUIRA' defined but not used
+../fh_registry.h:429: warning: `fh_setval_GUIRA' defined but not used
+../fh_registry.h:429: warning: `fh_setcmt_GUIRA' defined but not used
+../fh_registry.h:429: warning: `fh_get_GUIRA' defined but not used
+../fh_registry.h:429: warning: `fh_kw_GUIRA' defined but not used
+../fh_registry.h:429: warning: `fh_cmt_GUIRA' defined but not used
+../fh_registry.h:430: warning: `fh_set_GUIDEC' defined but not used
+../fh_registry.h:430: warning: `fh_setval_GUIDEC' defined but not used
+../fh_registry.h:430: warning: `fh_setcmt_GUIDEC' defined but not used
+../fh_registry.h:430: warning: `fh_get_GUIDEC' defined but not used
+../fh_registry.h:430: warning: `fh_kw_GUIDEC' defined but not used
+../fh_registry.h:430: warning: `fh_cmt_GUIDEC' defined but not used
+../fh_registry.h:431: warning: `fh_set_GUIRAPM' defined but not used
+../fh_registry.h:431: warning: `fh_setval_GUIRAPM' defined but not used
+../fh_registry.h:431: warning: `fh_setcmt_GUIRAPM' defined but not used
+../fh_registry.h:431: warning: `fh_get_GUIRAPM' defined but not used
+../fh_registry.h:431: warning: `fh_kw_GUIRAPM' defined but not used
+../fh_registry.h:431: warning: `fh_cmt_GUIRAPM' defined but not used
+../fh_registry.h:432: warning: `fh_set_GUIDECPM' defined but not used
+../fh_registry.h:432: warning: `fh_setval_GUIDECPM' defined but not used
+../fh_registry.h:432: warning: `fh_setcmt_GUIDECPM' defined but not used
+../fh_registry.h:432: warning: `fh_get_GUIDECPM' defined but not used
+../fh_registry.h:432: warning: `fh_kw_GUIDECPM' defined but not used
+../fh_registry.h:432: warning: `fh_cmt_GUIDECPM' defined but not used
+../fh_registry.h:433: warning: `fh_set_GUIOBJN' defined but not used
+../fh_registry.h:433: warning: `fh_setval_GUIOBJN' defined but not used
+../fh_registry.h:433: warning: `fh_setcmt_GUIOBJN' defined but not used
+../fh_registry.h:433: warning: `fh_get_GUIOBJN' defined but not used
+../fh_registry.h:433: warning: `fh_kw_GUIOBJN' defined but not used
+../fh_registry.h:433: warning: `fh_cmt_GUIOBJN' defined but not used
+../fh_registry.h:434: warning: `fh_set_GUIMAGN' defined but not used
+../fh_registry.h:434: warning: `fh_setval_GUIMAGN' defined but not used
+../fh_registry.h:434: warning: `fh_setcmt_GUIMAGN' defined but not used
+../fh_registry.h:434: warning: `fh_get_GUIMAGN' defined but not used
+../fh_registry.h:434: warning: `fh_kw_GUIMAGN' defined but not used
+../fh_registry.h:434: warning: `fh_cmt_GUIMAGN' defined but not used
+../fh_registry.h:435: warning: `fh_set_XPROBE' defined but not used
+../fh_registry.h:435: warning: `fh_setval_XPROBE' defined but not used
+../fh_registry.h:435: warning: `fh_setcmt_XPROBE' defined but not used
+../fh_registry.h:435: warning: `fh_get_XPROBE' defined but not used
+../fh_registry.h:435: warning: `fh_kw_XPROBE' defined but not used
+../fh_registry.h:435: warning: `fh_cmt_XPROBE' defined but not used
+../fh_registry.h:436: warning: `fh_set_YPROBE' defined but not used
+../fh_registry.h:436: warning: `fh_setval_YPROBE' defined but not used
+../fh_registry.h:436: warning: `fh_setcmt_YPROBE' defined but not used
+../fh_registry.h:436: warning: `fh_get_YPROBE' defined but not used
+../fh_registry.h:436: warning: `fh_kw_YPROBE' defined but not used
+../fh_registry.h:436: warning: `fh_cmt_YPROBE' defined but not used
+../fh_registry.h:437: warning: `fh_set_ZPROBE' defined but not used
+../fh_registry.h:437: warning: `fh_setval_ZPROBE' defined but not used
+../fh_registry.h:437: warning: `fh_setcmt_ZPROBE' defined but not used
+../fh_registry.h:437: warning: `fh_get_ZPROBE' defined but not used
+../fh_registry.h:437: warning: `fh_kw_ZPROBE' defined but not used
+../fh_registry.h:437: warning: `fh_cmt_ZPROBE' defined but not used
+../fh_registry.h:438: warning: `fh_set_GUIFLUX' defined but not used
+../fh_registry.h:438: warning: `fh_setval_GUIFLUX' defined but not used
+../fh_registry.h:438: warning: `fh_setcmt_GUIFLUX' defined but not used
+../fh_registry.h:438: warning: `fh_get_GUIFLUX' defined but not used
+../fh_registry.h:438: warning: `fh_kw_GUIFLUX' defined but not used
+../fh_registry.h:438: warning: `fh_cmt_GUIFLUX' defined but not used
+../fh_registry.h:439: warning: `fh_set_GUIFWHX' defined but not used
+../fh_registry.h:439: warning: `fh_setval_GUIFWHX' defined but not used
+../fh_registry.h:439: warning: `fh_setcmt_GUIFWHX' defined but not used
+../fh_registry.h:439: warning: `fh_get_GUIFWHX' defined but not used
+../fh_registry.h:439: warning: `fh_kw_GUIFWHX' defined but not used
+../fh_registry.h:439: warning: `fh_cmt_GUIFWHX' defined but not used
+../fh_registry.h:440: warning: `fh_set_GUIFWHY' defined but not used
+../fh_registry.h:440: warning: `fh_setval_GUIFWHY' defined but not used
+../fh_registry.h:440: warning: `fh_setcmt_GUIFWHY' defined but not used
+../fh_registry.h:440: warning: `fh_get_GUIFWHY' defined but not used
+../fh_registry.h:440: warning: `fh_kw_GUIFWHY' defined but not used
+../fh_registry.h:440: warning: `fh_cmt_GUIFWHY' defined but not used
+../fh_registry.h:441: warning: `fh_set_SKYFLUX' defined but not used
+../fh_registry.h:441: warning: `fh_setval_SKYFLUX' defined but not used
+../fh_registry.h:441: warning: `fh_setcmt_SKYFLUX' defined but not used
+../fh_registry.h:441: warning: `fh_get_SKYFLUX' defined but not used
+../fh_registry.h:441: warning: `fh_kw_SKYFLUX' defined but not used
+../fh_registry.h:441: warning: `fh_cmt_SKYFLUX' defined but not used
+../fh_registry.h:443: warning: `fh_set_GUINAME1' defined but not used
+../fh_registry.h:443: warning: `fh_setval_GUINAME1' defined but not used
+../fh_registry.h:443: warning: `fh_setcmt_GUINAME1' defined but not used
+../fh_registry.h:443: warning: `fh_get_GUINAME1' defined but not used
+../fh_registry.h:443: warning: `fh_kw_GUINAME1' defined but not used
+../fh_registry.h:443: warning: `fh_cmt_GUINAME1' defined but not used
+../fh_registry.h:444: warning: `fh_set_GUIEQUI1' defined but not used
+../fh_registry.h:444: warning: `fh_setcmt_GUIEQUI1' defined but not used
+../fh_registry.h:444: warning: `fh_kw_GUIEQUI1' defined but not used
+../fh_registry.h:444: warning: `fh_cmt_GUIEQUI1' defined but not used
+../fh_registry.h:445: warning: `fh_set_GUIRADE1' defined but not used
+../fh_registry.h:445: warning: `fh_setval_GUIRADE1' defined but not used
+../fh_registry.h:445: warning: `fh_setcmt_GUIRADE1' defined but not used
+../fh_registry.h:445: warning: `fh_get_GUIRADE1' defined but not used
+../fh_registry.h:445: warning: `fh_kw_GUIRADE1' defined but not used
+../fh_registry.h:445: warning: `fh_cmt_GUIRADE1' defined but not used
+../fh_registry.h:446: warning: `fh_set_GUIRA1' defined but not used
+../fh_registry.h:446: warning: `fh_setval_GUIRA1' defined but not used
+../fh_registry.h:446: warning: `fh_setcmt_GUIRA1' defined but not used
+../fh_registry.h:446: warning: `fh_get_GUIRA1' defined but not used
+../fh_registry.h:446: warning: `fh_kw_GUIRA1' defined but not used
+../fh_registry.h:446: warning: `fh_cmt_GUIRA1' defined but not used
+../fh_registry.h:447: warning: `fh_set_GUIDEC1' defined but not used
+../fh_registry.h:447: warning: `fh_setval_GUIDEC1' defined but not used
+../fh_registry.h:447: warning: `fh_setcmt_GUIDEC1' defined but not used
+../fh_registry.h:447: warning: `fh_get_GUIDEC1' defined but not used
+../fh_registry.h:447: warning: `fh_kw_GUIDEC1' defined but not used
+../fh_registry.h:447: warning: `fh_cmt_GUIDEC1' defined but not used
+../fh_registry.h:448: warning: `fh_set_GUIRAPM1' defined but not used
+../fh_registry.h:448: warning: `fh_setval_GUIRAPM1' defined but not used
+../fh_registry.h:448: warning: `fh_setcmt_GUIRAPM1' defined but not used
+../fh_registry.h:448: warning: `fh_get_GUIRAPM1' defined but not used
+../fh_registry.h:448: warning: `fh_kw_GUIRAPM1' defined but not used
+../fh_registry.h:448: warning: `fh_cmt_GUIRAPM1' defined but not used
+../fh_registry.h:449: warning: `fh_set_GUIDEPM1' defined but not used
+../fh_registry.h:449: warning: `fh_setval_GUIDEPM1' defined but not used
+../fh_registry.h:449: warning: `fh_setcmt_GUIDEPM1' defined but not used
+../fh_registry.h:449: warning: `fh_get_GUIDEPM1' defined but not used
+../fh_registry.h:449: warning: `fh_kw_GUIDEPM1' defined but not used
+../fh_registry.h:449: warning: `fh_cmt_GUIDEPM1' defined but not used
+../fh_registry.h:450: warning: `fh_set_GUIOBJN1' defined but not used
+../fh_registry.h:450: warning: `fh_setval_GUIOBJN1' defined but not used
+../fh_registry.h:450: warning: `fh_setcmt_GUIOBJN1' defined but not used
+../fh_registry.h:450: warning: `fh_get_GUIOBJN1' defined but not used
+../fh_registry.h:450: warning: `fh_kw_GUIOBJN1' defined but not used
+../fh_registry.h:450: warning: `fh_cmt_GUIOBJN1' defined but not used
+../fh_registry.h:451: warning: `fh_set_GUIMAGN1' defined but not used
+../fh_registry.h:451: warning: `fh_setval_GUIMAGN1' defined but not used
+../fh_registry.h:451: warning: `fh_setcmt_GUIMAGN1' defined but not used
+../fh_registry.h:451: warning: `fh_get_GUIMAGN1' defined but not used
+../fh_registry.h:451: warning: `fh_kw_GUIMAGN1' defined but not used
+../fh_registry.h:451: warning: `fh_cmt_GUIMAGN1' defined but not used
+../fh_registry.h:452: warning: `fh_set_GUIPOSX1' defined but not used
+../fh_registry.h:452: warning: `fh_setval_GUIPOSX1' defined but not used
+../fh_registry.h:452: warning: `fh_setcmt_GUIPOSX1' defined but not used
+../fh_registry.h:452: warning: `fh_get_GUIPOSX1' defined but not used
+../fh_registry.h:452: warning: `fh_kw_GUIPOSX1' defined but not used
+../fh_registry.h:452: warning: `fh_cmt_GUIPOSX1' defined but not used
+../fh_registry.h:453: warning: `fh_set_GUIPOSY1' defined but not used
+../fh_registry.h:453: warning: `fh_setval_GUIPOSY1' defined but not used
+../fh_registry.h:453: warning: `fh_setcmt_GUIPOSY1' defined but not used
+../fh_registry.h:453: warning: `fh_get_GUIPOSY1' defined but not used
+../fh_registry.h:453: warning: `fh_kw_GUIPOSY1' defined but not used
+../fh_registry.h:453: warning: `fh_cmt_GUIPOSY1' defined but not used
+../fh_registry.h:454: warning: `fh_set_GUIPOSZ1' defined but not used
+../fh_registry.h:454: warning: `fh_setval_GUIPOSZ1' defined but not used
+../fh_registry.h:454: warning: `fh_setcmt_GUIPOSZ1' defined but not used
+../fh_registry.h:454: warning: `fh_get_GUIPOSZ1' defined but not used
+../fh_registry.h:454: warning: `fh_kw_GUIPOSZ1' defined but not used
+../fh_registry.h:454: warning: `fh_cmt_GUIPOSZ1' defined but not used
+../fh_registry.h:455: warning: `fh_set_GUIFLUX1' defined but not used
+../fh_registry.h:455: warning: `fh_setval_GUIFLUX1' defined but not used
+../fh_registry.h:455: warning: `fh_setcmt_GUIFLUX1' defined but not used
+../fh_registry.h:455: warning: `fh_get_GUIFLUX1' defined but not used
+../fh_registry.h:455: warning: `fh_kw_GUIFLUX1' defined but not used
+../fh_registry.h:455: warning: `fh_cmt_GUIFLUX1' defined but not used
+../fh_registry.h:456: warning: `fh_set_GUIFWHX1' defined but not used
+../fh_registry.h:456: warning: `fh_setval_GUIFWHX1' defined but not used
+../fh_registry.h:456: warning: `fh_setcmt_GUIFWHX1' defined but not used
+../fh_registry.h:456: warning: `fh_get_GUIFWHX1' defined but not used
+../fh_registry.h:456: warning: `fh_kw_GUIFWHX1' defined but not used
+../fh_registry.h:456: warning: `fh_cmt_GUIFWHX1' defined but not used
+../fh_registry.h:457: warning: `fh_set_GUIFWHY1' defined but not used
+../fh_registry.h:457: warning: `fh_setval_GUIFWHY1' defined but not used
+../fh_registry.h:457: warning: `fh_setcmt_GUIFWHY1' defined but not used
+../fh_registry.h:457: warning: `fh_get_GUIFWHY1' defined but not used
+../fh_registry.h:457: warning: `fh_kw_GUIFWHY1' defined but not used
+../fh_registry.h:457: warning: `fh_cmt_GUIFWHY1' defined but not used
+../fh_registry.h:459: warning: `fh_set_GUINAME2' defined but not used
+../fh_registry.h:459: warning: `fh_setval_GUINAME2' defined but not used
+../fh_registry.h:459: warning: `fh_setcmt_GUINAME2' defined but not used
+../fh_registry.h:459: warning: `fh_get_GUINAME2' defined but not used
+../fh_registry.h:459: warning: `fh_kw_GUINAME2' defined but not used
+../fh_registry.h:459: warning: `fh_cmt_GUINAME2' defined but not used
+../fh_registry.h:460: warning: `fh_set_GUIEQUI2' defined but not used
+../fh_registry.h:460: warning: `fh_setcmt_GUIEQUI2' defined but not used
+../fh_registry.h:460: warning: `fh_kw_GUIEQUI2' defined but not used
+../fh_registry.h:460: warning: `fh_cmt_GUIEQUI2' defined but not used
+../fh_registry.h:461: warning: `fh_set_GUIRADE2' defined but not used
+../fh_registry.h:461: warning: `fh_setval_GUIRADE2' defined but not used
+../fh_registry.h:461: warning: `fh_setcmt_GUIRADE2' defined but not used
+../fh_registry.h:461: warning: `fh_get_GUIRADE2' defined but not used
+../fh_registry.h:461: warning: `fh_kw_GUIRADE2' defined but not used
+../fh_registry.h:461: warning: `fh_cmt_GUIRADE2' defined but not used
+../fh_registry.h:462: warning: `fh_set_GUIRA2' defined but not used
+../fh_registry.h:462: warning: `fh_setval_GUIRA2' defined but not used
+../fh_registry.h:462: warning: `fh_setcmt_GUIRA2' defined but not used
+../fh_registry.h:462: warning: `fh_get_GUIRA2' defined but not used
+../fh_registry.h:462: warning: `fh_kw_GUIRA2' defined but not used
+../fh_registry.h:462: warning: `fh_cmt_GUIRA2' defined but not used
+../fh_registry.h:463: warning: `fh_set_GUIDEC2' defined but not used
+../fh_registry.h:463: warning: `fh_setval_GUIDEC2' defined but not used
+../fh_registry.h:463: warning: `fh_setcmt_GUIDEC2' defined but not used
+../fh_registry.h:463: warning: `fh_get_GUIDEC2' defined but not used
+../fh_registry.h:463: warning: `fh_kw_GUIDEC2' defined but not used
+../fh_registry.h:463: warning: `fh_cmt_GUIDEC2' defined but not used
+../fh_registry.h:464: warning: `fh_set_GUIRAPM2' defined but not used
+../fh_registry.h:464: warning: `fh_setval_GUIRAPM2' defined but not used
+../fh_registry.h:464: warning: `fh_setcmt_GUIRAPM2' defined but not used
+../fh_registry.h:464: warning: `fh_get_GUIRAPM2' defined but not used
+../fh_registry.h:464: warning: `fh_kw_GUIRAPM2' defined but not used
+../fh_registry.h:464: warning: `fh_cmt_GUIRAPM2' defined but not used
+../fh_registry.h:465: warning: `fh_set_GUIDEPM2' defined but not used
+../fh_registry.h:465: warning: `fh_setval_GUIDEPM2' defined but not used
+../fh_registry.h:465: warning: `fh_setcmt_GUIDEPM2' defined but not used
+../fh_registry.h:465: warning: `fh_get_GUIDEPM2' defined but not used
+../fh_registry.h:465: warning: `fh_kw_GUIDEPM2' defined but not used
+../fh_registry.h:465: warning: `fh_cmt_GUIDEPM2' defined but not used
+../fh_registry.h:466: warning: `fh_set_GUIOBJN2' defined but not used
+../fh_registry.h:466: warning: `fh_setval_GUIOBJN2' defined but not used
+../fh_registry.h:466: warning: `fh_setcmt_GUIOBJN2' defined but not used
+../fh_registry.h:466: warning: `fh_get_GUIOBJN2' defined but not used
+../fh_registry.h:466: warning: `fh_kw_GUIOBJN2' defined but not used
+../fh_registry.h:466: warning: `fh_cmt_GUIOBJN2' defined but not used
+../fh_registry.h:467: warning: `fh_set_GUIMAGN2' defined but not used
+../fh_registry.h:467: warning: `fh_setval_GUIMAGN2' defined but not used
+../fh_registry.h:467: warning: `fh_setcmt_GUIMAGN2' defined but not used
+../fh_registry.h:467: warning: `fh_get_GUIMAGN2' defined but not used
+../fh_registry.h:467: warning: `fh_kw_GUIMAGN2' defined but not used
+../fh_registry.h:467: warning: `fh_cmt_GUIMAGN2' defined but not used
+../fh_registry.h:468: warning: `fh_set_GUIPOSX2' defined but not used
+../fh_registry.h:468: warning: `fh_setval_GUIPOSX2' defined but not used
+../fh_registry.h:468: warning: `fh_setcmt_GUIPOSX2' defined but not used
+../fh_registry.h:468: warning: `fh_get_GUIPOSX2' defined but not used
+../fh_registry.h:468: warning: `fh_kw_GUIPOSX2' defined but not used
+../fh_registry.h:468: warning: `fh_cmt_GUIPOSX2' defined but not used
+../fh_registry.h:469: warning: `fh_set_GUIPOSY2' defined but not used
+../fh_registry.h:469: warning: `fh_setval_GUIPOSY2' defined but not used
+../fh_registry.h:469: warning: `fh_setcmt_GUIPOSY2' defined but not used
+../fh_registry.h:469: warning: `fh_get_GUIPOSY2' defined but not used
+../fh_registry.h:469: warning: `fh_kw_GUIPOSY2' defined but not used
+../fh_registry.h:469: warning: `fh_cmt_GUIPOSY2' defined but not used
+../fh_registry.h:470: warning: `fh_set_GUIPOSZ2' defined but not used
+../fh_registry.h:470: warning: `fh_setval_GUIPOSZ2' defined but not used
+../fh_registry.h:470: warning: `fh_setcmt_GUIPOSZ2' defined but not used
+../fh_registry.h:470: warning: `fh_get_GUIPOSZ2' defined but not used
+../fh_registry.h:470: warning: `fh_kw_GUIPOSZ2' defined but not used
+../fh_registry.h:470: warning: `fh_cmt_GUIPOSZ2' defined but not used
+../fh_registry.h:471: warning: `fh_set_GUIFLUX2' defined but not used
+../fh_registry.h:471: warning: `fh_setval_GUIFLUX2' defined but not used
+../fh_registry.h:471: warning: `fh_setcmt_GUIFLUX2' defined but not used
+../fh_registry.h:471: warning: `fh_get_GUIFLUX2' defined but not used
+../fh_registry.h:471: warning: `fh_kw_GUIFLUX2' defined but not used
+../fh_registry.h:471: warning: `fh_cmt_GUIFLUX2' defined but not used
+../fh_registry.h:472: warning: `fh_set_GUIFWHX2' defined but not used
+../fh_registry.h:472: warning: `fh_setval_GUIFWHX2' defined but not used
+../fh_registry.h:472: warning: `fh_setcmt_GUIFWHX2' defined but not used
+../fh_registry.h:472: warning: `fh_get_GUIFWHX2' defined but not used
+../fh_registry.h:472: warning: `fh_kw_GUIFWHX2' defined but not used
+../fh_registry.h:472: warning: `fh_cmt_GUIFWHX2' defined but not used
+../fh_registry.h:473: warning: `fh_set_GUIFWHY2' defined but not used
+../fh_registry.h:473: warning: `fh_setval_GUIFWHY2' defined but not used
+../fh_registry.h:473: warning: `fh_setcmt_GUIFWHY2' defined but not used
+../fh_registry.h:473: warning: `fh_get_GUIFWHY2' defined but not used
+../fh_registry.h:473: warning: `fh_kw_GUIFWHY2' defined but not used
+../fh_registry.h:473: warning: `fh_cmt_GUIFWHY2' defined but not used
+../fh_registry.h:475: warning: `fh_set_GUINAME3' defined but not used
+../fh_registry.h:475: warning: `fh_setval_GUINAME3' defined but not used
+../fh_registry.h:475: warning: `fh_setcmt_GUINAME3' defined but not used
+../fh_registry.h:475: warning: `fh_get_GUINAME3' defined but not used
+../fh_registry.h:475: warning: `fh_kw_GUINAME3' defined but not used
+../fh_registry.h:475: warning: `fh_cmt_GUINAME3' defined but not used
+../fh_registry.h:476: warning: `fh_set_GUIEQUI3' defined but not used
+../fh_registry.h:476: warning: `fh_setcmt_GUIEQUI3' defined but not used
+../fh_registry.h:476: warning: `fh_kw_GUIEQUI3' defined but not used
+../fh_registry.h:476: warning: `fh_cmt_GUIEQUI3' defined but not used
+../fh_registry.h:477: warning: `fh_set_GUIRADE3' defined but not used
+../fh_registry.h:477: warning: `fh_setval_GUIRADE3' defined but not used
+../fh_registry.h:477: warning: `fh_setcmt_GUIRADE3' defined but not used
+../fh_registry.h:477: warning: `fh_get_GUIRADE3' defined but not used
+../fh_registry.h:477: warning: `fh_kw_GUIRADE3' defined but not used
+../fh_registry.h:477: warning: `fh_cmt_GUIRADE3' defined but not used
+../fh_registry.h:478: warning: `fh_set_GUIRA3' defined but not used
+../fh_registry.h:478: warning: `fh_setval_GUIRA3' defined but not used
+../fh_registry.h:478: warning: `fh_setcmt_GUIRA3' defined but not used
+../fh_registry.h:478: warning: `fh_get_GUIRA3' defined but not used
+../fh_registry.h:478: warning: `fh_kw_GUIRA3' defined but not used
+../fh_registry.h:478: warning: `fh_cmt_GUIRA3' defined but not used
+../fh_registry.h:479: warning: `fh_set_GUIDEC3' defined but not used
+../fh_registry.h:479: warning: `fh_setval_GUIDEC3' defined but not used
+../fh_registry.h:479: warning: `fh_setcmt_GUIDEC3' defined but not used
+../fh_registry.h:479: warning: `fh_get_GUIDEC3' defined but not used
+../fh_registry.h:479: warning: `fh_kw_GUIDEC3' defined but not used
+../fh_registry.h:479: warning: `fh_cmt_GUIDEC3' defined but not used
+../fh_registry.h:480: warning: `fh_set_GUIRAPM3' defined but not used
+../fh_registry.h:480: warning: `fh_setval_GUIRAPM3' defined but not used
+../fh_registry.h:480: warning: `fh_setcmt_GUIRAPM3' defined but not used
+../fh_registry.h:480: warning: `fh_get_GUIRAPM3' defined but not used
+../fh_registry.h:480: warning: `fh_kw_GUIRAPM3' defined but not used
+../fh_registry.h:480: warning: `fh_cmt_GUIRAPM3' defined but not used
+../fh_registry.h:481: warning: `fh_set_GUIDEPM3' defined but not used
+../fh_registry.h:481: warning: `fh_setval_GUIDEPM3' defined but not used
+../fh_registry.h:481: warning: `fh_setcmt_GUIDEPM3' defined but not used
+../fh_registry.h:481: warning: `fh_get_GUIDEPM3' defined but not used
+../fh_registry.h:481: warning: `fh_kw_GUIDEPM3' defined but not used
+../fh_registry.h:481: warning: `fh_cmt_GUIDEPM3' defined but not used
+../fh_registry.h:482: warning: `fh_set_GUIOBJN3' defined but not used
+../fh_registry.h:482: warning: `fh_setval_GUIOBJN3' defined but not used
+../fh_registry.h:482: warning: `fh_setcmt_GUIOBJN3' defined but not used
+../fh_registry.h:482: warning: `fh_get_GUIOBJN3' defined but not used
+../fh_registry.h:482: warning: `fh_kw_GUIOBJN3' defined but not used
+../fh_registry.h:482: warning: `fh_cmt_GUIOBJN3' defined but not used
+../fh_registry.h:483: warning: `fh_set_GUIMAGN3' defined but not used
+../fh_registry.h:483: warning: `fh_setval_GUIMAGN3' defined but not used
+../fh_registry.h:483: warning: `fh_setcmt_GUIMAGN3' defined but not used
+../fh_registry.h:483: warning: `fh_get_GUIMAGN3' defined but not used
+../fh_registry.h:483: warning: `fh_kw_GUIMAGN3' defined but not used
+../fh_registry.h:483: warning: `fh_cmt_GUIMAGN3' defined but not used
+../fh_registry.h:484: warning: `fh_set_GUIPOSX3' defined but not used
+../fh_registry.h:484: warning: `fh_setval_GUIPOSX3' defined but not used
+../fh_registry.h:484: warning: `fh_setcmt_GUIPOSX3' defined but not used
+../fh_registry.h:484: warning: `fh_get_GUIPOSX3' defined but not used
+../fh_registry.h:484: warning: `fh_kw_GUIPOSX3' defined but not used
+../fh_registry.h:484: warning: `fh_cmt_GUIPOSX3' defined but not used
+../fh_registry.h:485: warning: `fh_set_GUIPOSY3' defined but not used
+../fh_registry.h:485: warning: `fh_setval_GUIPOSY3' defined but not used
+../fh_registry.h:485: warning: `fh_setcmt_GUIPOSY3' defined but not used
+../fh_registry.h:485: warning: `fh_get_GUIPOSY3' defined but not used
+../fh_registry.h:485: warning: `fh_kw_GUIPOSY3' defined but not used
+../fh_registry.h:485: warning: `fh_cmt_GUIPOSY3' defined but not used
+../fh_registry.h:486: warning: `fh_set_GUIPOSZ3' defined but not used
+../fh_registry.h:486: warning: `fh_setval_GUIPOSZ3' defined but not used
+../fh_registry.h:486: warning: `fh_setcmt_GUIPOSZ3' defined but not used
+../fh_registry.h:486: warning: `fh_get_GUIPOSZ3' defined but not used
+../fh_registry.h:486: warning: `fh_kw_GUIPOSZ3' defined but not used
+../fh_registry.h:486: warning: `fh_cmt_GUIPOSZ3' defined but not used
+../fh_registry.h:487: warning: `fh_set_GUIFLUX3' defined but not used
+../fh_registry.h:487: warning: `fh_setval_GUIFLUX3' defined but not used
+../fh_registry.h:487: warning: `fh_setcmt_GUIFLUX3' defined but not used
+../fh_registry.h:487: warning: `fh_get_GUIFLUX3' defined but not used
+../fh_registry.h:487: warning: `fh_kw_GUIFLUX3' defined but not used
+../fh_registry.h:487: warning: `fh_cmt_GUIFLUX3' defined but not used
+../fh_registry.h:488: warning: `fh_set_GUIFWHX3' defined but not used
+../fh_registry.h:488: warning: `fh_setval_GUIFWHX3' defined but not used
+../fh_registry.h:488: warning: `fh_setcmt_GUIFWHX3' defined but not used
+../fh_registry.h:488: warning: `fh_get_GUIFWHX3' defined but not used
+../fh_registry.h:488: warning: `fh_kw_GUIFWHX3' defined but not used
+../fh_registry.h:488: warning: `fh_cmt_GUIFWHX3' defined but not used
+../fh_registry.h:489: warning: `fh_set_GUIFWHY3' defined but not used
+../fh_registry.h:489: warning: `fh_setval_GUIFWHY3' defined but not used
+../fh_registry.h:489: warning: `fh_setcmt_GUIFWHY3' defined but not used
+../fh_registry.h:489: warning: `fh_get_GUIFWHY3' defined but not used
+../fh_registry.h:489: warning: `fh_kw_GUIFWHY3' defined but not used
+../fh_registry.h:489: warning: `fh_cmt_GUIFWHY3' defined but not used
+../fh_registry.h:491: warning: `fh_set_GUINAME4' defined but not used
+../fh_registry.h:491: warning: `fh_setval_GUINAME4' defined but not used
+../fh_registry.h:491: warning: `fh_setcmt_GUINAME4' defined but not used
+../fh_registry.h:491: warning: `fh_get_GUINAME4' defined but not used
+../fh_registry.h:491: warning: `fh_kw_GUINAME4' defined but not used
+../fh_registry.h:491: warning: `fh_cmt_GUINAME4' defined but not used
+../fh_registry.h:492: warning: `fh_set_GUIEQUI4' defined but not used
+../fh_registry.h:492: warning: `fh_setcmt_GUIEQUI4' defined but not used
+../fh_registry.h:492: warning: `fh_kw_GUIEQUI4' defined but not used
+../fh_registry.h:492: warning: `fh_cmt_GUIEQUI4' defined but not used
+../fh_registry.h:493: warning: `fh_set_GUIRADE4' defined but not used
+../fh_registry.h:493: warning: `fh_setval_GUIRADE4' defined but not used
+../fh_registry.h:493: warning: `fh_setcmt_GUIRADE4' defined but not used
+../fh_registry.h:493: warning: `fh_get_GUIRADE4' defined but not used
+../fh_registry.h:493: warning: `fh_kw_GUIRADE4' defined but not used
+../fh_registry.h:493: warning: `fh_cmt_GUIRADE4' defined but not used
+../fh_registry.h:494: warning: `fh_set_GUIRA4' defined but not used
+../fh_registry.h:494: warning: `fh_setval_GUIRA4' defined but not used
+../fh_registry.h:494: warning: `fh_setcmt_GUIRA4' defined but not used
+../fh_registry.h:494: warning: `fh_get_GUIRA4' defined but not used
+../fh_registry.h:494: warning: `fh_kw_GUIRA4' defined but not used
+../fh_registry.h:494: warning: `fh_cmt_GUIRA4' defined but not used
+../fh_registry.h:495: warning: `fh_set_GUIDEC4' defined but not used
+../fh_registry.h:495: warning: `fh_setval_GUIDEC4' defined but not used
+../fh_registry.h:495: warning: `fh_setcmt_GUIDEC4' defined but not used
+../fh_registry.h:495: warning: `fh_get_GUIDEC4' defined but not used
+../fh_registry.h:495: warning: `fh_kw_GUIDEC4' defined but not used
+../fh_registry.h:495: warning: `fh_cmt_GUIDEC4' defined but not used
+../fh_registry.h:496: warning: `fh_set_GUIRAPM4' defined but not used
+../fh_registry.h:496: warning: `fh_setval_GUIRAPM4' defined but not used
+../fh_registry.h:496: warning: `fh_setcmt_GUIRAPM4' defined but not used
+../fh_registry.h:496: warning: `fh_get_GUIRAPM4' defined but not used
+../fh_registry.h:496: warning: `fh_kw_GUIRAPM4' defined but not used
+../fh_registry.h:496: warning: `fh_cmt_GUIRAPM4' defined but not used
+../fh_registry.h:497: warning: `fh_set_GUIDEPM4' defined but not used
+../fh_registry.h:497: warning: `fh_setval_GUIDEPM4' defined but not used
+../fh_registry.h:497: warning: `fh_setcmt_GUIDEPM4' defined but not used
+../fh_registry.h:497: warning: `fh_get_GUIDEPM4' defined but not used
+../fh_registry.h:497: warning: `fh_kw_GUIDEPM4' defined but not used
+../fh_registry.h:497: warning: `fh_cmt_GUIDEPM4' defined but not used
+../fh_registry.h:498: warning: `fh_set_GUIOBJN4' defined but not used
+../fh_registry.h:498: warning: `fh_setval_GUIOBJN4' defined but not used
+../fh_registry.h:498: warning: `fh_setcmt_GUIOBJN4' defined but not used
+../fh_registry.h:498: warning: `fh_get_GUIOBJN4' defined but not used
+../fh_registry.h:498: warning: `fh_kw_GUIOBJN4' defined but not used
+../fh_registry.h:498: warning: `fh_cmt_GUIOBJN4' defined but not used
+../fh_registry.h:499: warning: `fh_set_GUIMAGN4' defined but not used
+../fh_registry.h:499: warning: `fh_setval_GUIMAGN4' defined but not used
+../fh_registry.h:499: warning: `fh_setcmt_GUIMAGN4' defined but not used
+../fh_registry.h:499: warning: `fh_get_GUIMAGN4' defined but not used
+../fh_registry.h:499: warning: `fh_kw_GUIMAGN4' defined but not used
+../fh_registry.h:499: warning: `fh_cmt_GUIMAGN4' defined but not used
+../fh_registry.h:500: warning: `fh_set_GUIPOSX4' defined but not used
+../fh_registry.h:500: warning: `fh_setval_GUIPOSX4' defined but not used
+../fh_registry.h:500: warning: `fh_setcmt_GUIPOSX4' defined but not used
+../fh_registry.h:500: warning: `fh_get_GUIPOSX4' defined but not used
+../fh_registry.h:500: warning: `fh_kw_GUIPOSX4' defined but not used
+../fh_registry.h:500: warning: `fh_cmt_GUIPOSX4' defined but not used
+../fh_registry.h:501: warning: `fh_set_GUIPOSY4' defined but not used
+../fh_registry.h:501: warning: `fh_setval_GUIPOSY4' defined but not used
+../fh_registry.h:501: warning: `fh_setcmt_GUIPOSY4' defined but not used
+../fh_registry.h:501: warning: `fh_get_GUIPOSY4' defined but not used
+../fh_registry.h:501: warning: `fh_kw_GUIPOSY4' defined but not used
+../fh_registry.h:501: warning: `fh_cmt_GUIPOSY4' defined but not used
+../fh_registry.h:502: warning: `fh_set_GUIPOSZ4' defined but not used
+../fh_registry.h:502: warning: `fh_setval_GUIPOSZ4' defined but not used
+../fh_registry.h:502: warning: `fh_setcmt_GUIPOSZ4' defined but not used
+../fh_registry.h:502: warning: `fh_get_GUIPOSZ4' defined but not used
+../fh_registry.h:502: warning: `fh_kw_GUIPOSZ4' defined but not used
+../fh_registry.h:502: warning: `fh_cmt_GUIPOSZ4' defined but not used
+../fh_registry.h:503: warning: `fh_set_GUIFLUX4' defined but not used
+../fh_registry.h:503: warning: `fh_setval_GUIFLUX4' defined but not used
+../fh_registry.h:503: warning: `fh_setcmt_GUIFLUX4' defined but not used
+../fh_registry.h:503: warning: `fh_get_GUIFLUX4' defined but not used
+../fh_registry.h:503: warning: `fh_kw_GUIFLUX4' defined but not used
+../fh_registry.h:503: warning: `fh_cmt_GUIFLUX4' defined but not used
+../fh_registry.h:504: warning: `fh_set_GUIFWHX4' defined but not used
+../fh_registry.h:504: warning: `fh_setval_GUIFWHX4' defined but not used
+../fh_registry.h:504: warning: `fh_setcmt_GUIFWHX4' defined but not used
+../fh_registry.h:504: warning: `fh_get_GUIFWHX4' defined but not used
+../fh_registry.h:504: warning: `fh_kw_GUIFWHX4' defined but not used
+../fh_registry.h:504: warning: `fh_cmt_GUIFWHX4' defined but not used
+../fh_registry.h:505: warning: `fh_set_GUIFWHY4' defined but not used
+../fh_registry.h:505: warning: `fh_setval_GUIFWHY4' defined but not used
+../fh_registry.h:505: warning: `fh_setcmt_GUIFWHY4' defined but not used
+../fh_registry.h:505: warning: `fh_get_GUIFWHY4' defined but not used
+../fh_registry.h:505: warning: `fh_kw_GUIFWHY4' defined but not used
+../fh_registry.h:505: warning: `fh_cmt_GUIFWHY4' defined but not used
+../fh_registry.h:507: warning: `fh_set_AIRMASS' defined but not used
+../fh_registry.h:507: warning: `fh_setval_AIRMASS' defined but not used
+../fh_registry.h:507: warning: `fh_setcmt_AIRMASS' defined but not used
+../fh_registry.h:507: warning: `fh_get_AIRMASS' defined but not used
+../fh_registry.h:507: warning: `fh_kw_AIRMASS' defined but not used
+../fh_registry.h:507: warning: `fh_cmt_AIRMASS' defined but not used
+../fh_registry.h:508: warning: `fh_set_TELALT' defined but not used
+../fh_registry.h:508: warning: `fh_setval_TELALT' defined but not used
+../fh_registry.h:508: warning: `fh_setcmt_TELALT' defined but not used
+../fh_registry.h:508: warning: `fh_get_TELALT' defined but not used
+../fh_registry.h:508: warning: `fh_kw_TELALT' defined but not used
+../fh_registry.h:508: warning: `fh_cmt_TELALT' defined but not used
+../fh_registry.h:509: warning: `fh_set_TELAZ' defined but not used
+../fh_registry.h:509: warning: `fh_setval_TELAZ' defined but not used
+../fh_registry.h:509: warning: `fh_setcmt_TELAZ' defined but not used
+../fh_registry.h:509: warning: `fh_get_TELAZ' defined but not used
+../fh_registry.h:509: warning: `fh_kw_TELAZ' defined but not used
+../fh_registry.h:509: warning: `fh_cmt_TELAZ' defined but not used
+../fh_registry.h:510: warning: `fh_set_MOONANGL' defined but not used
+../fh_registry.h:510: warning: `fh_setval_MOONANGL' defined but not used
+../fh_registry.h:510: warning: `fh_setcmt_MOONANGL' defined but not used
+../fh_registry.h:510: warning: `fh_get_MOONANGL' defined but not used
+../fh_registry.h:510: warning: `fh_kw_MOONANGL' defined but not used
+../fh_registry.h:510: warning: `fh_cmt_MOONANGL' defined but not used
+../fh_registry.h:511: warning: `fh_set_FOCUSID' defined but not used
+../fh_registry.h:511: warning: `fh_setval_FOCUSID' defined but not used
+../fh_registry.h:511: warning: `fh_setcmt_FOCUSID' defined but not used
+../fh_registry.h:511: warning: `fh_get_FOCUSID' defined but not used
+../fh_registry.h:511: warning: `fh_kw_FOCUSID' defined but not used
+../fh_registry.h:511: warning: `fh_cmt_FOCUSID' defined but not used
+../fh_registry.h:512: warning: `fh_set_TELCONF' defined but not used
+../fh_registry.h:512: warning: `fh_setval_TELCONF' defined but not used
+../fh_registry.h:512: warning: `fh_setcmt_TELCONF' defined but not used
+../fh_registry.h:512: warning: `fh_get_TELCONF' defined but not used
+../fh_registry.h:512: warning: `fh_kw_TELCONF' defined but not used
+../fh_registry.h:512: warning: `fh_cmt_TELCONF' defined but not used
+../fh_registry.h:513: warning: `fh_set_FOCUSPOS' defined but not used
+../fh_registry.h:513: warning: `fh_setval_FOCUSPOS' defined but not used
+../fh_registry.h:513: warning: `fh_setcmt_FOCUSPOS' defined but not used
+../fh_registry.h:513: warning: `fh_get_FOCUSPOS' defined but not used
+../fh_registry.h:513: warning: `fh_kw_FOCUSPOS' defined but not used
+../fh_registry.h:513: warning: `fh_cmt_FOCUSPOS' defined but not used
+../fh_registry.h:514: warning: `fh_set_TELFOCUS' defined but not used
+../fh_registry.h:514: warning: `fh_setval_TELFOCUS' defined but not used
+../fh_registry.h:514: warning: `fh_setcmt_TELFOCUS' defined but not used
+../fh_registry.h:514: warning: `fh_get_TELFOCUS' defined but not used
+../fh_registry.h:514: warning: `fh_kw_TELFOCUS' defined but not used
+../fh_registry.h:514: warning: `fh_cmt_TELFOCUS' defined but not used
+../fh_registry.h:515: warning: `fh_set_BONANGLE' defined but not used
+../fh_registry.h:515: warning: `fh_setval_BONANGLE' defined but not used
+../fh_registry.h:515: warning: `fh_setcmt_BONANGLE' defined but not used
+../fh_registry.h:515: warning: `fh_get_BONANGLE' defined but not used
+../fh_registry.h:515: warning: `fh_kw_BONANGLE' defined but not used
+../fh_registry.h:515: warning: `fh_cmt_BONANGLE' defined but not used
+../fh_registry.h:516: warning: `fh_set_ROTANGLE' defined but not used
+../fh_registry.h:516: warning: `fh_setval_ROTANGLE' defined but not used
+../fh_registry.h:516: warning: `fh_setcmt_ROTANGLE' defined but not used
+../fh_registry.h:516: warning: `fh_get_ROTANGLE' defined but not used
+../fh_registry.h:516: warning: `fh_kw_ROTANGLE' defined but not used
+../fh_registry.h:516: warning: `fh_cmt_ROTANGLE' defined but not used
+../fh_registry.h:524: warning: `fh_set_ISUGAIN' defined but not used
+../fh_registry.h:524: warning: `fh_setval_ISUGAIN' defined but not used
+../fh_registry.h:524: warning: `fh_setcmt_ISUGAIN' defined but not used
+../fh_registry.h:524: warning: `fh_get_ISUGAIN' defined but not used
+../fh_registry.h:524: warning: `fh_kw_ISUGAIN' defined but not used
+../fh_registry.h:524: warning: `fh_cmt_ISUGAIN' defined but not used
+../fh_registry.h:525: warning: `fh_set_ISURATE' defined but not used
+../fh_registry.h:525: warning: `fh_setval_ISURATE' defined but not used
+../fh_registry.h:525: warning: `fh_setcmt_ISURATE' defined but not used
+../fh_registry.h:525: warning: `fh_get_ISURATE' defined but not used
+../fh_registry.h:525: warning: `fh_kw_ISURATE' defined but not used
+../fh_registry.h:525: warning: `fh_cmt_ISURATE' defined but not used
+../fh_registry.h:526: warning: `fh_set_ISUTCSOR' defined but not used
+../fh_registry.h:526: warning: `fh_setval_ISUTCSOR' defined but not used
+../fh_registry.h:526: warning: `fh_setcmt_ISUTCSOR' defined but not used
+../fh_registry.h:526: warning: `fh_get_ISUTCSOR' defined but not used
+../fh_registry.h:526: warning: `fh_kw_ISUTCSOR' defined but not used
+../fh_registry.h:526: warning: `fh_cmt_ISUTCSOR' defined but not used
+../fh_registry.h:527: warning: `fh_set_ISUSTATE' defined but not used
+../fh_registry.h:527: warning: `fh_setval_ISUSTATE' defined but not used
+../fh_registry.h:527: warning: `fh_setcmt_ISUSTATE' defined but not used
+../fh_registry.h:527: warning: `fh_get_ISUSTATE' defined but not used
+../fh_registry.h:527: warning: `fh_kw_ISUSTATE' defined but not used
+../fh_registry.h:527: warning: `fh_cmt_ISUSTATE' defined but not used
+../fh_registry.h:528: warning: `fh_set_ISUSTDVX' defined but not used
+../fh_registry.h:528: warning: `fh_setval_ISUSTDVX' defined but not used
+../fh_registry.h:528: warning: `fh_setcmt_ISUSTDVX' defined but not used
+../fh_registry.h:528: warning: `fh_get_ISUSTDVX' defined but not used
+../fh_registry.h:528: warning: `fh_kw_ISUSTDVX' defined but not used
+../fh_registry.h:528: warning: `fh_cmt_ISUSTDVX' defined but not used
+../fh_registry.h:529: warning: `fh_set_ISUSTDVY' defined but not used
+../fh_registry.h:529: warning: `fh_setval_ISUSTDVY' defined but not used
+../fh_registry.h:529: warning: `fh_setcmt_ISUSTDVY' defined but not used
+../fh_registry.h:529: warning: `fh_get_ISUSTDVY' defined but not used
+../fh_registry.h:529: warning: `fh_kw_ISUSTDVY' defined but not used
+../fh_registry.h:529: warning: `fh_cmt_ISUSTDVY' defined but not used
+../fh_registry.h:537: warning: `fh_set_FSAGAIN' defined but not used
+../fh_registry.h:537: warning: `fh_setval_FSAGAIN' defined but not used
+../fh_registry.h:537: warning: `fh_setcmt_FSAGAIN' defined but not used
+../fh_registry.h:537: warning: `fh_get_FSAGAIN' defined but not used
+../fh_registry.h:537: warning: `fh_kw_FSAGAIN' defined but not used
+../fh_registry.h:537: warning: `fh_cmt_FSAGAIN' defined but not used
+../fh_registry.h:538: warning: `fh_set_FSARATE' defined but not used
+../fh_registry.h:538: warning: `fh_setval_FSARATE' defined but not used
+../fh_registry.h:538: warning: `fh_setcmt_FSARATE' defined but not used
+../fh_registry.h:538: warning: `fh_get_FSARATE' defined but not used
+../fh_registry.h:538: warning: `fh_kw_FSARATE' defined but not used
+../fh_registry.h:538: warning: `fh_cmt_FSARATE' defined but not used
+../fh_registry.h:539: warning: `fh_set_FSATHRES' defined but not used
+../fh_registry.h:539: warning: `fh_setval_FSATHRES' defined but not used
+../fh_registry.h:539: warning: `fh_setcmt_FSATHRES' defined but not used
+../fh_registry.h:539: warning: `fh_get_FSATHRES' defined but not used
+../fh_registry.h:539: warning: `fh_kw_FSATHRES' defined but not used
+../fh_registry.h:539: warning: `fh_cmt_FSATHRES' defined but not used
+../fh_registry.h:540: warning: `fh_set_FSASTATE' defined but not used
+../fh_registry.h:540: warning: `fh_setval_FSASTATE' defined but not used
+../fh_registry.h:540: warning: `fh_setcmt_FSASTATE' defined but not used
+../fh_registry.h:540: warning: `fh_get_FSASTATE' defined but not used
+../fh_registry.h:540: warning: `fh_kw_FSASTATE' defined but not used
+../fh_registry.h:540: warning: `fh_cmt_FSASTATE' defined but not used
+../fh_registry.h:541: warning: `fh_set_FSANMOVE' defined but not used
+../fh_registry.h:541: warning: `fh_setval_FSANMOVE' defined but not used
+../fh_registry.h:541: warning: `fh_setcmt_FSANMOVE' defined but not used
+../fh_registry.h:541: warning: `fh_get_FSANMOVE' defined but not used
+../fh_registry.h:541: warning: `fh_kw_FSANMOVE' defined but not used
+../fh_registry.h:541: warning: `fh_cmt_FSANMOVE' defined but not used
+../fh_registry.h:542: warning: `fh_set_FSAMINZ' defined but not used
+../fh_registry.h:542: warning: `fh_setval_FSAMINZ' defined but not used
+../fh_registry.h:542: warning: `fh_setcmt_FSAMINZ' defined but not used
+../fh_registry.h:542: warning: `fh_get_FSAMINZ' defined but not used
+../fh_registry.h:542: warning: `fh_kw_FSAMINZ' defined but not used
+../fh_registry.h:542: warning: `fh_cmt_FSAMINZ' defined but not used
+../fh_registry.h:543: warning: `fh_set_FSAMAXZ' defined but not used
+../fh_registry.h:543: warning: `fh_setval_FSAMAXZ' defined but not used
+../fh_registry.h:543: warning: `fh_setcmt_FSAMAXZ' defined but not used
+../fh_registry.h:543: warning: `fh_get_FSAMAXZ' defined but not used
+../fh_registry.h:543: warning: `fh_kw_FSAMAXZ' defined but not used
+../fh_registry.h:543: warning: `fh_cmt_FSAMAXZ' defined but not used
+../fh_registry.h:544: warning: `fh_set_FSAMEANZ' defined but not used
+../fh_registry.h:544: warning: `fh_setval_FSAMEANZ' defined but not used
+../fh_registry.h:544: warning: `fh_setcmt_FSAMEANZ' defined but not used
+../fh_registry.h:544: warning: `fh_get_FSAMEANZ' defined but not used
+../fh_registry.h:544: warning: `fh_kw_FSAMEANZ' defined but not used
+../fh_registry.h:544: warning: `fh_cmt_FSAMEANZ' defined but not used
+../fh_registry.h:545: warning: `fh_set_FSASTDVZ' defined but not used
+../fh_registry.h:545: warning: `fh_setval_FSASTDVZ' defined but not used
+../fh_registry.h:545: warning: `fh_setcmt_FSASTDVZ' defined but not used
+../fh_registry.h:545: warning: `fh_get_FSASTDVZ' defined but not used
+../fh_registry.h:545: warning: `fh_kw_FSASTDVZ' defined but not used
+../fh_registry.h:545: warning: `fh_cmt_FSASTDVZ' defined but not used
+../fh_registry.h:553: warning: `fh_set_TCSGPSBC' defined but not used
+../fh_registry.h:553: warning: `fh_setval_TCSGPSBC' defined but not used
+../fh_registry.h:553: warning: `fh_setcmt_TCSGPSBC' defined but not used
+../fh_registry.h:553: warning: `fh_get_TCSGPSBC' defined but not used
+../fh_registry.h:553: warning: `fh_kw_TCSGPSBC' defined but not used
+../fh_registry.h:553: warning: `fh_cmt_TCSGPSBC' defined but not used
+../fh_registry.h:554: warning: `fh_set_TCSGPSTM' defined but not used
+../fh_registry.h:554: warning: `fh_setval_TCSGPSTM' defined but not used
+../fh_registry.h:554: warning: `fh_setcmt_TCSGPSTM' defined but not used
+../fh_registry.h:554: warning: `fh_get_TCSGPSTM' defined but not used
+../fh_registry.h:554: warning: `fh_kw_TCSGPSTM' defined but not used
+../fh_registry.h:554: warning: `fh_cmt_TCSGPSTM' defined but not used
+../fh_registry.h:555: warning: `fh_set_TCSRBUSS' defined but not used
+../fh_registry.h:555: warning: `fh_setval_TCSRBUSS' defined but not used
+../fh_registry.h:555: warning: `fh_setcmt_TCSRBUSS' defined but not used
+../fh_registry.h:555: warning: `fh_get_TCSRBUSS' defined but not used
+../fh_registry.h:555: warning: `fh_kw_TCSRBUSS' defined but not used
+../fh_registry.h:555: warning: `fh_cmt_TCSRBUSS' defined but not used
+../fh_registry.h:556: warning: `fh_set_TCSEPICS' defined but not used
+../fh_registry.h:556: warning: `fh_setval_TCSEPICS' defined but not used
+../fh_registry.h:556: warning: `fh_setcmt_TCSEPICS' defined but not used
+../fh_registry.h:556: warning: `fh_get_TCSEPICS' defined but not used
+../fh_registry.h:556: warning: `fh_kw_TCSEPICS' defined but not used
+../fh_registry.h:556: warning: `fh_cmt_TCSEPICS' defined but not used
+../fh_registry.h:557: warning: `fh_set_TCSAMODE' defined but not used
+../fh_registry.h:557: warning: `fh_setval_TCSAMODE' defined but not used
+../fh_registry.h:557: warning: `fh_setcmt_TCSAMODE' defined but not used
+../fh_registry.h:557: warning: `fh_get_TCSAMODE' defined but not used
+../fh_registry.h:557: warning: `fh_kw_TCSAMODE' defined but not used
+../fh_registry.h:557: warning: `fh_cmt_TCSAMODE' defined but not used
+../fh_registry.h:558: warning: `fh_set_TCSMJD' defined but not used
+../fh_registry.h:558: warning: `fh_setval_TCSMJD' defined but not used
+../fh_registry.h:558: warning: `fh_setcmt_TCSMJD' defined but not used
+../fh_registry.h:558: warning: `fh_get_TCSMJD' defined but not used
+../fh_registry.h:558: warning: `fh_kw_TCSMJD' defined but not used
+../fh_registry.h:558: warning: `fh_cmt_TCSMJD' defined but not used
+../fh_registry.h:559: warning: `fh_set_TCSLST' defined but not used
+../fh_registry.h:559: warning: `fh_setval_TCSLST' defined but not used
+../fh_registry.h:559: warning: `fh_setcmt_TCSLST' defined but not used
+../fh_registry.h:559: warning: `fh_get_TCSLST' defined but not used
+../fh_registry.h:559: warning: `fh_kw_TCSLST' defined but not used
+../fh_registry.h:559: warning: `fh_cmt_TCSLST' defined but not used
+../fh_registry.h:560: warning: `fh_set_TCSAPHA' defined but not used
+../fh_registry.h:560: warning: `fh_setval_TCSAPHA' defined but not used
+../fh_registry.h:560: warning: `fh_setcmt_TCSAPHA' defined but not used
+../fh_registry.h:560: warning: `fh_get_TCSAPHA' defined but not used
+../fh_registry.h:560: warning: `fh_kw_TCSAPHA' defined but not used
+../fh_registry.h:560: warning: `fh_cmt_TCSAPHA' defined but not used
+../fh_registry.h:561: warning: `fh_set_TCSAPDEC' defined but not used
+../fh_registry.h:561: warning: `fh_setval_TCSAPDEC' defined but not used
+../fh_registry.h:561: warning: `fh_setcmt_TCSAPDEC' defined but not used
+../fh_registry.h:561: warning: `fh_get_TCSAPDEC' defined but not used
+../fh_registry.h:561: warning: `fh_kw_TCSAPDEC' defined but not used
+../fh_registry.h:561: warning: `fh_cmt_TCSAPDEC' defined but not used
+../fh_registry.h:562: warning: `fh_set_TCSOBHA' defined but not used
+../fh_registry.h:562: warning: `fh_setval_TCSOBHA' defined but not used
+../fh_registry.h:562: warning: `fh_setcmt_TCSOBHA' defined but not used
+../fh_registry.h:562: warning: `fh_get_TCSOBHA' defined but not used
+../fh_registry.h:562: warning: `fh_kw_TCSOBHA' defined but not used
+../fh_registry.h:562: warning: `fh_cmt_TCSOBHA' defined but not used
+../fh_registry.h:563: warning: `fh_set_TCSOBDEC' defined but not used
+../fh_registry.h:563: warning: `fh_setval_TCSOBDEC' defined but not used
+../fh_registry.h:563: warning: `fh_setcmt_TCSOBDEC' defined but not used
+../fh_registry.h:563: warning: `fh_get_TCSOBDEC' defined but not used
+../fh_registry.h:563: warning: `fh_kw_TCSOBDEC' defined but not used
+../fh_registry.h:563: warning: `fh_cmt_TCSOBDEC' defined but not used
+../fh_registry.h:564: warning: `fh_set_TCSENHA' defined but not used
+../fh_registry.h:564: warning: `fh_setval_TCSENHA' defined but not used
+../fh_registry.h:564: warning: `fh_setcmt_TCSENHA' defined but not used
+../fh_registry.h:564: warning: `fh_get_TCSENHA' defined but not used
+../fh_registry.h:564: warning: `fh_kw_TCSENHA' defined but not used
+../fh_registry.h:564: warning: `fh_cmt_TCSENHA' defined but not used
+../fh_registry.h:565: warning: `fh_set_TCSENDEC' defined but not used
+../fh_registry.h:565: warning: `fh_setval_TCSENDEC' defined but not used
+../fh_registry.h:565: warning: `fh_setcmt_TCSENDEC' defined but not used
+../fh_registry.h:565: warning: `fh_get_TCSENDEC' defined but not used
+../fh_registry.h:565: warning: `fh_kw_TCSENDEC' defined but not used
+../fh_registry.h:565: warning: `fh_cmt_TCSENDEC' defined but not used
+../fh_registry.h:566: warning: `fh_set_TCSEDHA' defined but not used
+../fh_registry.h:566: warning: `fh_setval_TCSEDHA' defined but not used
+../fh_registry.h:566: warning: `fh_setcmt_TCSEDHA' defined but not used
+../fh_registry.h:566: warning: `fh_get_TCSEDHA' defined but not used
+../fh_registry.h:566: warning: `fh_kw_TCSEDHA' defined but not used
+../fh_registry.h:566: warning: `fh_cmt_TCSEDHA' defined but not used
+../fh_registry.h:567: warning: `fh_set_TCSEDDEC' defined but not used
+../fh_registry.h:567: warning: `fh_setval_TCSEDDEC' defined but not used
+../fh_registry.h:567: warning: `fh_setcmt_TCSEDDEC' defined but not used
+../fh_registry.h:567: warning: `fh_get_TCSEDDEC' defined but not used
+../fh_registry.h:567: warning: `fh_kw_TCSEDDEC' defined but not used
+../fh_registry.h:567: warning: `fh_cmt_TCSEDDEC' defined but not used
+../fh_registry.h:568: warning: `fh_set_TCSMVRA' defined but not used
+../fh_registry.h:568: warning: `fh_setval_TCSMVRA' defined but not used
+../fh_registry.h:568: warning: `fh_setcmt_TCSMVRA' defined but not used
+../fh_registry.h:568: warning: `fh_get_TCSMVRA' defined but not used
+../fh_registry.h:568: warning: `fh_kw_TCSMVRA' defined but not used
+../fh_registry.h:568: warning: `fh_cmt_TCSMVRA' defined but not used
+../fh_registry.h:569: warning: `fh_set_TCSMVDEC' defined but not used
+../fh_registry.h:569: warning: `fh_setval_TCSMVDEC' defined but not used
+../fh_registry.h:569: warning: `fh_setcmt_TCSMVDEC' defined but not used
+../fh_registry.h:569: warning: `fh_get_TCSMVDEC' defined but not used
+../fh_registry.h:569: warning: `fh_kw_TCSMVDEC' defined but not used
+../fh_registry.h:569: warning: `fh_cmt_TCSMVDEC' defined but not used
+../fh_registry.h:570: warning: `fh_set_TCSMVX' defined but not used
+../fh_registry.h:570: warning: `fh_setval_TCSMVX' defined but not used
+../fh_registry.h:570: warning: `fh_setcmt_TCSMVX' defined but not used
+../fh_registry.h:570: warning: `fh_get_TCSMVX' defined but not used
+../fh_registry.h:570: warning: `fh_kw_TCSMVX' defined but not used
+../fh_registry.h:570: warning: `fh_cmt_TCSMVX' defined but not used
+../fh_registry.h:571: warning: `fh_set_TCSMVY' defined but not used
+../fh_registry.h:571: warning: `fh_setval_TCSMVY' defined but not used
+../fh_registry.h:571: warning: `fh_setcmt_TCSMVY' defined but not used
+../fh_registry.h:571: warning: `fh_get_TCSMVY' defined but not used
+../fh_registry.h:571: warning: `fh_kw_TCSMVY' defined but not used
+../fh_registry.h:571: warning: `fh_cmt_TCSMVY' defined but not used
+../fh_registry.h:579: warning: `fh_set_CMTAOB1' defined but not used
+../fh_registry.h:580: warning: `fh_set_CMTAOB2' defined but not used
+../fh_registry.h:581: warning: `fh_set_CMTAOB3' defined but not used
+../fh_registry.h:582: warning: `fh_set_CMTAOB4' defined but not used
+../fh_registry.h:590: warning: `fh_set_AOBLOOP' defined but not used
+../fh_registry.h:590: warning: `fh_setval_AOBLOOP' defined but not used
+../fh_registry.h:590: warning: `fh_setcmt_AOBLOOP' defined but not used
+../fh_registry.h:590: warning: `fh_get_AOBLOOP' defined but not used
+../fh_registry.h:590: warning: `fh_kw_AOBLOOP' defined but not used
+../fh_registry.h:590: warning: `fh_cmt_AOBLOOP' defined but not used
+../fh_registry.h:594: warning: `fh_set_LOOPGAIN' defined but not used
+../fh_registry.h:594: warning: `fh_setval_LOOPGAIN' defined but not used
+../fh_registry.h:594: warning: `fh_setcmt_LOOPGAIN' defined but not used
+../fh_registry.h:594: warning: `fh_get_LOOPGAIN' defined but not used
+../fh_registry.h:594: warning: `fh_kw_LOOPGAIN' defined but not used
+../fh_registry.h:594: warning: `fh_cmt_LOOPGAIN' defined but not used
+../fh_registry.h:601: warning: `fh_set_LOOPNES' defined but not used
+../fh_registry.h:601: warning: `fh_setval_LOOPNES' defined but not used
+../fh_registry.h:601: warning: `fh_setcmt_LOOPNES' defined but not used
+../fh_registry.h:601: warning: `fh_get_LOOPNES' defined but not used
+../fh_registry.h:601: warning: `fh_kw_LOOPNES' defined but not used
+../fh_registry.h:601: warning: `fh_cmt_LOOPNES' defined but not used
+../fh_registry.h:606: warning: `fh_set_LOOPNESG' defined but not used
+../fh_registry.h:606: warning: `fh_setval_LOOPNESG' defined but not used
+../fh_registry.h:606: warning: `fh_setcmt_LOOPNESG' defined but not used
+../fh_registry.h:606: warning: `fh_get_LOOPNESG' defined but not used
+../fh_registry.h:606: warning: `fh_kw_LOOPNESG' defined but not used
+../fh_registry.h:606: warning: `fh_cmt_LOOPNESG' defined but not used
+../fh_registry.h:611: warning: `fh_set_LOOPOPT' defined but not used
+../fh_registry.h:611: warning: `fh_setval_LOOPOPT' defined but not used
+../fh_registry.h:611: warning: `fh_setcmt_LOOPOPT' defined but not used
+../fh_registry.h:611: warning: `fh_get_LOOPOPT' defined but not used
+../fh_registry.h:611: warning: `fh_kw_LOOPOPT' defined but not used
+../fh_registry.h:611: warning: `fh_cmt_LOOPOPT' defined but not used
+../fh_registry.h:615: warning: `fh_set_WFSGOPT' defined but not used
+../fh_registry.h:615: warning: `fh_setval_WFSGOPT' defined but not used
+../fh_registry.h:615: warning: `fh_setcmt_WFSGOPT' defined but not used
+../fh_registry.h:615: warning: `fh_get_WFSGOPT' defined but not used
+../fh_registry.h:615: warning: `fh_kw_WFSGOPT' defined but not used
+../fh_registry.h:615: warning: `fh_cmt_WFSGOPT' defined but not used
+../fh_registry.h:619: warning: `fh_set_WFSSAMP' defined but not used
+../fh_registry.h:619: warning: `fh_setval_WFSSAMP' defined but not used
+../fh_registry.h:619: warning: `fh_setcmt_WFSSAMP' defined but not used
+../fh_registry.h:619: warning: `fh_get_WFSSAMP' defined but not used
+../fh_registry.h:619: warning: `fh_kw_WFSSAMP' defined but not used
+../fh_registry.h:619: warning: `fh_cmt_WFSSAMP' defined but not used
+../fh_registry.h:626: warning: `fh_set_R0' defined but not used
+../fh_registry.h:626: warning: `fh_setval_R0' defined but not used
+../fh_registry.h:626: warning: `fh_setcmt_R0' defined but not used
+../fh_registry.h:626: warning: `fh_get_R0' defined but not used
+../fh_registry.h:626: warning: `fh_kw_R0' defined but not used
+../fh_registry.h:626: warning: `fh_cmt_R0' defined but not used
+../fh_registry.h:630: warning: `fh_set_WFSCOUNT' defined but not used
+../fh_registry.h:630: warning: `fh_setval_WFSCOUNT' defined but not used
+../fh_registry.h:630: warning: `fh_setcmt_WFSCOUNT' defined but not used
+../fh_registry.h:630: warning: `fh_get_WFSCOUNT' defined but not used
+../fh_registry.h:630: warning: `fh_kw_WFSCOUNT' defined but not used
+../fh_registry.h:630: warning: `fh_cmt_WFSCOUNT' defined but not used
+../fh_registry.h:638: warning: `fh_set_ADCPOS' defined but not used
+../fh_registry.h:638: warning: `fh_setval_ADCPOS' defined but not used
+../fh_registry.h:638: warning: `fh_setcmt_ADCPOS' defined but not used
+../fh_registry.h:638: warning: `fh_get_ADCPOS' defined but not used
+../fh_registry.h:638: warning: `fh_kw_ADCPOS' defined but not used
+../fh_registry.h:638: warning: `fh_cmt_ADCPOS' defined but not used
+../fh_registry.h:642: warning: `fh_set_ADCANGLE' defined but not used
+../fh_registry.h:642: warning: `fh_setval_ADCANGLE' defined but not used
+../fh_registry.h:642: warning: `fh_setcmt_ADCANGLE' defined but not used
+../fh_registry.h:642: warning: `fh_get_ADCANGLE' defined but not used
+../fh_registry.h:642: warning: `fh_kw_ADCANGLE' defined but not used
+../fh_registry.h:642: warning: `fh_cmt_ADCANGLE' defined but not used
+../fh_registry.h:646: warning: `fh_set_ADCPOWER' defined but not used
+../fh_registry.h:646: warning: `fh_setval_ADCPOWER' defined but not used
+../fh_registry.h:646: warning: `fh_setcmt_ADCPOWER' defined but not used
+../fh_registry.h:646: warning: `fh_get_ADCPOWER' defined but not used
+../fh_registry.h:646: warning: `fh_kw_ADCPOWER' defined but not used
+../fh_registry.h:646: warning: `fh_cmt_ADCPOWER' defined but not used
+../fh_registry.h:650: warning: `fh_set_BEAMSPID' defined but not used
+../fh_registry.h:650: warning: `fh_setval_BEAMSPID' defined but not used
+../fh_registry.h:650: warning: `fh_setcmt_BEAMSPID' defined but not used
+../fh_registry.h:650: warning: `fh_get_BEAMSPID' defined but not used
+../fh_registry.h:650: warning: `fh_kw_BEAMSPID' defined but not used
+../fh_registry.h:650: warning: `fh_cmt_BEAMSPID' defined but not used
+../fh_registry.h:654: warning: `fh_set_BEAMSP' defined but not used
+../fh_registry.h:654: warning: `fh_setval_BEAMSP' defined but not used
+../fh_registry.h:654: warning: `fh_setcmt_BEAMSP' defined but not used
+../fh_registry.h:654: warning: `fh_get_BEAMSP' defined but not used
+../fh_registry.h:654: warning: `fh_kw_BEAMSP' defined but not used
+../fh_registry.h:654: warning: `fh_cmt_BEAMSP' defined but not used
+../fh_registry.h:659: warning: `fh_set_MIRSLIDE' defined but not used
+../fh_registry.h:659: warning: `fh_setval_MIRSLIDE' defined but not used
+../fh_registry.h:659: warning: `fh_setcmt_MIRSLIDE' defined but not used
+../fh_registry.h:659: warning: `fh_get_MIRSLIDE' defined but not used
+../fh_registry.h:659: warning: `fh_kw_MIRSLIDE' defined but not used
+../fh_registry.h:659: warning: `fh_cmt_MIRSLIDE' defined but not used
+../fh_registry.h:668: warning: `fh_set_WFSNDID' defined but not used
+../fh_registry.h:668: warning: `fh_setval_WFSNDID' defined but not used
+../fh_registry.h:668: warning: `fh_setcmt_WFSNDID' defined but not used
+../fh_registry.h:668: warning: `fh_get_WFSNDID' defined but not used
+../fh_registry.h:668: warning: `fh_kw_WFSNDID' defined but not used
+../fh_registry.h:668: warning: `fh_cmt_WFSNDID' defined but not used
+../fh_registry.h:673: warning: `fh_set_WFSX' defined but not used
+../fh_registry.h:673: warning: `fh_setval_WFSX' defined but not used
+../fh_registry.h:673: warning: `fh_setcmt_WFSX' defined but not used
+../fh_registry.h:673: warning: `fh_get_WFSX' defined but not used
+../fh_registry.h:673: warning: `fh_kw_WFSX' defined but not used
+../fh_registry.h:673: warning: `fh_cmt_WFSX' defined but not used
+../fh_registry.h:674: warning: `fh_set_WFSY' defined but not used
+../fh_registry.h:674: warning: `fh_setval_WFSY' defined but not used
+../fh_registry.h:674: warning: `fh_setcmt_WFSY' defined but not used
+../fh_registry.h:674: warning: `fh_get_WFSY' defined but not used
+../fh_registry.h:674: warning: `fh_kw_WFSY' defined but not used
+../fh_registry.h:674: warning: `fh_cmt_WFSY' defined but not used
+../fh_registry.h:675: warning: `fh_set_WFSZ' defined but not used
+../fh_registry.h:675: warning: `fh_setval_WFSZ' defined but not used
+../fh_registry.h:675: warning: `fh_setcmt_WFSZ' defined but not used
+../fh_registry.h:675: warning: `fh_get_WFSZ' defined but not used
+../fh_registry.h:675: warning: `fh_kw_WFSZ' defined but not used
+../fh_registry.h:675: warning: `fh_cmt_WFSZ' defined but not used
+../fh_registry.h:682: warning: `fh_set_CMTCAL1' defined but not used
+../fh_registry.h:683: warning: `fh_set_CMTCAL2' defined but not used
+../fh_registry.h:684: warning: `fh_set_CMTCAL3' defined but not used
+../fh_registry.h:685: warning: `fh_set_CMTCAL4' defined but not used
+../fh_registry.h:693: warning: `fh_set_FFLAMPON' defined but not used
+../fh_registry.h:693: warning: `fh_setval_FFLAMPON' defined but not used
+../fh_registry.h:693: warning: `fh_setcmt_FFLAMPON' defined but not used
+../fh_registry.h:693: warning: `fh_get_FFLAMPON' defined but not used
+../fh_registry.h:693: warning: `fh_kw_FFLAMPON' defined but not used
+../fh_registry.h:693: warning: `fh_cmt_FFLAMPON' defined but not used
+../fh_registry.h:694: warning: `fh_set_FFLAMP' defined but not used
+../fh_registry.h:694: warning: `fh_setval_FFLAMP' defined but not used
+../fh_registry.h:694: warning: `fh_setcmt_FFLAMP' defined but not used
+../fh_registry.h:694: warning: `fh_get_FFLAMP' defined but not used
+../fh_registry.h:694: warning: `fh_kw_FFLAMP' defined but not used
+../fh_registry.h:694: warning: `fh_cmt_FFLAMP' defined but not used
+../fh_registry.h:702: warning: `fh_set_CLAMP0ON' defined but not used
+../fh_registry.h:702: warning: `fh_setval_CLAMP0ON' defined but not used
+../fh_registry.h:702: warning: `fh_setcmt_CLAMP0ON' defined but not used
+../fh_registry.h:702: warning: `fh_get_CLAMP0ON' defined but not used
+../fh_registry.h:702: warning: `fh_kw_CLAMP0ON' defined but not used
+../fh_registry.h:702: warning: `fh_cmt_CLAMP0ON' defined but not used
+../fh_registry.h:703: warning: `fh_set_CLAMP0' defined but not used
+../fh_registry.h:703: warning: `fh_setval_CLAMP0' defined but not used
+../fh_registry.h:703: warning: `fh_setcmt_CLAMP0' defined but not used
+../fh_registry.h:703: warning: `fh_get_CLAMP0' defined but not used
+../fh_registry.h:703: warning: `fh_kw_CLAMP0' defined but not used
+../fh_registry.h:703: warning: `fh_cmt_CLAMP0' defined but not used
+../fh_registry.h:704: warning: `fh_set_CLAMP1ON' defined but not used
+../fh_registry.h:704: warning: `fh_setval_CLAMP1ON' defined but not used
+../fh_registry.h:704: warning: `fh_setcmt_CLAMP1ON' defined but not used
+../fh_registry.h:704: warning: `fh_get_CLAMP1ON' defined but not used
+../fh_registry.h:704: warning: `fh_kw_CLAMP1ON' defined but not used
+../fh_registry.h:704: warning: `fh_cmt_CLAMP1ON' defined but not used
+../fh_registry.h:705: warning: `fh_set_CLAMP1' defined but not used
+../fh_registry.h:705: warning: `fh_setval_CLAMP1' defined but not used
+../fh_registry.h:705: warning: `fh_setcmt_CLAMP1' defined but not used
+../fh_registry.h:705: warning: `fh_get_CLAMP1' defined but not used
+../fh_registry.h:705: warning: `fh_kw_CLAMP1' defined but not used
+../fh_registry.h:705: warning: `fh_cmt_CLAMP1' defined but not used
+../fh_registry.h:706: warning: `fh_set_CLAMP2ON' defined but not used
+../fh_registry.h:706: warning: `fh_setval_CLAMP2ON' defined but not used
+../fh_registry.h:706: warning: `fh_setcmt_CLAMP2ON' defined but not used
+../fh_registry.h:706: warning: `fh_get_CLAMP2ON' defined but not used
+../fh_registry.h:706: warning: `fh_kw_CLAMP2ON' defined but not used
+../fh_registry.h:706: warning: `fh_cmt_CLAMP2ON' defined but not used
+../fh_registry.h:707: warning: `fh_set_CLAMP2' defined but not used
+../fh_registry.h:707: warning: `fh_setval_CLAMP2' defined but not used
+../fh_registry.h:707: warning: `fh_setcmt_CLAMP2' defined but not used
+../fh_registry.h:707: warning: `fh_get_CLAMP2' defined but not used
+../fh_registry.h:707: warning: `fh_kw_CLAMP2' defined but not used
+../fh_registry.h:707: warning: `fh_cmt_CLAMP2' defined but not used
+../fh_registry.h:708: warning: `fh_set_CLAMP3ON' defined but not used
+../fh_registry.h:708: warning: `fh_setval_CLAMP3ON' defined but not used
+../fh_registry.h:708: warning: `fh_setcmt_CLAMP3ON' defined but not used
+../fh_registry.h:708: warning: `fh_get_CLAMP3ON' defined but not used
+../fh_registry.h:708: warning: `fh_kw_CLAMP3ON' defined but not used
+../fh_registry.h:708: warning: `fh_cmt_CLAMP3ON' defined but not used
+../fh_registry.h:709: warning: `fh_set_CLAMP3' defined but not used
+../fh_registry.h:709: warning: `fh_setval_CLAMP3' defined but not used
+../fh_registry.h:709: warning: `fh_setcmt_CLAMP3' defined but not used
+../fh_registry.h:709: warning: `fh_get_CLAMP3' defined but not used
+../fh_registry.h:709: warning: `fh_kw_CLAMP3' defined but not used
+../fh_registry.h:709: warning: `fh_cmt_CLAMP3' defined but not used
+../fh_registry.h:716: warning: `fh_set_CALIBL0' defined but not used
+../fh_registry.h:716: warning: `fh_setval_CALIBL0' defined but not used
+../fh_registry.h:716: warning: `fh_setcmt_CALIBL0' defined but not used
+../fh_registry.h:716: warning: `fh_get_CALIBL0' defined but not used
+../fh_registry.h:716: warning: `fh_kw_CALIBL0' defined but not used
+../fh_registry.h:716: warning: `fh_cmt_CALIBL0' defined but not used
+../fh_registry.h:717: warning: `fh_set_CALIBL1' defined but not used
+../fh_registry.h:717: warning: `fh_setval_CALIBL1' defined but not used
+../fh_registry.h:717: warning: `fh_setcmt_CALIBL1' defined but not used
+../fh_registry.h:717: warning: `fh_get_CALIBL1' defined but not used
+../fh_registry.h:717: warning: `fh_kw_CALIBL1' defined but not used
+../fh_registry.h:717: warning: `fh_cmt_CALIBL1' defined but not used
+../fh_registry.h:718: warning: `fh_set_CALIBL2' defined but not used
+../fh_registry.h:718: warning: `fh_setval_CALIBL2' defined but not used
+../fh_registry.h:718: warning: `fh_setcmt_CALIBL2' defined but not used
+../fh_registry.h:718: warning: `fh_get_CALIBL2' defined but not used
+../fh_registry.h:718: warning: `fh_kw_CALIBL2' defined but not used
+../fh_registry.h:718: warning: `fh_cmt_CALIBL2' defined but not used
+../fh_registry.h:719: warning: `fh_set_CALIBL3' defined but not used
+../fh_registry.h:719: warning: `fh_setval_CALIBL3' defined but not used
+../fh_registry.h:719: warning: `fh_setcmt_CALIBL3' defined but not used
+../fh_registry.h:719: warning: `fh_get_CALIBL3' defined but not used
+../fh_registry.h:719: warning: `fh_kw_CALIBL3' defined but not used
+../fh_registry.h:719: warning: `fh_cmt_CALIBL3' defined but not used
+../fh_registry.h:720: warning: `fh_set_CALIBL4' defined but not used
+../fh_registry.h:720: warning: `fh_setval_CALIBL4' defined but not used
+../fh_registry.h:720: warning: `fh_setcmt_CALIBL4' defined but not used
+../fh_registry.h:720: warning: `fh_get_CALIBL4' defined but not used
+../fh_registry.h:720: warning: `fh_kw_CALIBL4' defined but not used
+../fh_registry.h:720: warning: `fh_cmt_CALIBL4' defined but not used
+../fh_registry.h:721: warning: `fh_set_CALIBL5' defined but not used
+../fh_registry.h:721: warning: `fh_setval_CALIBL5' defined but not used
+../fh_registry.h:721: warning: `fh_setcmt_CALIBL5' defined but not used
+../fh_registry.h:721: warning: `fh_get_CALIBL5' defined but not used
+../fh_registry.h:721: warning: `fh_kw_CALIBL5' defined but not used
+../fh_registry.h:721: warning: `fh_cmt_CALIBL5' defined but not used
+../fh_registry.h:722: warning: `fh_set_CALIBL6' defined but not used
+../fh_registry.h:722: warning: `fh_setval_CALIBL6' defined but not used
+../fh_registry.h:722: warning: `fh_setcmt_CALIBL6' defined but not used
+../fh_registry.h:722: warning: `fh_get_CALIBL6' defined but not used
+../fh_registry.h:722: warning: `fh_kw_CALIBL6' defined but not used
+../fh_registry.h:722: warning: `fh_cmt_CALIBL6' defined but not used
+../fh_registry.h:723: warning: `fh_set_CALIBL7' defined but not used
+../fh_registry.h:723: warning: `fh_setval_CALIBL7' defined but not used
+../fh_registry.h:723: warning: `fh_setcmt_CALIBL7' defined but not used
+../fh_registry.h:723: warning: `fh_get_CALIBL7' defined but not used
+../fh_registry.h:723: warning: `fh_kw_CALIBL7' defined but not used
+../fh_registry.h:723: warning: `fh_cmt_CALIBL7' defined but not used
+../fh_registry.h:724: warning: `fh_set_CALIBL8' defined but not used
+../fh_registry.h:724: warning: `fh_setval_CALIBL8' defined but not used
+../fh_registry.h:724: warning: `fh_setcmt_CALIBL8' defined but not used
+../fh_registry.h:724: warning: `fh_get_CALIBL8' defined but not used
+../fh_registry.h:724: warning: `fh_kw_CALIBL8' defined but not used
+../fh_registry.h:724: warning: `fh_cmt_CALIBL8' defined but not used
+../fh_registry.h:725: warning: `fh_set_CALIBL9' defined but not used
+../fh_registry.h:725: warning: `fh_setval_CALIBL9' defined but not used
+../fh_registry.h:725: warning: `fh_setcmt_CALIBL9' defined but not used
+../fh_registry.h:725: warning: `fh_get_CALIBL9' defined but not used
+../fh_registry.h:725: warning: `fh_kw_CALIBL9' defined but not used
+../fh_registry.h:725: warning: `fh_cmt_CALIBL9' defined but not used
+../fh_registry.h:732: warning: `fh_set_CMTINST1' defined but not used
+../fh_registry.h:733: warning: `fh_set_CMTINST2' defined but not used
+../fh_registry.h:734: warning: `fh_set_CMTINST3' defined but not used
+../fh_registry.h:735: warning: `fh_set_CMTINST4' defined but not used
+../fh_registry.h:766: warning: `fh_set_FILTERID' defined but not used
+../fh_registry.h:766: warning: `fh_setval_FILTERID' defined but not used
+../fh_registry.h:766: warning: `fh_setcmt_FILTERID' defined but not used
+../fh_registry.h:766: warning: `fh_get_FILTERID' defined but not used
+../fh_registry.h:766: warning: `fh_kw_FILTERID' defined but not used
+../fh_registry.h:766: warning: `fh_cmt_FILTERID' defined but not used
+../fh_registry.h:767: warning: `fh_set_FILTER' defined but not used
+../fh_registry.h:767: warning: `fh_setval_FILTER' defined but not used
+../fh_registry.h:767: warning: `fh_setcmt_FILTER' defined but not used
+../fh_registry.h:767: warning: `fh_get_FILTER' defined but not used
+../fh_registry.h:767: warning: `fh_kw_FILTER' defined but not used
+../fh_registry.h:767: warning: `fh_cmt_FILTER' defined but not used
+../fh_registry.h:768: warning: `fh_set_FILTERBW' defined but not used
+../fh_registry.h:768: warning: `fh_setval_FILTERBW' defined but not used
+../fh_registry.h:768: warning: `fh_setcmt_FILTERBW' defined but not used
+../fh_registry.h:768: warning: `fh_get_FILTERBW' defined but not used
+../fh_registry.h:768: warning: `fh_kw_FILTERBW' defined but not used
+../fh_registry.h:768: warning: `fh_cmt_FILTERBW' defined but not used
+../fh_registry.h:769: warning: `fh_set_FILTERWL' defined but not used
+../fh_registry.h:769: warning: `fh_setval_FILTERWL' defined but not used
+../fh_registry.h:769: warning: `fh_setcmt_FILTERWL' defined but not used
+../fh_registry.h:769: warning: `fh_get_FILTERWL' defined but not used
+../fh_registry.h:769: warning: `fh_kw_FILTERWL' defined but not used
+../fh_registry.h:769: warning: `fh_cmt_FILTERWL' defined but not used
+../fh_registry.h:770: warning: `fh_set_FILTERLB' defined but not used
+../fh_registry.h:770: warning: `fh_setval_FILTERLB' defined but not used
+../fh_registry.h:770: warning: `fh_setcmt_FILTERLB' defined but not used
+../fh_registry.h:770: warning: `fh_get_FILTERLB' defined but not used
+../fh_registry.h:770: warning: `fh_kw_FILTERLB' defined but not used
+../fh_registry.h:770: warning: `fh_cmt_FILTERLB' defined but not used
+../fh_registry.h:771: warning: `fh_set_FILTERUB' defined but not used
+../fh_registry.h:771: warning: `fh_setval_FILTERUB' defined but not used
+../fh_registry.h:771: warning: `fh_setcmt_FILTERUB' defined but not used
+../fh_registry.h:771: warning: `fh_get_FILTERUB' defined but not used
+../fh_registry.h:771: warning: `fh_kw_FILTERUB' defined but not used
+../fh_registry.h:771: warning: `fh_cmt_FILTERUB' defined but not used
+../fh_registry.h:773: warning: `fh_set_FILTSLID' defined but not used
+../fh_registry.h:773: warning: `fh_setval_FILTSLID' defined but not used
+../fh_registry.h:773: warning: `fh_setcmt_FILTSLID' defined but not used
+../fh_registry.h:773: warning: `fh_get_FILTSLID' defined but not used
+../fh_registry.h:773: warning: `fh_kw_FILTSLID' defined but not used
+../fh_registry.h:773: warning: `fh_cmt_FILTSLID' defined but not used
+../fh_registry.h:776: warning: `fh_set_WHEELAID' defined but not used
+../fh_registry.h:776: warning: `fh_setval_WHEELAID' defined but not used
+../fh_registry.h:776: warning: `fh_setcmt_WHEELAID' defined but not used
+../fh_registry.h:776: warning: `fh_get_WHEELAID' defined but not used
+../fh_registry.h:776: warning: `fh_kw_WHEELAID' defined but not used
+../fh_registry.h:776: warning: `fh_cmt_WHEELAID' defined but not used
+../fh_registry.h:777: warning: `fh_set_WHEELADE' defined but not used
+../fh_registry.h:777: warning: `fh_setval_WHEELADE' defined but not used
+../fh_registry.h:777: warning: `fh_setcmt_WHEELADE' defined but not used
+../fh_registry.h:777: warning: `fh_get_WHEELADE' defined but not used
+../fh_registry.h:777: warning: `fh_kw_WHEELADE' defined but not used
+../fh_registry.h:777: warning: `fh_cmt_WHEELADE' defined but not used
+../fh_registry.h:778: warning: `fh_set_WHEELALB' defined but not used
+../fh_registry.h:778: warning: `fh_setval_WHEELALB' defined but not used
+../fh_registry.h:778: warning: `fh_setcmt_WHEELALB' defined but not used
+../fh_registry.h:778: warning: `fh_get_WHEELALB' defined but not used
+../fh_registry.h:778: warning: `fh_kw_WHEELALB' defined but not used
+../fh_registry.h:778: warning: `fh_cmt_WHEELALB' defined but not used
+../fh_registry.h:779: warning: `fh_set_WHEELAUB' defined but not used
+../fh_registry.h:779: warning: `fh_setval_WHEELAUB' defined but not used
+../fh_registry.h:779: warning: `fh_setcmt_WHEELAUB' defined but not used
+../fh_registry.h:779: warning: `fh_get_WHEELAUB' defined but not used
+../fh_registry.h:779: warning: `fh_kw_WHEELAUB' defined but not used
+../fh_registry.h:779: warning: `fh_cmt_WHEELAUB' defined but not used
+../fh_registry.h:781: warning: `fh_set_WHEELBID' defined but not used
+../fh_registry.h:781: warning: `fh_setval_WHEELBID' defined but not used
+../fh_registry.h:781: warning: `fh_setcmt_WHEELBID' defined but not used
+../fh_registry.h:781: warning: `fh_get_WHEELBID' defined but not used
+../fh_registry.h:781: warning: `fh_kw_WHEELBID' defined but not used
+../fh_registry.h:781: warning: `fh_cmt_WHEELBID' defined but not used
+../fh_registry.h:782: warning: `fh_set_WHEELBDE' defined but not used
+../fh_registry.h:782: warning: `fh_setval_WHEELBDE' defined but not used
+../fh_registry.h:782: warning: `fh_setcmt_WHEELBDE' defined but not used
+../fh_registry.h:782: warning: `fh_get_WHEELBDE' defined but not used
+../fh_registry.h:782: warning: `fh_kw_WHEELBDE' defined but not used
+../fh_registry.h:782: warning: `fh_cmt_WHEELBDE' defined but not used
+../fh_registry.h:783: warning: `fh_set_WHEELBLB' defined but not used
+../fh_registry.h:783: warning: `fh_setval_WHEELBLB' defined but not used
+../fh_registry.h:783: warning: `fh_setcmt_WHEELBLB' defined but not used
+../fh_registry.h:783: warning: `fh_get_WHEELBLB' defined but not used
+../fh_registry.h:783: warning: `fh_kw_WHEELBLB' defined but not used
+../fh_registry.h:783: warning: `fh_cmt_WHEELBLB' defined but not used
+../fh_registry.h:784: warning: `fh_set_WHEELBUB' defined but not used
+../fh_registry.h:784: warning: `fh_setval_WHEELBUB' defined but not used
+../fh_registry.h:784: warning: `fh_setcmt_WHEELBUB' defined but not used
+../fh_registry.h:784: warning: `fh_get_WHEELBUB' defined but not used
+../fh_registry.h:784: warning: `fh_kw_WHEELBUB' defined but not used
+../fh_registry.h:784: warning: `fh_cmt_WHEELBUB' defined but not used
+../fh_registry.h:792: warning: `fh_set_INSTFOC' defined but not used
+../fh_registry.h:792: warning: `fh_setval_INSTFOC' defined but not used
+../fh_registry.h:792: warning: `fh_setcmt_INSTFOC' defined but not used
+../fh_registry.h:792: warning: `fh_get_INSTFOC' defined but not used
+../fh_registry.h:792: warning: `fh_kw_INSTFOC' defined but not used
+../fh_registry.h:792: warning: `fh_cmt_INSTFOC' defined but not used
+../fh_registry.h:800: warning: `fh_set_CMTSPEC1' defined but not used
+../fh_registry.h:801: warning: `fh_set_CMTSPEC2' defined but not used
+../fh_registry.h:802: warning: `fh_set_CMTSPEC3' defined but not used
+../fh_registry.h:803: warning: `fh_set_CMTSPEC4' defined but not used
+../fh_registry.h:815: warning: `fh_set_GRISMID' defined but not used
+../fh_registry.h:815: warning: `fh_setval_GRISMID' defined but not used
+../fh_registry.h:815: warning: `fh_setcmt_GRISMID' defined but not used
+../fh_registry.h:815: warning: `fh_get_GRISMID' defined but not used
+../fh_registry.h:815: warning: `fh_kw_GRISMID' defined but not used
+../fh_registry.h:815: warning: `fh_cmt_GRISMID' defined but not used
+../fh_registry.h:816: warning: `fh_set_GRISM' defined but not used
+../fh_registry.h:816: warning: `fh_setval_GRISM' defined but not used
+../fh_registry.h:816: warning: `fh_setcmt_GRISM' defined but not used
+../fh_registry.h:816: warning: `fh_get_GRISM' defined but not used
+../fh_registry.h:816: warning: `fh_kw_GRISM' defined but not used
+../fh_registry.h:816: warning: `fh_cmt_GRISM' defined but not used
+../fh_registry.h:817: warning: `fh_set_GRISSLID' defined but not used
+../fh_registry.h:817: warning: `fh_setval_GRISSLID' defined but not used
+../fh_registry.h:817: warning: `fh_setcmt_GRISSLID' defined but not used
+../fh_registry.h:817: warning: `fh_get_GRISSLID' defined but not used
+../fh_registry.h:817: warning: `fh_kw_GRISSLID' defined but not used
+../fh_registry.h:817: warning: `fh_cmt_GRISSLID' defined but not used
+../fh_registry.h:818: warning: `fh_set_MASKID' defined but not used
+../fh_registry.h:818: warning: `fh_setval_MASKID' defined but not used
+../fh_registry.h:818: warning: `fh_setcmt_MASKID' defined but not used
+../fh_registry.h:818: warning: `fh_get_MASKID' defined but not used
+../fh_registry.h:818: warning: `fh_kw_MASKID' defined but not used
+../fh_registry.h:818: warning: `fh_cmt_MASKID' defined but not used
+../fh_registry.h:819: warning: `fh_set_MASK' defined but not used
+../fh_registry.h:819: warning: `fh_setval_MASK' defined but not used
+../fh_registry.h:819: warning: `fh_setcmt_MASK' defined but not used
+../fh_registry.h:819: warning: `fh_get_MASK' defined but not used
+../fh_registry.h:819: warning: `fh_kw_MASK' defined but not used
+../fh_registry.h:819: warning: `fh_cmt_MASK' defined but not used
+../fh_registry.h:820: warning: `fh_set_MASKSLID' defined but not used
+../fh_registry.h:820: warning: `fh_setval_MASKSLID' defined but not used
+../fh_registry.h:820: warning: `fh_setcmt_MASKSLID' defined but not used
+../fh_registry.h:820: warning: `fh_get_MASKSLID' defined but not used
+../fh_registry.h:820: warning: `fh_kw_MASKSLID' defined but not used
+../fh_registry.h:820: warning: `fh_cmt_MASKSLID' defined but not used
+../fh_registry.h:827: warning: `fh_set_DISPEL' defined but not used
+../fh_registry.h:827: warning: `fh_setval_DISPEL' defined but not used
+../fh_registry.h:827: warning: `fh_setcmt_DISPEL' defined but not used
+../fh_registry.h:827: warning: `fh_get_DISPEL' defined but not used
+../fh_registry.h:827: warning: `fh_kw_DISPEL' defined but not used
+../fh_registry.h:827: warning: `fh_cmt_DISPEL' defined but not used
+../fh_registry.h:831: warning: `fh_set_DISPAXIS' defined but not used
+../fh_registry.h:831: warning: `fh_setval_DISPAXIS' defined but not used
+../fh_registry.h:831: warning: `fh_setcmt_DISPAXIS' defined but not used
+../fh_registry.h:831: warning: `fh_get_DISPAXIS' defined but not used
+../fh_registry.h:831: warning: `fh_kw_DISPAXIS' defined but not used
+../fh_registry.h:831: warning: `fh_cmt_DISPAXIS' defined but not used
+../fh_registry.h:835: warning: `fh_set_DISPANG' defined but not used
+../fh_registry.h:835: warning: `fh_setval_DISPANG' defined but not used
+../fh_registry.h:835: warning: `fh_setcmt_DISPANG' defined but not used
+../fh_registry.h:835: warning: `fh_get_DISPANG' defined but not used
+../fh_registry.h:835: warning: `fh_kw_DISPANG' defined but not used
+../fh_registry.h:835: warning: `fh_cmt_DISPANG' defined but not used
+../fh_registry.h:839: warning: `fh_set_WAVELENG' defined but not used
+../fh_registry.h:839: warning: `fh_setval_WAVELENG' defined but not used
+../fh_registry.h:839: warning: `fh_setcmt_WAVELENG' defined but not used
+../fh_registry.h:839: warning: `fh_get_WAVELENG' defined but not used
+../fh_registry.h:839: warning: `fh_kw_WAVELENG' defined but not used
+../fh_registry.h:839: warning: `fh_cmt_WAVELENG' defined but not used
+../fh_registry.h:843: warning: `fh_set_ORDER' defined but not used
+../fh_registry.h:843: warning: `fh_setval_ORDER' defined but not used
+../fh_registry.h:843: warning: `fh_setcmt_ORDER' defined but not used
+../fh_registry.h:843: warning: `fh_get_ORDER' defined but not used
+../fh_registry.h:843: warning: `fh_kw_ORDER' defined but not used
+../fh_registry.h:843: warning: `fh_cmt_ORDER' defined but not used
+../fh_registry.h:847: warning: `fh_set_GRSETUP' defined but not used
+../fh_registry.h:847: warning: `fh_setval_GRSETUP' defined but not used
+../fh_registry.h:847: warning: `fh_setcmt_GRSETUP' defined but not used
+../fh_registry.h:847: warning: `fh_get_GRSETUP' defined but not used
+../fh_registry.h:847: warning: `fh_kw_GRSETUP' defined but not used
+../fh_registry.h:847: warning: `fh_cmt_GRSETUP' defined but not used
+../fh_registry.h:851: warning: `fh_set_OPENANG2' defined but not used
+../fh_registry.h:851: warning: `fh_setval_OPENANG2' defined but not used
+../fh_registry.h:851: warning: `fh_setcmt_OPENANG2' defined but not used
+../fh_registry.h:851: warning: `fh_get_OPENANG2' defined but not used
+../fh_registry.h:851: warning: `fh_kw_OPENANG2' defined but not used
+../fh_registry.h:851: warning: `fh_cmt_OPENANG2' defined but not used
+../fh_registry.h:855: warning: `fh_set_GRISMANG' defined but not used
+../fh_registry.h:855: warning: `fh_setval_GRISMANG' defined but not used
+../fh_registry.h:855: warning: `fh_setcmt_GRISMANG' defined but not used
+../fh_registry.h:855: warning: `fh_get_GRISMANG' defined but not used
+../fh_registry.h:855: warning: `fh_kw_GRISMANG' defined but not used
+../fh_registry.h:855: warning: `fh_cmt_GRISMANG' defined but not used
+../fh_registry.h:860: warning: `fh_set_SLICER' defined but not used
+../fh_registry.h:860: warning: `fh_setval_SLICER' defined but not used
+../fh_registry.h:860: warning: `fh_setcmt_SLICER' defined but not used
+../fh_registry.h:860: warning: `fh_get_SLICER' defined but not used
+../fh_registry.h:860: warning: `fh_kw_SLICER' defined but not used
+../fh_registry.h:860: warning: `fh_cmt_SLICER' defined but not used
+../fh_registry.h:865: warning: `fh_set_HART1A' defined but not used
+../fh_registry.h:865: warning: `fh_setval_HART1A' defined but not used
+../fh_registry.h:865: warning: `fh_setcmt_HART1A' defined but not used
+../fh_registry.h:865: warning: `fh_get_HART1A' defined but not used
+../fh_registry.h:865: warning: `fh_kw_HART1A' defined but not used
+../fh_registry.h:865: warning: `fh_cmt_HART1A' defined but not used
+../fh_registry.h:866: warning: `fh_set_HART1B' defined but not used
+../fh_registry.h:866: warning: `fh_setval_HART1B' defined but not used
+../fh_registry.h:866: warning: `fh_setcmt_HART1B' defined but not used
+../fh_registry.h:866: warning: `fh_get_HART1B' defined but not used
+../fh_registry.h:866: warning: `fh_kw_HART1B' defined but not used
+../fh_registry.h:866: warning: `fh_cmt_HART1B' defined but not used
+../fh_registry.h:867: warning: `fh_set_HART2' defined but not used
+../fh_registry.h:867: warning: `fh_setval_HART2' defined but not used
+../fh_registry.h:867: warning: `fh_setcmt_HART2' defined but not used
+../fh_registry.h:867: warning: `fh_get_HART2' defined but not used
+../fh_registry.h:867: warning: `fh_kw_HART2' defined but not used
+../fh_registry.h:867: warning: `fh_cmt_HART2' defined but not used
+../fh_registry.h:868: warning: `fh_set_HART3' defined but not used
+../fh_registry.h:868: warning: `fh_setval_HART3' defined but not used
+../fh_registry.h:868: warning: `fh_setcmt_HART3' defined but not used
+../fh_registry.h:868: warning: `fh_get_HART3' defined but not used
+../fh_registry.h:868: warning: `fh_kw_HART3' defined but not used
+../fh_registry.h:868: warning: `fh_cmt_HART3' defined but not used
+../fh_registry.h:869: warning: `fh_set_HART4' defined but not used
+../fh_registry.h:869: warning: `fh_setval_HART4' defined but not used
+../fh_registry.h:869: warning: `fh_setcmt_HART4' defined but not used
+../fh_registry.h:869: warning: `fh_get_HART4' defined but not used
+../fh_registry.h:869: warning: `fh_kw_HART4' defined but not used
+../fh_registry.h:869: warning: `fh_cmt_HART4' defined but not used
+../fh_registry.h:875: warning: `fh_set_COUDETRN' defined but not used
+../fh_registry.h:875: warning: `fh_setval_COUDETRN' defined but not used
+../fh_registry.h:875: warning: `fh_setcmt_COUDETRN' defined but not used
+../fh_registry.h:875: warning: `fh_get_COUDETRN' defined but not used
+../fh_registry.h:875: warning: `fh_kw_COUDETRN' defined but not used
+../fh_registry.h:875: warning: `fh_cmt_COUDETRN' defined but not used
+../fh_registry.h:880: warning: `fh_set_EMFILTER' defined but not used
+../fh_registry.h:880: warning: `fh_setval_EMFILTER' defined but not used
+../fh_registry.h:880: warning: `fh_setcmt_EMFILTER' defined but not used
+../fh_registry.h:880: warning: `fh_get_EMFILTER' defined but not used
+../fh_registry.h:880: warning: `fh_kw_EMFILTER' defined but not used
+../fh_registry.h:880: warning: `fh_cmt_EMFILTER' defined but not used
+../fh_registry.h:881: warning: `fh_set_EMCNTS' defined but not used
+../fh_registry.h:881: warning: `fh_setval_EMCNTS' defined but not used
+../fh_registry.h:881: warning: `fh_setcmt_EMCNTS' defined but not used
+../fh_registry.h:881: warning: `fh_get_EMCNTS' defined but not used
+../fh_registry.h:881: warning: `fh_kw_EMCNTS' defined but not used
+../fh_registry.h:881: warning: `fh_cmt_EMCNTS' defined but not used
+../fh_registry.h:882: warning: `fh_set_MIDEXPTM' defined but not used
+../fh_registry.h:882: warning: `fh_setval_MIDEXPTM' defined but not used
+../fh_registry.h:882: warning: `fh_setcmt_MIDEXPTM' defined but not used
+../fh_registry.h:882: warning: `fh_get_MIDEXPTM' defined but not used
+../fh_registry.h:882: warning: `fh_kw_MIDEXPTM' defined but not used
+../fh_registry.h:882: warning: `fh_cmt_MIDEXPTM' defined but not used
+../fh_registry.h:889: warning: `fh_set_CAFE' defined but not used
+../fh_registry.h:889: warning: `fh_setval_CAFE' defined but not used
+../fh_registry.h:889: warning: `fh_setcmt_CAFE' defined but not used
+../fh_registry.h:889: warning: `fh_get_CAFE' defined but not used
+../fh_registry.h:889: warning: `fh_kw_CAFE' defined but not used
+../fh_registry.h:889: warning: `fh_cmt_CAFE' defined but not used
+../fh_registry.h:897: warning: `fh_set_AUXINST' defined but not used
+../fh_registry.h:897: warning: `fh_setval_AUXINST' defined but not used
+../fh_registry.h:897: warning: `fh_setcmt_AUXINST' defined but not used
+../fh_registry.h:897: warning: `fh_get_AUXINST' defined but not used
+../fh_registry.h:897: warning: `fh_kw_AUXINST' defined but not used
+../fh_registry.h:897: warning: `fh_cmt_AUXINST' defined but not used
+../fh_registry.h:901: warning: `fh_set_CONST' defined but not used
+../fh_registry.h:901: warning: `fh_setval_CONST' defined but not used
+../fh_registry.h:901: warning: `fh_setcmt_CONST' defined but not used
+../fh_registry.h:901: warning: `fh_get_CONST' defined but not used
+../fh_registry.h:901: warning: `fh_kw_CONST' defined but not used
+../fh_registry.h:901: warning: `fh_cmt_CONST' defined but not used
+../fh_registry.h:905: warning: `fh_set_NUMCHAN' defined but not used
+../fh_registry.h:905: warning: `fh_setval_NUMCHAN' defined but not used
+../fh_registry.h:905: warning: `fh_setcmt_NUMCHAN' defined but not used
+../fh_registry.h:905: warning: `fh_get_NUMCHAN' defined but not used
+../fh_registry.h:905: warning: `fh_kw_NUMCHAN' defined but not used
+../fh_registry.h:905: warning: `fh_cmt_NUMCHAN' defined but not used
+../fh_registry.h:909: warning: `fh_set_CURCHAN' defined but not used
+../fh_registry.h:909: warning: `fh_setval_CURCHAN' defined but not used
+../fh_registry.h:909: warning: `fh_setcmt_CURCHAN' defined but not used
+../fh_registry.h:909: warning: `fh_get_CURCHAN' defined but not used
+../fh_registry.h:909: warning: `fh_kw_CURCHAN' defined but not used
+../fh_registry.h:909: warning: `fh_cmt_CURCHAN' defined but not used
+../fh_registry.h:913: warning: `fh_set_BINVAL' defined but not used
+../fh_registry.h:913: warning: `fh_setval_BINVAL' defined but not used
+../fh_registry.h:913: warning: `fh_setcmt_BINVAL' defined but not used
+../fh_registry.h:913: warning: `fh_get_BINVAL' defined but not used
+../fh_registry.h:913: warning: `fh_kw_BINVAL' defined but not used
+../fh_registry.h:913: warning: `fh_cmt_BINVAL' defined but not used
+../fh_registry.h:922: warning: `fh_set_GRFPPOS' defined but not used
+../fh_registry.h:922: warning: `fh_setval_GRFPPOS' defined but not used
+../fh_registry.h:922: warning: `fh_setcmt_GRFPPOS' defined but not used
+../fh_registry.h:922: warning: `fh_get_GRFPPOS' defined but not used
+../fh_registry.h:922: warning: `fh_kw_GRFPPOS' defined but not used
+../fh_registry.h:922: warning: `fh_cmt_GRFPPOS' defined but not used
+../fh_registry.h:927: warning: `fh_set_GRWAVORD' defined but not used
+../fh_registry.h:927: warning: `fh_setval_GRWAVORD' defined but not used
+../fh_registry.h:927: warning: `fh_setcmt_GRWAVORD' defined but not used
+../fh_registry.h:927: warning: `fh_get_GRWAVORD' defined but not used
+../fh_registry.h:927: warning: `fh_kw_GRWAVORD' defined but not used
+../fh_registry.h:927: warning: `fh_cmt_GRWAVORD' defined but not used
+../fh_registry.h:928: warning: `fh_set_GRWAVCAL' defined but not used
+../fh_registry.h:928: warning: `fh_setval_GRWAVCAL' defined but not used
+../fh_registry.h:928: warning: `fh_setcmt_GRWAVCAL' defined but not used
+../fh_registry.h:928: warning: `fh_get_GRWAVCAL' defined but not used
+../fh_registry.h:928: warning: `fh_kw_GRWAVCAL' defined but not used
+../fh_registry.h:928: warning: `fh_cmt_GRWAVCAL' defined but not used
+../fh_registry.h:929: warning: `fh_set_GRBCVCAL' defined but not used
+../fh_registry.h:929: warning: `fh_setval_GRBCVCAL' defined but not used
+../fh_registry.h:929: warning: `fh_setcmt_GRBCVCAL' defined but not used
+../fh_registry.h:929: warning: `fh_get_GRBCVCAL' defined but not used
+../fh_registry.h:929: warning: `fh_kw_GRBCVCAL' defined but not used
+../fh_registry.h:929: warning: `fh_cmt_GRBCVCAL' defined but not used
+../fh_registry.h:936: warning: `fh_set_GRSCANTY' defined but not used
+../fh_registry.h:936: warning: `fh_setval_GRSCANTY' defined but not used
+../fh_registry.h:936: warning: `fh_setcmt_GRSCANTY' defined but not used
+../fh_registry.h:936: warning: `fh_get_GRSCANTY' defined but not used
+../fh_registry.h:936: warning: `fh_kw_GRSCANTY' defined but not used
+../fh_registry.h:936: warning: `fh_cmt_GRSCANTY' defined but not used
+../fh_registry.h:940: warning: `fh_set_GRWAVBEG' defined but not used
+../fh_registry.h:940: warning: `fh_setval_GRWAVBEG' defined but not used
+../fh_registry.h:940: warning: `fh_setcmt_GRWAVBEG' defined but not used
+../fh_registry.h:940: warning: `fh_get_GRWAVBEG' defined but not used
+../fh_registry.h:940: warning: `fh_kw_GRWAVBEG' defined but not used
+../fh_registry.h:940: warning: `fh_cmt_GRWAVBEG' defined but not used
+../fh_registry.h:941: warning: `fh_set_GRWAVSTP' defined but not used
+../fh_registry.h:941: warning: `fh_setval_GRWAVSTP' defined but not used
+../fh_registry.h:941: warning: `fh_setcmt_GRWAVSTP' defined but not used
+../fh_registry.h:941: warning: `fh_get_GRWAVSTP' defined but not used
+../fh_registry.h:941: warning: `fh_kw_GRWAVSTP' defined but not used
+../fh_registry.h:941: warning: `fh_cmt_GRWAVSTP' defined but not used
+../fh_registry.h:942: warning: `fh_set_GRWAVCUR' defined but not used
+../fh_registry.h:942: warning: `fh_setval_GRWAVCUR' defined but not used
+../fh_registry.h:942: warning: `fh_setcmt_GRWAVCUR' defined but not used
+../fh_registry.h:942: warning: `fh_get_GRWAVCUR' defined but not used
+../fh_registry.h:942: warning: `fh_kw_GRWAVCUR' defined but not used
+../fh_registry.h:942: warning: `fh_cmt_GRWAVCUR' defined but not used
+../fh_registry.h:948: warning: `fh_set_GRBCVBEG' defined but not used
+../fh_registry.h:948: warning: `fh_setval_GRBCVBEG' defined but not used
+../fh_registry.h:948: warning: `fh_setcmt_GRBCVBEG' defined but not used
+../fh_registry.h:948: warning: `fh_get_GRBCVBEG' defined but not used
+../fh_registry.h:948: warning: `fh_kw_GRBCVBEG' defined but not used
+../fh_registry.h:948: warning: `fh_cmt_GRBCVBEG' defined but not used
+../fh_registry.h:949: warning: `fh_set_GRBCVSTP' defined but not used
+../fh_registry.h:949: warning: `fh_setval_GRBCVSTP' defined but not used
+../fh_registry.h:949: warning: `fh_setcmt_GRBCVSTP' defined but not used
+../fh_registry.h:949: warning: `fh_get_GRBCVSTP' defined but not used
+../fh_registry.h:949: warning: `fh_kw_GRBCVSTP' defined but not used
+../fh_registry.h:949: warning: `fh_cmt_GRBCVSTP' defined but not used
+../fh_registry.h:950: warning: `fh_set_GRBCVCUR' defined but not used
+../fh_registry.h:950: warning: `fh_setval_GRBCVCUR' defined but not used
+../fh_registry.h:950: warning: `fh_setcmt_GRBCVCUR' defined but not used
+../fh_registry.h:950: warning: `fh_get_GRBCVCUR' defined but not used
+../fh_registry.h:950: warning: `fh_kw_GRBCVCUR' defined but not used
+../fh_registry.h:950: warning: `fh_cmt_GRBCVCUR' defined but not used
+../fh_registry.h:956: warning: `fh_set_GRNBCHAN' defined but not used
+../fh_registry.h:956: warning: `fh_setval_GRNBCHAN' defined but not used
+../fh_registry.h:956: warning: `fh_setcmt_GRNBCHAN' defined but not used
+../fh_registry.h:956: warning: `fh_get_GRNBCHAN' defined but not used
+../fh_registry.h:956: warning: `fh_kw_GRNBCHAN' defined but not used
+../fh_registry.h:956: warning: `fh_cmt_GRNBCHAN' defined but not used
+../fh_registry.h:957: warning: `fh_set_GRCURRCH' defined but not used
+../fh_registry.h:957: warning: `fh_setval_GRCURRCH' defined but not used
+../fh_registry.h:957: warning: `fh_setcmt_GRCURRCH' defined but not used
+../fh_registry.h:957: warning: `fh_get_GRCURRCH' defined but not used
+../fh_registry.h:957: warning: `fh_kw_GRCURRCH' defined but not used
+../fh_registry.h:957: warning: `fh_cmt_GRCURRCH' defined but not used
+../fh_registry.h:962: warning: `fh_set_GRBCV_X' defined but not used
+../fh_registry.h:962: warning: `fh_setval_GRBCV_X' defined but not used
+../fh_registry.h:962: warning: `fh_setcmt_GRBCV_X' defined but not used
+../fh_registry.h:962: warning: `fh_get_GRBCV_X' defined but not used
+../fh_registry.h:962: warning: `fh_kw_GRBCV_X' defined but not used
+../fh_registry.h:962: warning: `fh_cmt_GRBCV_X' defined but not used
+../fh_registry.h:963: warning: `fh_set_GRBCV_Y' defined but not used
+../fh_registry.h:963: warning: `fh_setval_GRBCV_Y' defined but not used
+../fh_registry.h:963: warning: `fh_setcmt_GRBCV_Y' defined but not used
+../fh_registry.h:963: warning: `fh_get_GRBCV_Y' defined but not used
+../fh_registry.h:963: warning: `fh_kw_GRBCV_Y' defined but not used
+../fh_registry.h:963: warning: `fh_cmt_GRBCV_Y' defined but not used
+../fh_registry.h:975: warning: `fh_set_TESPMIRE' defined but not used
+../fh_registry.h:975: warning: `fh_setval_TESPMIRE' defined but not used
+../fh_registry.h:975: warning: `fh_setcmt_TESPMIRE' defined but not used
+../fh_registry.h:975: warning: `fh_get_TESPMIRE' defined but not used
+../fh_registry.h:975: warning: `fh_kw_TESPMIRE' defined but not used
+../fh_registry.h:975: warning: `fh_cmt_TESPMIRE' defined but not used
+../fh_registry.h:976: warning: `fh_set_TESPMIRW' defined but not used
+../fh_registry.h:976: warning: `fh_setval_TESPMIRW' defined but not used
+../fh_registry.h:976: warning: `fh_setcmt_TESPMIRW' defined but not used
+../fh_registry.h:976: warning: `fh_get_TESPMIRW' defined but not used
+../fh_registry.h:976: warning: `fh_kw_TESPMIRW' defined but not used
+../fh_registry.h:976: warning: `fh_cmt_TESPMIRW' defined but not used
+../fh_registry.h:977: warning: `fh_set_TESPMIRS' defined but not used
+../fh_registry.h:977: warning: `fh_setval_TESPMIRS' defined but not used
+../fh_registry.h:977: warning: `fh_setcmt_TESPMIRS' defined but not used
+../fh_registry.h:977: warning: `fh_get_TESPMIRS' defined but not used
+../fh_registry.h:977: warning: `fh_kw_TESPMIRS' defined but not used
+../fh_registry.h:977: warning: `fh_cmt_TESPMIRS' defined but not used
+../fh_registry.h:978: warning: `fh_set_TEAPMCLW' defined but not used
+../fh_registry.h:978: warning: `fh_setval_TEAPMCLW' defined but not used
+../fh_registry.h:978: warning: `fh_setcmt_TEAPMCLW' defined but not used
+../fh_registry.h:978: warning: `fh_get_TEAPMCLW' defined but not used
+../fh_registry.h:978: warning: `fh_kw_TEAPMCLW' defined but not used
+../fh_registry.h:978: warning: `fh_cmt_TEAPMCLW' defined but not used
+../fh_registry.h:979: warning: `fh_set_TEAMIRCI' defined but not used
+../fh_registry.h:979: warning: `fh_setval_TEAMIRCI' defined but not used
+../fh_registry.h:979: warning: `fh_setcmt_TEAMIRCI' defined but not used
+../fh_registry.h:979: warning: `fh_get_TEAMIRCI' defined but not used
+../fh_registry.h:979: warning: `fh_kw_TEAMIRCI' defined but not used
+../fh_registry.h:979: warning: `fh_cmt_TEAMIRCI' defined but not used
+../fh_registry.h:980: warning: `fh_set_TEAMIRCO' defined but not used
+../fh_registry.h:980: warning: `fh_setval_TEAMIRCO' defined but not used
+../fh_registry.h:980: warning: `fh_setcmt_TEAMIRCO' defined but not used
+../fh_registry.h:980: warning: `fh_get_TEAMIRCO' defined but not used
+../fh_registry.h:980: warning: `fh_kw_TEAMIRCO' defined but not used
+../fh_registry.h:980: warning: `fh_cmt_TEAMIRCO' defined but not used
+../fh_registry.h:981: warning: `fh_set_TEAPMSPN' defined but not used
+../fh_registry.h:981: warning: `fh_setval_TEAPMSPN' defined but not used
+../fh_registry.h:981: warning: `fh_setcmt_TEAPMSPN' defined but not used
+../fh_registry.h:981: warning: `fh_get_TEAPMSPN' defined but not used
+../fh_registry.h:981: warning: `fh_kw_TEAPMSPN' defined but not used
+../fh_registry.h:981: warning: `fh_cmt_TEAPMSPN' defined but not used
+../fh_registry.h:982: warning: `fh_set_TEAPMSPS' defined but not used
+../fh_registry.h:982: warning: `fh_setval_TEAPMSPS' defined but not used
+../fh_registry.h:982: warning: `fh_setcmt_TEAPMSPS' defined but not used
+../fh_registry.h:982: warning: `fh_get_TEAPMSPS' defined but not used
+../fh_registry.h:982: warning: `fh_kw_TEAPMSPS' defined but not used
+../fh_registry.h:982: warning: `fh_cmt_TEAPMSPS' defined but not used
+../fh_registry.h:983: warning: `fh_set_TEATRNGE' defined but not used
+../fh_registry.h:983: warning: `fh_setval_TEATRNGE' defined but not used
+../fh_registry.h:983: warning: `fh_setcmt_TEATRNGE' defined but not used
+../fh_registry.h:983: warning: `fh_get_TEATRNGE' defined but not used
+../fh_registry.h:983: warning: `fh_kw_TEATRNGE' defined but not used
+../fh_registry.h:983: warning: `fh_cmt_TEATRNGE' defined but not used
+../fh_registry.h:984: warning: `fh_set_TEATRNGW' defined but not used
+../fh_registry.h:984: warning: `fh_setval_TEATRNGW' defined but not used
+../fh_registry.h:984: warning: `fh_setcmt_TEATRNGW' defined but not used
+../fh_registry.h:984: warning: `fh_get_TEATRNGW' defined but not used
+../fh_registry.h:984: warning: `fh_kw_TEATRNGW' defined but not used
+../fh_registry.h:984: warning: `fh_cmt_TEATRNGW' defined but not used
+../fh_registry.h:985: warning: `fh_set_TEANRLSB' defined but not used
+../fh_registry.h:985: warning: `fh_setval_TEANRLSB' defined but not used
+../fh_registry.h:985: warning: `fh_setcmt_TEANRLSB' defined but not used
+../fh_registry.h:985: warning: `fh_get_TEANRLSB' defined but not used
+../fh_registry.h:985: warning: `fh_kw_TEANRLSB' defined but not used
+../fh_registry.h:985: warning: `fh_cmt_TEANRLSB' defined but not used
+../fh_registry.h:986: warning: `fh_set_TESHRSET' defined but not used
+../fh_registry.h:986: warning: `fh_setval_TESHRSET' defined but not used
+../fh_registry.h:986: warning: `fh_setcmt_TESHRSET' defined but not used
+../fh_registry.h:986: warning: `fh_get_TESHRSET' defined but not used
+../fh_registry.h:986: warning: `fh_kw_TESHRSET' defined but not used
+../fh_registry.h:986: warning: `fh_cmt_TESHRSET' defined but not used
+../fh_registry.h:987: warning: `fh_set_TESTELTL' defined but not used
+../fh_registry.h:987: warning: `fh_setval_TESTELTL' defined but not used
+../fh_registry.h:987: warning: `fh_setcmt_TESTELTL' defined but not used
+../fh_registry.h:987: warning: `fh_get_TESTELTL' defined but not used
+../fh_registry.h:987: warning: `fh_kw_TESTELTL' defined but not used
+../fh_registry.h:987: warning: `fh_cmt_TESTELTL' defined but not used
+../fh_registry.h:988: warning: `fh_set_TESTELTH' defined but not used
+../fh_registry.h:988: warning: `fh_setval_TESTELTH' defined but not used
+../fh_registry.h:988: warning: `fh_setcmt_TESTELTH' defined but not used
+../fh_registry.h:988: warning: `fh_get_TESTELTH' defined but not used
+../fh_registry.h:988: warning: `fh_kw_TESTELTH' defined but not used
+../fh_registry.h:988: warning: `fh_cmt_TESTELTH' defined but not used
+../fh_registry.h:989: warning: `fh_set_TEALOWWS' defined but not used
+../fh_registry.h:989: warning: `fh_setval_TEALOWWS' defined but not used
+../fh_registry.h:989: warning: `fh_setcmt_TEALOWWS' defined but not used
+../fh_registry.h:989: warning: `fh_get_TEALOWWS' defined but not used
+../fh_registry.h:989: warning: `fh_kw_TEALOWWS' defined but not used
+../fh_registry.h:989: warning: `fh_cmt_TEALOWWS' defined but not used
+../fh_registry.h:990: warning: `fh_set_TEATOPWS' defined but not used
+../fh_registry.h:990: warning: `fh_setval_TEATOPWS' defined but not used
+../fh_registry.h:990: warning: `fh_setcmt_TEATOPWS' defined but not used
+../fh_registry.h:990: warning: `fh_get_TEATOPWS' defined but not used
+../fh_registry.h:990: warning: `fh_kw_TEATOPWS' defined but not used
+../fh_registry.h:990: warning: `fh_cmt_TEATOPWS' defined but not used
+../fh_registry.h:991: warning: `fh_set_TEATOPOP' defined but not used
+../fh_registry.h:991: warning: `fh_setval_TEATOPOP' defined but not used
+../fh_registry.h:991: warning: `fh_setcmt_TEATOPOP' defined but not used
+../fh_registry.h:991: warning: `fh_get_TEATOPOP' defined but not used
+../fh_registry.h:991: warning: `fh_kw_TEATOPOP' defined but not used
+../fh_registry.h:991: warning: `fh_cmt_TEATOPOP' defined but not used
+../fh_registry.h:992: warning: `fh_set_TEA2INCH' defined but not used
+../fh_registry.h:992: warning: `fh_setval_TEA2INCH' defined but not used
+../fh_registry.h:992: warning: `fh_setcmt_TEA2INCH' defined but not used
+../fh_registry.h:992: warning: `fh_get_TEA2INCH' defined but not used
+../fh_registry.h:992: warning: `fh_kw_TEA2INCH' defined but not used
+../fh_registry.h:992: warning: `fh_cmt_TEA2INCH' defined but not used
+../fh_registry.h:993: warning: `fh_set_TEA2INEB' defined but not used
+../fh_registry.h:993: warning: `fh_setval_TEA2INEB' defined but not used
+../fh_registry.h:993: warning: `fh_setcmt_TEA2INEB' defined but not used
+../fh_registry.h:993: warning: `fh_get_TEA2INEB' defined but not used
+../fh_registry.h:993: warning: `fh_kw_TEA2INEB' defined but not used
+../fh_registry.h:993: warning: `fh_cmt_TEA2INEB' defined but not used
+../fh_registry.h:994: warning: `fh_set_TEA6FOOT' defined but not used
+../fh_registry.h:994: warning: `fh_setval_TEA6FOOT' defined but not used
+../fh_registry.h:994: warning: `fh_setcmt_TEA6FOOT' defined but not used
+../fh_registry.h:994: warning: `fh_get_TEA6FOOT' defined but not used
+../fh_registry.h:994: warning: `fh_kw_TEA6FOOT' defined but not used
+../fh_registry.h:994: warning: `fh_cmt_TEA6FOOT' defined but not used
+../fh_registry.h:995: warning: `fh_set_TESCONRM' defined but not used
+../fh_registry.h:995: warning: `fh_setval_TESCONRM' defined but not used
+../fh_registry.h:995: warning: `fh_setcmt_TESCONRM' defined but not used
+../fh_registry.h:995: warning: `fh_get_TESCONRM' defined but not used
+../fh_registry.h:995: warning: `fh_kw_TESCONRM' defined but not used
+../fh_registry.h:995: warning: `fh_cmt_TESCONRM' defined but not used
+../fh_registry.h:996: warning: `fh_set_TESPIERN' defined but not used
+../fh_registry.h:996: warning: `fh_setval_TESPIERN' defined but not used
+../fh_registry.h:996: warning: `fh_setcmt_TESPIERN' defined but not used
+../fh_registry.h:996: warning: `fh_get_TESPIERN' defined but not used
+../fh_registry.h:996: warning: `fh_kw_TESPIERN' defined but not used
+../fh_registry.h:996: warning: `fh_cmt_TESPIERN' defined but not used
+../fh_registry.h:997: warning: `fh_set_TESPIERS' defined but not used
+../fh_registry.h:997: warning: `fh_setval_TESPIERS' defined but not used
+../fh_registry.h:997: warning: `fh_setcmt_TESPIERS' defined but not used
+../fh_registry.h:997: warning: `fh_get_TESPIERS' defined but not used
+../fh_registry.h:997: warning: `fh_kw_TESPIERS' defined but not used
+../fh_registry.h:997: warning: `fh_cmt_TESPIERS' defined but not used
+../fh_registry.h:998: warning: `fh_set_TEAWTHRT' defined but not used
+../fh_registry.h:998: warning: `fh_setval_TEAWTHRT' defined but not used
+../fh_registry.h:998: warning: `fh_setcmt_TEAWTHRT' defined but not used
+../fh_registry.h:998: warning: `fh_get_TEAWTHRT' defined but not used
+../fh_registry.h:998: warning: `fh_kw_TEAWTHRT' defined but not used
+../fh_registry.h:998: warning: `fh_cmt_TEAWTHRT' defined but not used
+../fh_registry.h:999: warning: `fh_set_TEMPERAT' defined but not used
+../fh_registry.h:999: warning: `fh_setval_TEMPERAT' defined but not used
+../fh_registry.h:999: warning: `fh_setcmt_TEMPERAT' defined but not used
+../fh_registry.h:999: warning: `fh_get_TEMPERAT' defined but not used
+../fh_registry.h:999: warning: `fh_kw_TEMPERAT' defined but not used
+../fh_registry.h:999: warning: `fh_cmt_TEMPERAT' defined but not used
+../fh_registry.h:1000: warning: `fh_set_WINDSPED' defined but not used
+../fh_registry.h:1000: warning: `fh_setval_WINDSPED' defined but not used
+../fh_registry.h:1000: warning: `fh_setcmt_WINDSPED' defined but not used
+../fh_registry.h:1000: warning: `fh_get_WINDSPED' defined but not used
+../fh_registry.h:1000: warning: `fh_kw_WINDSPED' defined but not used
+../fh_registry.h:1000: warning: `fh_cmt_WINDSPED' defined but not used
+../fh_registry.h:1001: warning: `fh_set_WINDDIR' defined but not used
+../fh_registry.h:1001: warning: `fh_setval_WINDDIR' defined but not used
+../fh_registry.h:1001: warning: `fh_setcmt_WINDDIR' defined but not used
+../fh_registry.h:1001: warning: `fh_get_WINDDIR' defined but not used
+../fh_registry.h:1001: warning: `fh_kw_WINDDIR' defined but not used
+../fh_registry.h:1001: warning: `fh_cmt_WINDDIR' defined but not used
+../fh_registry.h:1002: warning: `fh_set_RELHUMID' defined but not used
+../fh_registry.h:1002: warning: `fh_setval_RELHUMID' defined but not used
+../fh_registry.h:1002: warning: `fh_setcmt_RELHUMID' defined but not used
+../fh_registry.h:1002: warning: `fh_get_RELHUMID' defined but not used
+../fh_registry.h:1002: warning: `fh_kw_RELHUMID' defined but not used
+../fh_registry.h:1002: warning: `fh_cmt_RELHUMID' defined but not used
+../fh_registry.h:1003: warning: `fh_set_PRESSURE' defined but not used
+../fh_registry.h:1003: warning: `fh_setval_PRESSURE' defined but not used
+../fh_registry.h:1003: warning: `fh_setcmt_PRESSURE' defined but not used
+../fh_registry.h:1003: warning: `fh_get_PRESSURE' defined but not used
+../fh_registry.h:1003: warning: `fh_kw_PRESSURE' defined but not used
+../fh_registry.h:1003: warning: `fh_cmt_PRESSURE' defined but not used
+../fh_registry.h:1015: warning: `fh_set_CMTPROC1' defined but not used
+../fh_registry.h:1016: warning: `fh_set_CMTPROC2' defined but not used
+../fh_registry.h:1017: warning: `fh_set_CMTPROC3' defined but not used
+../fh_registry.h:1018: warning: `fh_set_CMTPROC4' defined but not used
+../fh_registry.h:1019: warning: `fh_set_CRUNID' defined but not used
+../fh_registry.h:1019: warning: `fh_setval_CRUNID' defined but not used
+../fh_registry.h:1019: warning: `fh_setcmt_CRUNID' defined but not used
+../fh_registry.h:1019: warning: `fh_get_CRUNID' defined but not used
+../fh_registry.h:1019: warning: `fh_kw_CRUNID' defined but not used
+../fh_registry.h:1019: warning: `fh_cmt_CRUNID' defined but not used
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.sh
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.sh	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfh/tests/t.sh	(revision 23490)
@@ -0,0 +1,7 @@
+#!/apps/gnu/bin/bash
+#
+# test compile current fh_registry.h
+
+gcc -Wall t.c -c -o t.o >t.log 2>&1
+grep -v "defined but not" t.log
+rm -f t.o
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Index
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Index	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Index	(revision 23490)
@@ -0,0 +1,21 @@
+# Description:
+
+  package		FITS Keyword Registry
+  version		0
+  organization		Pan-STARRS
+  email			isani@ifa.hawaii.edu
+  year			2004
+
+# Contents:
+
+  Makefile		Use with GNU make to build libfhreg
+
+  dummy.c		Placeholder.  There is no C code with libfhreg now.
+  macros.h		CPP macros to make fhreg work, automatically included
+  general.h		General FITS structure keyword registry entries
+  gpc_all.h		Top-level include file that includes all categories
+  gpc_detector.h	Pan-STARRS Giga Pixel Camera detector keywords
+  gpc_instrument.h	Pan-STARRS instrument FITS header keywords
+  gpc_shutter.h	        Pan-STARRS shutter FITS header keywords
+  gpc_telescope.h	Pan-STARRS TCS FITS header keywords
+  gpc_plant.h		Pan-STARRS plant-related FITS header keywords
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Make.Common
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Make.Common	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Make.Common	(revision 23490)
@@ -0,0 +1,1 @@
+link ../Make.Common
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Makefile
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Makefile	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/Makefile	(revision 23490)
@@ -0,0 +1,12 @@
+# `Makefile' - Use with GNU make to build libfhreg
+#
+#   This file is part of version 0 of the FITS Keyword Registry.
+#   Read the `License' file for terms of use and distribution.
+#   Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+#
+# ___This header automatically generated from `Index'. Do not edit it here!___
+include ../Make.Common
+include ../Make.Common
+# Dependencies by Make.Common $Revision: 2.17 $
+
+$(OBJ)/dummy.o: dummy.c
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/dummy.c
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/dummy.c	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/dummy.c	(revision 23490)
@@ -0,0 +1,9 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`dummy.c' - Placeholder.  There is no C code with libfhreg now.
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/general.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/general.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/general.h	(revision 23490)
@@ -0,0 +1,131 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`general.h' - General FITS structure keyword registry entries
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include "macros.h"
+
+/*
+ * Description of columns:
+ *
+ *      TYPE - MK_BLN, MK_STR, MK_INT, MK_FLT, MK_PFL selects a type for the
+ *             keyword (True/False, 'String  ', integer, or floating point.)
+ *             Any keyword can still be set to any type with fh_setval_*(),
+ *             which takes a pre-formatted character string for the card.
+ *
+ *      IDX  - Index sorting number, which eventually determines the final
+ *             order of keywords in the FITS header.  These are floating point
+ *             values so new keywords can always be inserted in between
+ *             without shifting all the values.
+ *
+ *   KEYWORD - The name of the keyword.  Macros will be generated of the form
+ *             fh_get_KEYWORD(), fh_set_KEYWORD(), and fh_setval_KEYWORD().
+ *
+ *      PRC  - For MK_FLT(), this specifies the (scientific) precision,
+ *             or number of significant digits in the value.  If necessary,
+ *             scientific notation will be used to format the value (see
+ *             rules for printf "%.*G").
+ *             For MK_PFL(), this specifies mathematical precision, or number
+ *             of decimal places in the formatted value (see the rules for
+ *             printf "%.*f").
+ *
+ *             Use MK_PFL() (make "precise float") if that value is always
+ *             precise to an exact number digits after the decimal point.
+ *             Use MK_FLT() if the value might require scientific notation.
+ *             All results are FITS-standard legal.
+ *
+ *   COMMENT - String to be included after the / in the FITS card, if
+ *             there is room within the 80 columns (it may get truncated.)
+ *             Note that in the text below, 80 columns are reached when
+ *             there is still one space between the " and the ) at the end
+ *             of the line.
+ *
+ * FITS Structure : 0.000 to 9.999
+ *
+ * The following keywords give basic information about the structure and
+ * dimensions of the FITS file, and must appear in the specific order
+ * below, usually without any other intervening keywords.
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_BLN( 0.0,	SIMPLE  ,   "Standard FITS"                                   )
+MK_STR( 0.0,	XTENSION,   ""                                                )
+MK_INT( 1.0,	BITPIX  ,   "Bits per pixel"                                  )
+MK_INT( 2.0,	NAXIS   ,   "Number of axes"                                  )
+MK_INT( 2.1,	NAXIS1  ,   "Number of pixel columns"                         )
+MK_INT( 2.2,	NAXIS2  ,   "Number of pixel rows"                            )
+MK_INT( 2.3,	NAXIS3  ,   "Number of stacked frames (cube)"                 )
+MK_BLN( 3.0,	EXTEND  ,   "File contains extensions"                        )
+MK_INT( 3.1,	NEXTEND ,   "Number of extensions"                            )
+MK_BLN( 4.0,	GROUPS  ,   "File contains random groups records"             )
+MK_INT( 5.0,	PCOUNT  ,   "Random parameters before each array in a group"  )
+MK_INT( 6.0,	GCOUNT  ,   "Number of random groups"                         )
+MK_INT( 7.0000,	TFIELDS ,   "Number of fields in a row"                       )
+MK_STR( 7.0011,	TFORM1  ,   "Table format for field 1"                        )
+MK_INT( 7.0012,	TBCOL1  ,   "Start Column for field 1"                        )
+MK_STR( 7.0021,	TFORM2  ,   "Table format for field 2"                        )
+MK_INT( 7.0022,	TBCOL2  ,   "Start Column for field 2"                        )
+MK_STR( 7.0031,	TFORM3  ,   "Table format for field 3"                        )
+MK_INT( 7.0032,	TBCOL3  ,   "Start Column for field 3"                        )
+MK_STR( 7.0041,	TFORM4  ,   "Table format for field 4"                        )
+MK_INT( 7.0042,	TBCOL4  ,   "Start Column for field 4"                        )
+MK_STR( 7.0051,	TFORM5  ,   "Table format for field 5"                        )
+MK_INT( 7.0052,	TBCOL5  ,   "Start Column for field 5"                        )
+MK_BLN( 9.0,	INHERIT	,   "Inherit global keywords from primary header"     )
+MK_PFL( 10.0,   BZERO   ,1, "Zero factor"                                     )
+MK_PFL( 11.0,	BSCALE  ,1, "Scale factor"                                    )
+
+/*
+ * Summary : 50.000 to 59.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(   50.1, CMTSUM1 ,   ""                                                )
+MK_CMT(   50.2, CMTSUM2 ,   "Observation Summary"                             )
+MK_CMT(   50.3, CMTSUM3 ,   "-------------------"                             )
+MK_CMT(   50.4, CMTSUM4 ,   ""                                                )
+MK_CMT(   50.5, CMTSUM5 ,   ""                                                )
+MK_STR(   51.0, CMMTOBS ,   ""                                                )
+MK_STR(   52.0, CMMTSEQ ,   ""                                                )
+MK_STR(   53.0, OBJECT  ,   ""                                                )
+MK_STR(   54.0, OBSERVER,   ""                                                )
+MK_STR(   55.0, PI_NAME ,   ""                                                )
+MK_STR(   56.0, RUNID   ,   ""                                                )
+MK_STR(   57.0, QUEUEID ,   ""                                                )
+MK_STR(   58.0, OBS_MODE,   ""                                                )
+MK_INT(   59.0, TESSEL  ,   ""                                                )
+
+/*
+ * General : 70.000 to 79.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  70.10, CMTGEN1 ,   ""                                                )
+MK_CMT(  70.20, CMTGEN2 ,   "General"                                         )
+MK_CMT(  70.30, CMTGEN3 ,   "-------"                                         )
+MK_CMT(  70.40, CMTGEN4 ,   ""                                                )
+MK_STR(  71.00, FILENAME,   "Base filename at acquisition"                    )
+MK_STR(  71.01, PATHNAME,   "Original directory name at acquisition"          )
+MK_STR(  71.10, EXTNAME ,   "Extension name"                                  )
+MK_INT(  71.20, EXTVER  ,   "Extension version"                               )
+MK_INT(  71.21, IMAGEID ,   ""                                                )
+MK_STR(  74.00, DATE    ,   "UTC Date of file creation"                       )
+MK_STR(  74.10, HSTTIME ,   "Local time in Hawaii"                            )
+MK_STR(  76.99, IMGSWPRG,   "Image creation software program"                 )
+MK_STR(  77.00, IMAGESWV,   "Image creation software version"                 )
+MK_STR(  79.00, ORIGIN  ,   ""                                                )
+
+/*
+ * Summary : 90.0 Key stuff from instrument, detector (and other?) sections
+ */
+MK_STR(   91.0, INSTRUME,   "Instrument Name"                                 )
+MK_STR(   91.1, INSTMODE,   "Instrument Mode"                                 )
+MK_STR(   92.0,	DETECTOR,   "Science Detector"                                )
+MK_STR(   92.1, FPPOS,      "Position of detector in focal plane mosaic"      )
+
+MK_STR(   95.0, OBSTYPE,    "Observation/Exposure type"                       )
+MK_PFL(   96.0, EXPTIME,3,  "Exposure time (seconds)"                         )
+MK_PFL(   96.1, EXPREQ ,3,  "Exposure time requested (seconds)"               )
+MK_PFL(   97.0, DARKTIME,3, "Dark current time (seconds)"                     )
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_all.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_all.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_all.h	(revision 23490)
@@ -0,0 +1,21 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`gpc_all.h' - Top-level include file that includes all categories
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+/*
+ * Each subsystem registers their keywords in a separate file.
+ * Including gpc_all.h includes them all.
+ */
+#include "general.h"
+#include "gpc_detector.h"
+#include "gpc_shutter.h"
+#include "gpc_telescope.h"
+#include "gpc_instrument.h"
+#include "gpc_wcs.h"
+#include "gpc_plant.h"
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_detector.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_detector.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_detector.h	(revision 23490)
@@ -0,0 +1,215 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`gpc_detector.h' - Pan-STARRS Giga Pixel Camera detector keywords
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include "macros.h"
+
+/*
+ * Description of columns:
+ *
+ *      TYPE - MK_BLN, MK_STR, MK_INT, MK_FLT, MK_PFL selects a type for the
+ *             keyword (True/False, 'String  ', integer, or floating point.)
+ *             Any keyword can still be set to any type with fh_setval_*(),
+ *             which takes a pre-formatted character string for the card.
+ *
+ *      IDX  - Index sorting number, which eventually determines the final
+ *             order of keywords in the FITS header.  These are floating point
+ *             values so new keywords can always be inserted in between
+ *             without shifting all the values.
+ *
+ *   KEYWORD - The name of the keyword.  Macros will be generated of the form
+ *             fh_get_KEYWORD(), fh_set_KEYWORD(), and fh_setval_KEYWORD().
+ *
+ *      PRC  - For MK_FLT(), this specifies the (scientific) precision,
+ *             or number of significant digits in the value.  If necessary,
+ *             scientific notation will be used to format the value (see
+ *             rules for printf "%.*G").
+ *             For MK_PFL(), this specifies mathematical precision, or number
+ *             of decimal places in the formatted value (see the rules for
+ *             printf "%.*f").
+ *
+ *             Use MK_PFL() (make "precise float") if that value is always
+ *             precise to an exact number digits after the decimal point.
+ *             Use MK_FLT() if the value might require scientific notation.
+ *             All results are FITS-standard legal.
+ *
+ *   COMMENT - String to be included after the / in the FITS card, if
+ *             there is room within the 80 columns (it may get truncated.)
+ *             Note that in the text below, 80 columns are reached when
+ *             there is still one space between the " and the ) at the end
+ *             of the line.
+ *
+ * FITS Structure : 0.000 to 9.999
+ *
+ * The following keywords give basic information about the structure and
+ * dimensions of the FITS file, and must appear in the specific order
+ * below, usually without any other intervening keywords.
+ *
+ * Detector : 100.000 to 199.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  100.1,	CMTDET1	,   ""                                                )
+MK_CMT(  100.2,	CMTDET2	,   "Detector"                                        )
+MK_CMT(  100.3,	CMTDET3	,   "--------"                                        )
+MK_CMT(  100.4,	CMTDET4	,   ""                                                )
+MK_STR(  103.0,	RASTER	,   ""                                                )
+MK_INT(  105.0, NAMPS   ,   "Number of amplifiers in the detector"            )
+MK_STR(  105.1,	AMPLIST	,   "List of amplifiers for this image"               )
+MK_STR(  105.2,	AMPNAME	,   "Amplifier name"                                  )
+MK_STR(  150.1, OTADEV  ,   "Identification of device type"                   )
+MK_STR(  150.1, CCDNAME,    "Name of the CCD (manufacturer reference)"        )
+MK_STR(  150.2, CCDNICK,    "Nickname of the CCD"                             )
+MK_INT(  152.0, MAXLIN  ,   "[ADU] Maximum linearity estimate"                )
+MK_INT(  152.1, SATURATE,   "[ADU] Saturation value"                          )
+MK_FLT(  155.0,	GAIN    ,3, "[e/ADU] est. gain from xray"                     )
+MK_FLT(  155.9, XRNOISE, 2, "[ADU] RMS noise in overscan on xray"             )
+MK_FLT(  156.0,	RDNOISE ,2, "[ADU] RMS Read noise on overscan"                )
+MK_FLT(  157.0, DCURRENT,5, "[ADU/pixel/sec] Dark current"                    )
+MK_FLT(  157.1, DARKCUR ,5, "[e-/pixel/hour] Dark current"                    )
+MK_STR(  158.0,	QEPOINTS,   "QE%@wavelength in nm"                            )
+MK_INT(  159.0, BIASLVL,    "[ADU] Bias level (overscan mean)"                )
+MK_INT(  159.2, BACKEST,    "[ADU] Background level est., overscan corrected" )
+MK_STR(  165.0,	DETSTAT	,   "Detector status"                                 )
+MK_FLT(  166.0, DETTEM  ,3, "[C] Detector temperature"                        )
+MK_PFL(  170.0,	PIXSIZE ,3, "[um] Pixel size for both axes"                   )
+MK_PFL(  171.1,	PIXSIZE1,3, "[um] Pixel size for axis 1"                      )
+MK_PFL(  171.2,	PIXSIZE2,3, "[um] Pixel size for axis 2"                      )
+MK_FLT(  172.1,	PIXSCAL1,4, "[arcsec/pixel] Pixel scale for axis 1"           )
+MK_FLT(  172.2,	PIXSCAL2,4, "[arcsec/pixel] Pixel scale for axis 2"           )
+MK_STR(  176.0, CELLMODE,   " 64 cells: S)cience D)ead V)ideo F)loat"         )
+MK_INT(  180.01,IMNAXIS1,   "OTA image width in unbinned pixels"              )
+MK_INT(  180.02,IMNAXIS2,   "OTA image height in unbinned pixels"             )
+MK_INT(  180.11,IMNPIX1 ,   "OTA image coordinate of amp. (the cell origin)"  )
+MK_INT(  180.12,IMNPIX2 ,   "OTA image coordinate of amp. (the cell origin)"  )
+MK_CMT(  181.01,CMTCEL1,
+         "The following keywords apply equally to each cell, so can be in PHU")
+MK_CMT(  181.02,CMTCEL2,
+         "If not, they MUST be included in every image extension."            )
+MK_PFL(  181.11,IMTM1_1 ,8, "IMage Transform Matrix; A unit vector in the"    )
+MK_PFL(  181.12,IMTM1_2 ,8, " serial (fast) direction of amplifier readout"   )
+MK_PFL(  181.21,IMTM2_1 ,8, "And a unit vector in parallel (slow) direction"  )
+MK_PFL(  181.22,IMTM2_2 ,8, " of amplifier readout"                           )
+MK_INT(  184.01,CELLGAP1,   "Cell gap between columns (in unbinned pixels)"   )
+MK_INT(  184.02,CELLGAP2,   "Cell gap between rows (in unbinned pixels)"      )
+MK_INT(  184.11,CNAXIS1 ,   "Cell imaging size in unbinned pixel columns"     )
+MK_INT(  184.12,CNAXIS2 ,   "Cell imaging size in unbinned pixel rows"        )
+MK_INT(  184.21,CNPIX1  ,   "Offset in unbinned pixel cols to readout start"  )
+MK_INT(  184.22,CNPIX2  ,   "Offset in unbinned pixel rows to readout start"  )
+MK_INT(  185.1,	CCDBIN1	,   "Binning factor along axis 1"                     )
+MK_INT(  185.2,	CCDBIN2	,   "Binning factor along axis 2"                     )
+MK_INT(  186.1, PRESCAN1,   "Prescan count on axis 1"                         )
+MK_INT(  186.2, PRESCAN2,   "Prescan count on axis 2"                         )
+MK_INT(  187.1, OVRSCAN1,   "Overscan count on axis 1"                        )
+MK_INT(  187.2, OVRSCAN2,   "Overscan count on axis 2"                        )
+MK_CMT(  195.01,CMTIRAF1,   ""                                                )
+MK_CMT(  195.02,CMTIRAF2,   "  Iraf coordinates"                              )
+MK_CMT(  195.03,CMTIRAF3,   "  ----------------"                              )
+MK_STR(  195.1, CCDSUM  ,   "Binning factors"                                 )
+MK_STR(  195.2,	DATASEC ,   "Imaging area of the detector"                    )
+MK_STR(  195.3,	BIASSEC ,   "Overscan (bias) area"                            )
+MK_STR(  195.4,	CCDSIZE ,   "Detector imaging area size"                      )
+MK_STR(  195.5, CCDSEC  ,   "Unbinned mapping of read section to CCD"         )
+MK_STR(  195.6, DETSIZE	,   "Iraf total image pixels in full mosaic"          )
+MK_STR(  195.7,	DETSEC  ,   "Iraf mosaic area of the detector"                )
+MK_PFL(  196.01,LTV1    ,8, "Iraf image transformation vector"                )
+MK_PFL(  196.02,LTV2    ,8, "Iraf image transformation vector"                )
+MK_PFL(  196.11,LTM1_1  ,8, "Iraf image transformation matrix"                )
+MK_PFL(  196.12,LTM1_2  ,8, "Iraf image transformation matrix"                )
+MK_PFL(  196.21,LTM2_1  ,8, "Iraf image transformation matrix"                )
+MK_PFL(  196.22,LTM2_2  ,8, "Iraf image transformation matrix"                )
+MK_PFL(  197.01,ATV1    ,8, "Iraf amplifier transformation vector"            )
+MK_PFL(  197.02,ATV2    ,8, "Iraf amplifier transformation vector"            )
+MK_PFL(  197.11,ATM1_1  ,8, "Iraf amplifier transformation matrix"            )
+MK_PFL(  197.12,ATM1_2  ,8, "Iraf amplifier transformation matrix"            )
+MK_PFL(  197.21,ATM2_1  ,8, "Iraf amplifier transformation matrix"            )
+MK_PFL(  197.22,ATM2_2  ,8, "Iraf amplifier transformation matrix"            )
+MK_CMT(  197.96,CMTCON1,    ""                                                )
+MK_CMT(  197.97,CMTCON2,    "  Controller Data"                               )
+MK_CMT(  197.98,CMTCON3,    "  ---------------"                               )
+MK_STR(  198.00,CONTROLR,   "Detector Controller"                             )
+MK_STR(  198.01,CONHWURL,   "Controller hardware SVN location"                )
+MK_STR(  198.02,CONHWV,     "Controller hardware SVN revision"                )
+MK_STR(  198.01,CONSWURL,   "Controller software SVN location"                )
+MK_STR(  198.02,CONSWV,     "Controller software SVN revision"                )
+MK_STR(  198.03,CON_MAC,    "Controller MAC (HW Ethernet) Address"            )
+MK_STR(  198.04,CON_IP,     "Controller IP Address"                           )
+MK_STR(  198.05,CON_NAME,   "Controller IP Hostname"                          )
+MK_INT(  198.06,CON_DEV,    "Controller device number (0 or 1)"               )
+MK_INT(  198.07,CON_UP,     "[seconds] Controller up-time"                    )
+MK_STR(  198.08,CON_VSUM,   "Device operating point md5sum"                   )
+MK_INT(  198.40,TSP_SHOP,   "Milliseconds from last clean to shutter open"    )
+MK_INT(  198.41,TSP_SHCL,   "Milliseconds from last clean to shutter close"   )
+MK_INT(  198.50,TSP_RD00,   "Milliseconds darktime for buffer (cell row) 0"   )
+MK_INT(  198.51,TSP_RD01,   "Milliseconds darktime for buffer (cell row) 1"   )
+MK_INT(  198.52,TSP_RD02,   "Milliseconds darktime for buffer (cell row) 2"   )
+MK_INT(  198.53,TSP_RD03,   "Milliseconds darktime for buffer (cell row) 3"   )
+MK_INT(  198.54,TSP_RD04,   "Milliseconds darktime for buffer (cell row) 4"   )
+MK_INT(  198.55,TSP_RD05,   "Milliseconds darktime for buffer (cell row) 5"   )
+MK_INT(  198.56,TSP_RD06,   "Milliseconds darktime for buffer (cell row) 6"   )
+MK_INT(  198.57,TSP_RD07,   "Milliseconds darktime for buffer (cell row) 7"   )
+MK_INT(  198.60,TSP_NOW,    "Milliseconds from last clean until save"         )
+MK_STR(  199.01,CLV_PPG4,   "Coded parallel timings"                          )
+MK_STR(  199.02,CLV_PG3,    "Coded serial timings"                            )
+MK_STR(  199.03,CLV_PG4,    "Coded SW/RST/VCLAMP/SAMP"                        )
+MK_STR(  199.04,CLV_ADC,    "Coded ADC parameters"                            )
+MK_INT(  199.05,CLV_TRIG,   "Cross-trigger phase delay (x 10nsec)"            )
+MK_INT(  199.06,CLV_PRES,   "Serial prescan, (skipped in addition to CNPIX1)" )
+MK_INT(  199.07,CLV_PIPE,   "Clocking pattern pipeline (in addition to ADC)"  )
+MK_INT(  199.071,CLV_PXTP,  "OT Pixel Type 1 or 2 (or 0 for normal CCD)"      )
+MK_STR(  199.072,ADC_CONF,  "ADC configuration"                               )
+MK_STR(  199.073,ADC_MUX,   "ADC MUX configuration"                           )
+MK_STR(  199.074,ADC_PGAR,  "Red ADC pga (adcgain val)"                       )
+MK_STR(  199.075,ADC_PGAG,  "Grn ADC pga (adcgain val)"                       )
+MK_STR(  199.076,ADC_PGAB,  "Blu ADC pga (adcgain val)"                       )
+MK_STR(  199.077,ADC_OFSR,  "Red ADC offset"                                  )
+MK_STR(  199.078,ADC_OFSG,  "Grn ADC offset"                                  )
+MK_STR(  199.079,ADC_OFSB,  "Blu ADC offset"                                  )
+MK_INT(  199.08,DAC_INIT,   "[mV] DAC internal vref offset voltage"           )
+MK_PFL(  199.09,DAC_S_L,3,  "[V] Serial and summing well LO"                  )
+MK_PFL(  199.10,DAC_S_H,3,  "[V] Serial and summing well HI"                  )
+MK_PFL(  199.11,DAC_SW_L,3, "[V] Summing Well LO           "                  )
+MK_PFL(  199.12,DAC_SW_H,3, "[V] Summing Well HI           "                  )
+MK_PFL(  199.13,DAC_S1_L,3, "[V] Serial 1 LO               "                  )
+MK_PFL(  199.14,DAC_S1_H,3, "[V] Serial 1 HI               "                  )
+MK_PFL(  199.15,DAC_S2_L,3, "[V] Serial 2 LO               "                  )
+MK_PFL(  199.16,DAC_S2_H,3, "[V] Serial 2 HI               "                  )
+MK_PFL(  199.17,DAC_S3_L,3, "[V] Serial 3 LO               "                  )
+MK_PFL(  199.18,DAC_S3_H,3, "[V] Serial 3 HI               "                  )
+MK_PFL(  199.19,DAC_P_L,3,  "[V] Parallel and P. standby LO"                  )
+MK_PFL(  199.20,DAC_P_H,3,  "[V] Parallel and P. standby HI"                  )
+MK_PFL(  199.21,DAC_P1_L,3, "[V] Parallel 1 LO             "                  )
+MK_PFL(  199.22,DAC_P1_H,3, "[V] Parallel 1 HI             "                  )
+MK_PFL(  199.23,DAC_P2_L,3, "[V] Parallel 2 LO             "                  )
+MK_PFL(  199.24,DAC_P2_H,3, "[V] Parallel 2 HI             "                  )
+MK_PFL(  199.25,DAC_P3_L,3, "[V] Parallel 3 LO             "                  )
+MK_PFL(  199.26,DAC_P3_H,3, "[V] Parallel 3 HI             "                  )
+MK_PFL(  199.27,DAC_P4_L,3, "[V] Parallel 4 LO             "                  )
+MK_PFL(  199.28,DAC_P4_H,3, "[V] Parallel 4 HI             "                  )
+MK_PFL(  199.29,DAC_PSL,3,  "[V] Parallel Standby LO       "                  )
+MK_PFL(  199.30,DAC_PSH,3,  "[V] Parallel Standby HI       "                  )
+MK_PFL(  199.31,DAC_RG_L,3, "[V] Reset Gate LO             "                  )
+MK_PFL(  199.32,DAC_RG_H,3, "[V] Reset Gate HI             "                  )
+MK_PFL(  199.33,DAC_SO,3,   "[V] 1st Stage Source          "                  )
+MK_PFL(  199.34,DAC_DR,3,   "[V] Drain Bias                "                  )
+MK_PFL(  199.35,DAC_VSS,3,  "[V] Logic Low Supply          "                  )
+MK_PFL(  199.36,DAC_VDDL,3, "[V] Logic Drain Supply LO     "                  )
+MK_PFL(  199.37,DAC_VDDH,3, "[V] Logic Drain Supply HI     "                  )
+MK_PFL(  199.38,DAC_OG1,3,  "[V] Output Gate Bias          "                  )
+MK_PFL(  199.39,DAC_RD,3,   "[V] Reset Drain Bias          "                  )
+MK_PFL(  199.40,DAC_SUB,3,  "[V] Substrate                 "                  )
+MK_PFL(  199.41,DAC_SCP,3,  "[V] Scupper Bias              "                  )
+MK_PFL(  199.42,DAC_LREF,3, "[V] Logic Reference Ground    "                  )
+MK_STR(  199.70,DAC_CAL0,   "[mV] Pedestal cal"                               )
+MK_STR(  199.71,DAC_CAL1,   "[mV] Pedestal cal"                               )
+MK_STR(  199.72,DAC_CAL2,   "[mV] Pedestal cal"                               )
+MK_STR(  199.73,DAC_CAL3,   "[mV] Pedestal cal"                               )
+MK_STR(  199.74,DAC_CAL4,   "[mV] Pedestal cal"                               )
+MK_STR(  199.75,DAC_CAL5,   "[mV] Pedestal cal"                               )
+MK_STR(  199.76,DAC_CAL6,   "[mV] Pedestal cal"                               )
+MK_STR(  199.77,DAC_CAL7,   "[mV] Pedestal cal"                               )
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_instrument.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_instrument.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_instrument.h	(revision 23490)
@@ -0,0 +1,81 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`gpc_instrument.h' - Pan-STARRS instrument FITS header keywords
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include "macros.h"
+
+/*
+ * Description of columns:
+ *
+ *      TYPE - MK_BLN, MK_STR, MK_INT, MK_FLT, MK_PFL selects a type for the
+ *             keyword (True/False, 'String  ', integer, or floating point.)
+ *             Any keyword can still be set to any type with fh_setval_*(),
+ *             which takes a pre-formatted character string for the card.
+ *
+ *      IDX  - Index sorting number, which eventually determines the final
+ *             order of keywords in the FITS header.  These are floating point
+ *             values so new keywords can always be inserted in between
+ *             without shifting all the values.
+ *
+ *   KEYWORD - The name of the keyword.  Macros will be generated of the form
+ *             fh_get_KEYWORD(), fh_set_KEYWORD(), and fh_setval_KEYWORD().
+ *
+ *      PRC  - For MK_FLT(), this specifies the (scientific) precision,
+ *             or number of significant digits in the value.  If necessary,
+ *             scientific notation will be used to format the value (see
+ *             rules for printf "%.*G").
+ *             For MK_PFL(), this specifies mathematical precision, or number
+ *             of decimal places in the formatted value (see the rules for
+ *             printf "%.*f").
+ *
+ *             Use MK_PFL() (make "precise float") if that value is always
+ *             precise to an exact number digits after the decimal point.
+ *             Use MK_FLT() if the value might require scientific notation.
+ *             All results are FITS-standard legal.
+ *
+ *   COMMENT - String to be included after the / in the FITS card, if
+ *             there is room within the 80 columns (it may get truncated.)
+ *             Note that in the text below, 80 columns are reached when
+ *             there is still one space between the " and the ) at the end
+ *             of the line.
+ *
+ * FITS Structure : 0.000 to 9.999
+ *
+ * The following keywords give miscellaneous information about
+ * the instrument in general that doesn't really fit anywhere 
+ * else.
+ * 
+ * Instrument : 1000.000 to 1999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT( 1000.00,CMTINST1,   ""                                                )
+MK_CMT( 1000.10,CMTINST2,   "Instrument Information"                          )
+MK_CMT( 1000.20,CMTINST3,   "----------------------"                          )
+MK_CMT( 1000.40,CMTINST4,   ""                                                )
+MK_PFL( 1009.0, PRESSURE,6, "[Torr] Micropirani pressure reading"             )
+MK_PFL( 1009.10,L3HUMID, 1, "[%] Relative humidity in space above L3"         )
+MK_PFL( 1009.11,L3AIRTMP,1, "[C] Air temperature in space above L3"           )
+MK_PFL( 1009.12,L3DEWPT, 1, "[C] Calculated dew point in space above L3"      )
+MK_STR( 1010.0, FILTSTAT,   "Filter mechanism status"                         )
+MK_STR( 1010.1, FILTERID,   "Filter glass identification"                     )
+MK_STR( 1010.2, FILTER  ,   "Filter band name OPEN,u,g,r,i,z,y,w"             )
+MK_STR( 1011.0, VIDMODE,    "Video mode used (w pix x h pix x rate Hz)"       )
+MK_PFL( 1110.1, DEWTEM1, 1, "[K] Dewar rtd 1 (CTI-Left head)"                 )
+MK_PFL( 1110.2, DEWTEM2, 1, "[K] Dewar rtd 2 (Copper plate)"                  )
+MK_PFL( 1110.3, DEWTEM3, 1, "[K] Dewar rtd 3 (OTA67 package)"                 )
+MK_PFL( 1110.4, DEWTEM4, 1, "[K] Dewar rtd 4 (Triangle post)"                 )
+MK_PFL( 1110.5, DEWTEM5, 1, "[K] Dewar rtd 5 (Copper bar)"                    )
+MK_PFL( 1110.6, DEWTEM6, 1, "[K] Dewar rtd 6 (CTI-Right head)"                )
+MK_PFL( 1210.1, SH_TEM,  1, "[K] Shack Hartmann head temperature"             )
+MK_INT( 1220.1, SH_POS    , "[steps] Shack Hartmann arm position"             )
+MK_INT( 1221.0, SH_STDLY  , "[2.04us/step] S-H arm step delay"                )
+MK_INT( 1222.0, SH_ACCEL  , "[2.04us/step^2] S-H acceleration param"          )
+MK_INT( 1223.0, SH_MNDLY  , "[2.04us/step] S-H minimum step delay"            )
+MK_INT( 1224.0, SH_ARMPN  , "motion controller input pins"                    )
+MK_PFL( 1225.0, SH_DIODE,1, "Vref/4096 (Vref=5V nominal) photodiode volts"    )
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_otguide.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_otguide.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_otguide.h	(revision 23490)
@@ -0,0 +1,82 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`gpc_otguide.h' - Pan-STARRS GPC OT correction and Guider keywords
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include "macros.h"
+
+/*
+ * Description of columns:
+ *
+ *      TYPE - MK_BLN, MK_STR, MK_INT, MK_FLT, MK_PFL selects a type for the
+ *             keyword (True/False, 'String  ', integer, or floating point.)
+ *             Any keyword can still be set to any type with fh_setval_*(),
+ *             which takes a pre-formatted character string for the card.
+ *
+ *      IDX  - Index sorting number, which eventually determines the final
+ *             order of keywords in the FITS header.  These are floating point
+ *             values so new keywords can always be inserted in between
+ *             without shifting all the values.
+ *
+ *   KEYWORD - The name of the keyword.  Macros will be generated of the form
+ *             fh_get_KEYWORD(), fh_set_KEYWORD(), and fh_setval_KEYWORD().
+ *
+ *      PRC  - For MK_FLT(), this specifies the (scientific) precision,
+ *             or number of significant digits in the value.  If necessary,
+ *             scientific notation will be used to format the value (see
+ *             rules for printf "%.*G").
+ *             For MK_PFL(), this specifies mathematical precision, or number
+ *             of decimal places in the formatted value (see the rules for
+ *             printf "%.*f").
+ *
+ *             Use MK_PFL() (make "precise float") if that value is always
+ *             precise to an exact number digits after the decimal point.
+ *             Use MK_FLT() if the value might require scientific notation.
+ *             All results are FITS-standard legal.
+ *
+ *   COMMENT - String to be included after the / in the FITS card, if
+ *             there is room within the 80 columns (it may get truncated.)
+ *             Note that in the text below, 80 columns are reached when
+ *             there is still one space between the " and the ) at the end
+ *             of the line.
+ *
+ * FITS Structure : 0.000 to 9.999
+ *
+ * The following keywords give basic information about the structure and
+ * dimensions of the FITS file, and must appear in the specific order
+ * below, usually without any other intervening keywords.
+ *
+ * Guider : ???
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  250.00,CMTOTGD1 ,   ""                                               )
+MK_CMT(  250.01,CMTOTGD2 ,   "Guide Star Info"                                )
+MK_CMT(  250.02,CMTOTGD3 ,   "---------------"                                )
+MK_STR(  250.10,GS_ID,      "Guide star catalogue ID/name"                    )
+MK_PFL(  250.20,GS_PRRA,6,  "[degrees] Guide star predicted RA"               )
+MK_PFL(  250.30,GS_PRDEC,6, "[degrees] Guide star predicted DEC"              )
+MK_PFL(  250.40,GS_PRFP1,2, "[microns] Guide star pred. focal plane pos"      )
+MK_PFL(  250.50,GS_PRFP2,2, "[microns] Guide star pred. focal plane pos"      )
+MK_INT(  250.60,GS_PREDX,   "[unbinned pix] Guide star predicted X position"  )
+MK_INT(  250.70,GS_PREDY,   "[unbinned pix] Guide star predicted Y position"  )
+MK_PFL(  250.80,GS_PRMAG,2, "Guide star predicted magnitude with curr filter" )
+MK_STR(  251.07,GS_PSF,     "Video PSF algorithm used for centroid"           )
+MK_PFL( 251.081,GS_CORX, 6, "[pix] GS calc correction applied in camera X"    )
+MK_PFL( 251.082,GS_CORY, 6, "[pix] GS calc correction applied in camera Y"    )
+MK_PFL( 251.083,GS_CORPA,6, "[deg] GS calc correction applied to rotation"    )
+MK_PFL(  251.10,GS_CPIX1,2, "Guide star centroid from origin of CNAXIS system")
+MK_PFL(  251.20,GS_CPIX2,2, "Guide star centroid from origin of CNAXIS system")
+MK_PFL(  252.00,GS_FWHM, 2, "[pix] Guide star full width at half maximum"     )
+MK_PFL(  252.10,GS_FWHM1,2, "[pix] Guide star full width at half maximum in x")
+MK_PFL(  252.20,GS_FWHM2,2, "[pix] Guide star full width at half maximum in y")
+MK_PFL(  253.00,GS_PSKY, 2, "[adu] Sky level in guide box"                    )
+MK_PFL(  254.00,GS_PFLUX,2, "[adu] Total flux in star"                        )
+MK_PFL(  255.00,GS_SN   ,2, "Guide star signal to noise ratio"                )
+MK_PFL(  259.10,GS_AVFW ,2, "[pix] Average FWHM to present"                   )
+MK_PFL(  259.20,GS_AVX  ,2, "[microns] Average focal plane X pos to present"  )
+MK_PFL(  259.30,GS_AVY  ,2, "[microns] Average focal plane Y pos to present"  )
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_plant.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_plant.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_plant.h	(revision 23490)
@@ -0,0 +1,9 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`gpc_plant.h' - Pan-STARRS plant-related FITS header keywords
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_shutter.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_shutter.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_shutter.h	(revision 23490)
@@ -0,0 +1,71 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`gpc_instrument.h' - Pan-STARRS instrument FITS header keywords
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include "macros.h"
+
+/*
+ * Description of columns:
+ *
+ *      TYPE - MK_BLN, MK_STR, MK_INT, MK_FLT, MK_PFL selects a type for the
+ *             keyword (True/False, 'String  ', integer, or floating point.)
+ *             Any keyword can still be set to any type with fh_setval_*(),
+ *             which takes a pre-formatted character string for the card.
+ *
+ *      IDX  - Index sorting number, which eventually determines the final
+ *             order of keywords in the FITS header.  These are floating point
+ *             values so new keywords can always be inserted in between
+ *             without shifting all the values.
+ *
+ *   KEYWORD - The name of the keyword.  Macros will be generated of the form
+ *             fh_get_KEYWORD(), fh_set_KEYWORD(), and fh_setval_KEYWORD().
+ *
+ *      PRC  - For MK_FLT(), this specifies the (scientific) precision,
+ *             or number of significant digits in the value.  If necessary,
+ *             scientific notation will be used to format the value (see
+ *             rules for printf "%.*G").
+ *             For MK_PFL(), this specifies mathematical precision, or number
+ *             of decimal places in the formatted value (see the rules for
+ *             printf "%.*f").
+ *
+ *             Use MK_PFL() (make "precise float") if that value is always
+ *             precise to an exact number digits after the decimal point.
+ *             Use MK_FLT() if the value might require scientific notation.
+ *             All results are FITS-standard legal.
+ *
+ *   COMMENT - String to be included after the / in the FITS card, if
+ *             there is room within the 80 columns (it may get truncated.)
+ *             Note that in the text below, 80 columns are reached when
+ *             there is still one space between the " and the ) at the end
+ *             of the line.
+ *
+ * Shutter: 200.000 to 209.999
+ *
+ * The following keywords give information about the shutter system
+ * for a given exposure.
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  200.0, CMTSHU1 ,   ""                                                )
+MK_CMT(  200.1, CMTSHU2 ,   "Shutter"                                         )
+MK_CMT(  200.2, CMTSHU3 ,   "-------"                                         )
+MK_STR(  201.0,	SHUTSTAT,   "Shutter status"                                  )
+MK_STR(  201.1,	SHUTERR,    "Shutter error code"                              )
+MK_STR(  202.00,SHUTOPEN,   "Shutter open time (TAI)"                         )
+MK_STR(  202.01,SHUTCLOS,   "Shutter close time (TAI)"                        )
+MK_PFL(  202.02,SHUTOPWN,6, "Shutter open uncertainty before SHUTOPEN (sec)"  )
+MK_PFL(  202.03,SHUTCLWN,6, "Shutter close uncertainty before SHUTCLOS (sec)" )
+MK_STR(  202.04,SHUTOUTC,   "Shutter open time (UTC)"                         )
+MK_STR(  202.05,SHUTCUTC,   "Shutter close time (UTC)"                        )
+MK_INT(  202.06,SHUTLEAP,   "Leap seconds used in TAI-UTC conversion (sec)"   )
+MK_PFL(  202.07,SHUTREQ, 6, "Requested exposure duration (sec)"               )
+MK_PFL(  202.08,SHUTTIME,6, "Actual exposure duration (sec)"                  )
+MK_STR(  202.09,SHUTOPBL,   "Shutter blade in aperture at start of exposure"  )
+MK_STR(  202.10,SHUTCLBL,   "Shutter blade in aperture at end of exposure"    )
+MK_STR(  209.0, SHUTDAVR,   "Shutter daemon version"                          )
+MK_STR(  209.1, SHUTDRVR,   "Shutter driver version"                          )
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_telescope.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_telescope.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_telescope.h	(revision 23490)
@@ -0,0 +1,166 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`gpc_telescope.h' - Pan-STARRS TCS FITS header keywords
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include "macros.h"
+
+/*
+ * Description of columns:
+ *
+ *      TYPE - MK_BLN, MK_STR, MK_INT, MK_FLT, MK_PFL selects a type for the
+ *             keyword (True/False, 'String  ', integer, or floating point.)
+ *             Any keyword can still be set to any type with fh_setval_*(),
+ *             which takes a pre-formatted character string for the card.
+ *
+ *      IDX  - Index sorting number, which eventually determines the final
+ *             order of keywords in the FITS header.  These are floating point
+ *             values so new keywords can always be inserted in between
+ *             without shifting all the values.
+ *
+ *   KEYWORD - The name of the keyword.  Macros will be generated of the form
+ *             fh_get_KEYWORD(), fh_set_KEYWORD(), and fh_setval_KEYWORD().
+ *
+ *      PRC  - For MK_FLT(), this specifies the (scientific) precision,
+ *             or number of significant digits in the value.  If necessary,
+ *             scientific notation will be used to format the value (see
+ *             rules for printf "%.*G").
+ *             For MK_PFL(), this specifies mathematical precision, or number
+ *             of decimal places in the formatted value (see the rules for
+ *             printf "%.*f").
+ *
+ *             Use MK_PFL() (make "precise float") if that value is always
+ *             precise to an exact number digits after the decimal point.
+ *             Use MK_FLT() if the value might require scientific notation.
+ *             All results are FITS-standard legal.
+ *
+ *   COMMENT - String to be included after the / in the FITS card, if
+ *             there is room within the 80 columns (it may get truncated.)
+ *             Note that in the text below, 80 columns are reached when
+ *             there is still one space between the " and the ) at the end
+ *             of the line.
+ *
+ * FITS Structure : 0.000 to 9.999
+ *
+ * The following keywords give basic information about the structure and
+ * dimensions of the FITS file, and must appear in the specific order
+ * below, usually without any other intervening keywords.
+ *
+ *  * Telescope : 500.000 to 599.999
+ *
+ * Almost all keywords we define can be generated with the MK_XXX macros.
+ * The only exceptions are those keywords which contain a '-', since the
+ * '-' is not a legal character in a C identifier.  TCS uses four of them
+ * (DATE-OBS, UTC-OBS, MJD-OBS, and LST-OBS.)  The ID_XXX macros are used
+ * and the '-' is translated to a '_' (underscore) for use in C programs.
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  500.00,CMTPNT1 ,   ""                                                )
+MK_CMT(  500.10,CMTPNT2 ,   "Telescope and Pointing Information"              )
+MK_CMT(  500.20,CMTPNT3 ,   "----------------------------------"              )
+MK_CMT(  500.40,CMTPNT4 ,   ""                                                )
+MK_STR(  501.00,TELESCOP,   "Telescope"                                       )
+ID_PFL( 513.1,  MJD_OBS ,"MJD-OBS",7, "Modified Julian Date at start of obs." )
+ID_STR( 514.1,  LST_OBS ,"LST-OBS", "Local Sidereal time at start of obs."    )
+MK_STR(  503.0, TELSTAT ,   "Telescope control system status"                 )
+MK_STR(  503.1, DOMSTAT ,   "Telescope enclosure status"                      )
+MK_STR(  503.2, GUISTAT ,   "Telescope guiding system status"                 )
+MK_STR(  503.3, GUICONF ,   "Telescope guiding configuration"                 )
+MK_STR(  503.4, GUIKERN ,   "Filter kernel used for guiding"                  )
+MK_PFL(  503.5, GUIGAIX ,2, "Telescope guiding gain factor (x offset)"        )
+MK_PFL(  503.6, GUIGAIY ,2, "Telescope guiding gain factor (y offset)"        )
+MK_PFL(  503.7, GUIRATE ,1, "Telescope guiding rate (Hz)"                     )
+MK_VAL(  521.1, EQUINOX ,   "Telescope equinox of coordinates"                )
+MK_VAL(  521.2, EPOCH   ,   "Telescope equinox of coordinates"                )
+MK_PFL(  522.1, RA      ,6, "Telescope Right Ascension (degrees)"             )
+MK_PFL(  522.2, DEC     ,6, "Telescope Declination (degrees)"                 )
+MK_PFL(  522.3, AZ      ,6, "Telescope azimuth (degrees)"                     )
+MK_PFL(  522.4, ALT     ,6, "Telescope pointing altitude (degrees)"           )
+MK_PFL(  522.5, ROT     ,6, "Telescope rotator angle (degrees)"               )
+MK_PFL(  522.6, POSANGLE,6, "Telescope position angle (degrees)"              )
+MK_PFL(  522.7, PA_DEBUG,6, "Telescope position angle (alternate value)"      )
+MK_PFL(  523.0, COMRA   ,6, "Commanded telescope Right Ascension (degrees)"   )
+MK_PFL(  523.1, COMDEC  ,6, "Commanded telescope Declination (degrees)"       )
+MK_PFL(  523.2, COMAZ   ,6, "Commanded telescope azimuth (degrees)"           )
+MK_PFL(  523.3, COMALT  ,6, "Commanded telescope pointing altitude (degrees)" )
+MK_PFL(  523.4, COMROT  ,6, "Commanded telescope rotator angle (degrees)"     )
+MK_CMT(  530.00,CMTTELO1,   "NOTE: Telescope RA DEC or ALT AZ already include")
+MK_CMT(  530.10,CMTTELO2,   "      the following offsets.  Do not re-apply!"  )
+MK_PFL(  532.1, TELOFRA ,6, "Telescope offset in RA (degrees)"                )
+MK_PFL(  532.2, TELOFDEC,6, "Telescope offset in DEC (degrees)"               )
+MK_PFL(  532.3, TELOFAZ ,6, "Telescope offset in AZ (degrees)"                )
+MK_PFL(  532.4, TELOFALT,6, "Telescope offset in ALT (degrees)"               )
+MK_PFL(  532.5, TELOFROT,6, "Telescope offset in ROT (degrees)"               )
+MK_PFL(  532.7, TELOFX  ,6, "Telescope offset in camera X (degrees)"          )
+MK_PFL(  532.8, TELOFY  ,6, "Telescope offset in camera Y (degrees)"          )
+MK_PFL(  540.1, AIRMASS ,3, "Airmass at start of observation"                 )
+MK_PFL(  541.1, M1X     ,6, "Primary mirror x position (um)"                  )
+MK_PFL(  541.2, M1Y     ,6, "Primary mirror y position (um)"                  )
+MK_PFL(  541.3, M1Z     ,6, "Primary mirror z position (um)"                  )
+MK_PFL(  541.4, M1TIP   ,6, "Primary mirror tip (arcsec)"                     )
+MK_PFL(  541.5, M1TILT  ,6, "Primary mirror tilt (arcsec)"                    )
+MK_PFL(  542.1, M2X     ,6, "Secondary mirror x position (um)"                )
+MK_PFL(  542.2, M2Y     ,6, "Secondary mirror y position (um)"                )
+MK_PFL(  542.3, M2Z     ,6, "Secondary mirror z position (um)"                )
+MK_PFL(  542.4, M2TIP   ,6, "Secondary mirror tip (arcsec)"                   )
+MK_PFL(  542.5, M2TILT  ,6, "Secondary mirror tilt (arcsec)"                  )
+MK_STR(  543.0, M1M2MODV,   "Telescope mirror position model version"         )
+MK_PFL(  543.1, M1NOMX  ,6, "Modeled Primary mirror x position (um)"          )
+MK_PFL(  543.2, M1NOMY  ,6, "Modeled Primary mirror y position (um)"          )
+MK_PFL(  543.3, M1NOMZ  ,6, "Modeled Primary mirror z position (um)"          )
+MK_PFL(  543.4, M1NOMTIP,6, "Modeled Primary mirror tip (arcsec)"             )
+MK_PFL(  543.5, M1NOMTIL,6, "Modeled Primary mirror tilt (arcsec)"            )
+MK_PFL(  544.1, M2NOMX  ,6, "Modeled Secondary mirror x position (um)"        )
+MK_PFL(  544.2, M2NOMY  ,6, "Modeled Secondary mirror y position (um)"        )
+MK_PFL(  544.3, M2NOMZ  ,6, "Modeled Secondary mirror z position (um)"        )
+MK_PFL(  544.4, M2NOMTIP,6, "Modeled Secondary mirror tip (arcsec)"           )
+MK_PFL(  544.5, M2NOMTIL,6, "Modeled Secondary mirror tilt (arcsec)"          )
+MK_STR(  550.1, TELTEMTR,   "Mid truss temperatures (C)"                      )
+MK_STR(  550.2, TELTEMSP,   "Spider temperatures (C)"                         )
+MK_STR(  550.3, TELTEMMS,   "Primary mirror support temps (C)"                )
+MK_STR(  550.4, TELTEMM1,   "Primary mirror temps (C)"                        )
+MK_STR(  550.5, TELTEMM2,   "Secondary mirror temps (C)"                      )
+MK_STR(  550.6, TELTEMEX,   "Miscellaneous temperatures (C)"                  )
+
+/*
+ * Wavefront
+ */
+MK_PFL(  551.01,WVFA    ,14,"Wavefront A actuator force (N)"                  )
+MK_PFL(  551.02,WVFB    ,14,"Wavefront B actuator force (N)"                  )
+MK_PFL(  551.03,WVFC    ,14,"Wavefront C actuator force (N)"                  )
+MK_PFL(  551.04,WVFD    ,14,"Wavefront D actuator force (N)"                  )
+MK_PFL(  551.05,WVFE    ,14,"Wavefront E actuator force (N)"                  )
+MK_PFL(  551.06,WVFF    ,14,"Wavefront F actuator force (N)"                  )
+MK_PFL(  551.07,WVFG    ,14,"Wavefront G actuator force (N)"                  )
+MK_PFL(  551.08,WVFH    ,14,"Wavefront H actuator force (N)"                  )
+MK_PFL(  551.09,WVFI    ,14,"Wavefront I actuator force (N)"                  )
+MK_PFL(  551.10,WVFJ    ,14,"Wavefront J actuator force (N)"                  )
+MK_PFL(  551.11,WVFK    ,14,"Wavefront K actuator force (N)"                  )
+MK_PFL(  551.12,WVFL    ,14,"Wavefront L actuator force (N)"                  )
+
+/*
+ * These probably want to be in a different section... %%%
+ */
+MK_PFL(  560.1, ENVTEM,  1, "[C]           Weather, outside temperature"      )
+MK_PFL(  560.2, ENVHUM,  1, "[%]           Weather, relative humidity"        )
+MK_PFL(  560.3, ENVWIN,  1, "[m/s]         Weather, wind speed"               )
+MK_PFL(  560.4, ENVDIR,  1, "[deg E. of N] Weather, wind direction"           )
+MK_PFL(  561.0, SEEING,  1, "[arcsec]      Weather, seeing from DIMM, FWHM"   )
+
+/* 
+ * Other stuff Craig had put in general.h:
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_PFL( 586.02, HA      ,16,"Hour angle at start (degrees)"                   )
+MK_PFL( 586.03,	ST      ,16,"Sidereal time at start (hours)"                  )
+MK_PFL( 586.04,	ZD      ,16,"Zenith distance (degrees)"                       )
+MK_STR( 587.00,	RASTRNG ,   "Actual Right Ascension (incl offset)"            )
+MK_STR( 587.01,	DECSTRNG,   "Actual Declination (incl offset)"                )
+MK_STR( 587.02,	HASTRNG ,   "Hour angle at start"                             )
+MK_STR( 587.03,	STSTRNG ,   "Sidereal time at start"                          )     
+MK_STR( 587.04,	ZDSTRNG ,   "Zenith distance (deg:mm:ss)"                     )                   
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_wcs.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_wcs.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/gpc_wcs.h	(revision 23490)
@@ -0,0 +1,103 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`gpc_instrument.h' - Pan-STARRS instrument FITS header keywords
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+#include "macros.h"
+
+/*
+ * Description of columns:
+ *
+ *      TYPE - MK_BLN, MK_STR, MK_INT, MK_FLT, MK_PFL selects a type for the
+ *             keyword (True/False, 'String  ', integer, or floating point.)
+ *             Any keyword can still be set to any type with fh_setval_*(),
+ *             which takes a pre-formatted character string for the card.
+ *
+ *      IDX  - Index sorting number, which eventually determines the final
+ *             order of keywords in the FITS header.  These are floating point
+ *             values so new keywords can always be inserted in between
+ *             without shifting all the values.
+ *
+ *   KEYWORD - The name of the keyword.  Macros will be generated of the form
+ *             fh_get_KEYWORD(), fh_set_KEYWORD(), and fh_setval_KEYWORD().
+ *
+ *      PRC  - For MK_FLT(), this specifies the (scientific) precision,
+ *             or number of significant digits in the value.  If necessary,
+ *             scientific notation will be used to format the value (see
+ *             rules for printf "%.*G").
+ *             For MK_PFL(), this specifies mathematical precision, or number
+ *             of decimal places in the formatted value (see the rules for
+ *             printf "%.*f").
+ *
+ *             Use MK_PFL() (make "precise float") if that value is always
+ *             precise to an exact number digits after the decimal point.
+ *             Use MK_FLT() if the value might require scientific notation.
+ *             All results are FITS-standard legal.
+ *
+ *   COMMENT - String to be included after the / in the FITS card, if
+ *             there is room within the 80 columns (it may get truncated.)
+ *             Note that in the text below, 80 columns are reached when
+ *             there is still one space between the " and the ) at the end
+ *             of the line.
+ *
+ * WCS: 600.0 to 609.99
+ *
+ * The following keywords give information about the various WCS coordinate
+ * systems available for the FITS file.
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT( 600.0,  CMTWCS1 ,   ""                                                )
+MK_CMT( 600.1,  CMTWCS2 ,   "WCS Coordinate Systems"                          )
+MK_CMT( 600.2,  CMTWCS3 ,   "----------------------"                          )
+
+MK_STR( 601.10, CTYPE1  ,   "R.A. in tangent plane projection"                )
+MK_STR( 601.11, CUNIT1  ,   "Units for focal plane coord system axis 1"       )
+MK_PFL( 601.12, CRVAL1  ,6, "R.A. at ref. pixel"                              )
+MK_PFL( 601.13, CRPIX1  ,1, "Ref. pixel of first axis"                        )
+MK_PFL( 601.14, CDELT1  ,10,"R.A. pixel step"                                 )
+MK_STR( 601.15, CTYPE2  ,   "Dec. in tangent plane projection"                )
+MK_STR( 601.16, CUNIT2  ,   "Units for focal plane coord system axis 1"       )
+MK_PFL( 601.17, CRVAL2  ,6, "Dec. at ref. pixel"                              )
+MK_PFL( 601.18, CRPIX2  ,1, "Ref. pixel of second axis"                       )
+MK_PFL( 601.19, CDELT2  ,10,"Dec. pixel step"                                 )
+MK_PFL( 601.20, CD1_1   ,10,"CD transform matrix"                             )
+MK_PFL( 601.21, CD1_2   ,10,"CD transform matrix"                             )
+MK_PFL( 601.22, CD2_1   ,10,"CD transform matrix"                             )
+MK_PFL( 601.23, CD2_2   ,10,"CD transform matrix"                             )
+
+MK_STR( 602.00, WCSNAMEA,   "Redundant reiteration of default WCS system"     )
+MK_STR( 602.10, CTYPE1A ,   "R.A. in tangent plane projection"                )
+MK_STR( 602.11, CUNIT1A ,   "Units for focal plane coord system axis 1"       )
+MK_PFL( 602.12, CRVAL1A ,6, "R.A. at ref. pixel"                              )
+MK_PFL( 602.13, CRPIX1A ,1, "Ref. pixel of first axis"                        )
+MK_PFL( 602.14, CDELT1A ,10,"R.A. pixel step"                                 )
+MK_STR( 602.15, CTYPE2A ,   "Dec. in tangent plane projection"                )
+MK_STR( 602.16, CUNIT2A ,   "Units for focal plane coord system axis 1"       )
+MK_PFL( 602.17, CRVAL2A ,6, "Dec. at ref. pixel"                              )
+MK_PFL( 602.18, CRPIX2A ,1, "Ref. pixel of second axis"                       )
+MK_PFL( 602.19, CDELT2A ,10,"Dec. pixel step"                                 )
+MK_PFL( 602.20, CD1_1A  ,10,"CD transform matrix"                             )
+MK_PFL( 602.21, CD1_2A  ,10,"CD transform matrix"                             )
+MK_PFL( 602.22, CD2_1A  ,10,"CD transform matrix"                             )
+MK_PFL( 602.23, CD2_2A  ,10,"CD transform matrix"                             )
+
+MK_STR( 603.00, WCSNAMEU,   "Position on instrument focal plane"              )
+MK_STR( 603.10, CTYPE1U ,   "Linear instrument focal plane position"          )
+MK_STR( 603.11, CUNIT1U ,   "Units for focal plane coord system axis 1"       )
+MK_PFL( 603.12, CRVAL1U ,6, "Focal plane position at reference pixel"         )
+MK_PFL( 603.13, CRPIX1U ,1, "Ref. pixel of first axis"                        )
+MK_PFL( 603.14, CDELT1U ,10,"Pixel step"                                      )
+MK_STR( 603.15, CTYPE2U ,   "Linear instrument focal plane position"          )
+MK_STR( 603.16, CUNIT2U ,   "Units for focal plane coord system axis 2"       )
+MK_PFL( 603.17, CRVAL2U ,6, "Focal plane position at reference pixel"         )
+MK_PFL( 603.18, CRPIX2U ,1, "Ref. pixel of second axis"                       )
+MK_PFL( 603.19, CDELT2U ,10,"Pixel step"                                      )
+MK_PFL( 603.20, CD1_1U  ,10,"CD transform matrix"                             )
+MK_PFL( 603.21, CD1_2U  ,10,"CD transform matrix"                             )
+MK_PFL( 603.22, CD2_1U  ,10,"CD transform matrix"                             )
+MK_PFL( 603.23, CD2_2U  ,10,"CD transform matrix"                             )
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/junk
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/junk	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/junk	(revision 23490)
@@ -0,0 +1,686 @@
+
+/* ****************************************************
+ * *** World Coordinate System : 300.000 to 399.999 ***
+ * ****************************************************
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+/*
+ * Telescope : 500.000 to 599.999
+ *
+ * Almost all keywords we define can be generated with the MK_XXX macros.
+ * The only exceptions are those keywords which contain a '-', since the
+ * '-' is not a legal character in a C identifier.  TCS uses four of them
+ * (DATE-OBS, UTC-OBS, MJD-OBS, and LST-OBS.)  The ID_XXX macros are used
+ * and the '-' is translated to a '_' (underscore) for use in C programs.
+ *
+ * NOTE: TELESCOP, TELSTAT, TELCONF, LATITUDE, and LONGITUD are currently
+ * inserted by DetCom and _not_ tcsh.  This should probably be changed.
+ *
+ * Further details on some less obvious keywords:
+ *
+ *   SKYFLUX  - if the guider(s) can generate a reasonable guess for the
+ *              amount of flux currently available for doing flats, that
+ *              number is in this keyword - negative means not available
+ *
+ *   GUIFLUXn - these values are the most recent one minute average of the
+ *              total flux seen in whatever guiding box/area is in use
+ *
+ *   GUIFWH?n - these are the most recent one minute average FWHM values
+ *              for the x/y axes of the guider image(s) recorded at the
+ *              start of the exposure
+ *
+ *   ISUSTDV? - these are the most recent one minute standard deviations
+ *              in the ISU x and y positions in arc seconds recorded
+ *              at the start of the exposure
+ *
+ *   FSAstats - the FSA statistics are for the most recent 10 minutes
+ *              recorded at the start of the exposure
+ *
+ * If there are multiple guiders in use, the unnumbered GUIEQUIN/GUIRADEC
+ * /GUIRA/GUIDEC/GUIRAPM/GUIDECPM values will duplicate the numbered
+ * values for the primary, reference guider.  If there is only one guider
+ * in use, only the unnumbered values should be present.
+ *
+ *TYPE --IDX--  SYMBOL--  KEYWORD-  -----------COMMENT----------------------*/
+ID_STR( 511.1,	DATE_OBS,"DATE-OBS", "Date at start of observation (UTC)"     )
+ID_STR( 512.1,	UTC_OBS ,"UTC-OBS", "Time at start of observation (UTC)"      )
+ID_PFL( 513.1,  MJD_OBS ,"MJD-OBS",7, "Modified Julian Date at start of obs." )
+ID_STR( 514.1,	LST_OBS ,"LST-OBS", "Sidereal time at start of exposure"      )
+
+/*TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+MK_CMT(  500.1, CMTTCS1 ,   ""                                                )
+MK_CMT(  500.2, CMTTCS2 ,   "Telescope"                                       )
+MK_CMT(  500.3, CMTTCS3 ,   "---------"                                       )
+MK_CMT(  500.4, CMTTCS4 ,   ""                                                )
+MK_STR(  501.1, TELESCOP,   ""                                                )
+MK_STR(  501.2, ORIGIN  ,   "Canada-France-Hawaii Telescope"                  )
+MK_PFL(  502.1, LATITUDE,6, "Latitude (degrees N)"                            )
+MK_PFL(  502.2, LONGITUD,6, "Longitude (degrees E)"                           )
+MK_STR(  503.0, TELSTAT ,   "Telescope Control System status"                 )
+MK_STR(  510.0, TIMESYS ,   "Time System for DATExxxx"                        )
+/* note that the following three have xxx.1 versions above */
+MK_STR(  512.0,	UTIME   ,   "Time at start of observation (UT)"               )
+MK_PFL(  513.0,	MJDATE  ,7 ,"Modified Julian Date at start of observation"    )
+MK_STR(  514.0,	SIDTIME ,   "Sidereal time at start of observation"           )
+MK_VAL(  521.0,	EPOCH   ,   "Equinox of coordinates"                          )
+MK_VAL(  521.1,	EQUINOX ,   "Equinox of coordinates"                          )
+MK_STR(  522.0,	RADECSYS,   "Coordinate system for equinox (FK4/FK5/GAPPT)"   )
+MK_STR(  522.1,	RA      ,   "Object right ascension"                          )
+MK_STR(  522.2,	DEC     ,   "Object declination"                              )
+MK_PFL(  523.1,	RA_DEG  ,6, "Object right ascension in degrees"               )
+MK_PFL(  523.2,	DEC_DEG ,6, "Object declination in degrees"                   )
+
+MK_PFL(525.101,	CRVAL1	,5, "WCS Ref value (RA in decimal degrees)"           )
+MK_PFL(525.102,	CRVAL2	,5, "WCS Ref value (DEC in decimal degrees)"          )
+MK_STR(525.211,	CTYPE1	,   "WCS Coordinate type"                             )
+MK_STR(525.212,	CTYPE2	,   "WCS Coordinate type"                             )
+MK_PFL(525.301,	CRPIX1	,1, "WCS Coordinate reference pixel"                  )
+MK_PFL(525.302,	CRPIX2	,1, "WCS Coordinate reference pixel"                  )
+MK_FLT(525.411,	CD1_1	,6, "WCS Coordinate scale matrix"                     )
+MK_FLT(525.412,	CD1_2	,6, "WCS Coordinate scale matrix"                     )
+MK_FLT(525.421,	CD2_1	,6, "WCS Coordinate scale matrix"                     )
+MK_FLT(525.422,	CD2_2	,6, "WCS Coordinate scale matrix"                     )
+
+MK_INT(  530.0,	NGUIDER	,   "TCS Number of guiders"                           )
+MK_INT( 530.01, NGUISTAR,   "TCS number of guide stars/probes in use"         )
+MK_STR(  530.1, GUINAME ,   "TCS guider name"                                 )
+MK_VAL( 530.21,	GUIEQUIN,   "TCS guider equinox"                              )
+MK_STR( 530.22,	GUIRADEC,   "TCS guider system for equinox"                   )
+MK_STR( 530.23,	GUIRA   ,   "TCS guider right ascension"                      )
+MK_STR( 530.24,	GUIDEC  ,   "TCS guider declination"                          )
+MK_PFL( 530.25, GUIRAPM ,2, "TCS guider right ascension proper motion arcsec" )
+MK_PFL( 530.26, GUIDECPM,2, "TCS guider declination proper motion arcsec"     )
+MK_STR(  530.3, GUIOBJN ,   "TCS guider object name"                          )
+MK_PFL(  530.4, GUIMAGN ,1, "TCS guider object magnitude"                     )
+MK_PFL( 530.51,	XPROBE  ,3 ,"Telescope bonnette guide probe X position"       )
+MK_PFL( 530.52,	YPROBE  ,3 ,"Telescope bonnette guide probe Y position"       )
+MK_PFL( 530.53,	ZPROBE  ,3 ,"Telescope bonnette guide probe Z position"       )
+MK_INT(  530.6, GUIFLUX ,   "TCS guider flux"                                 )
+MK_PFL( 530.71, GUIFWHX ,2, "TCS guider average x FWHM in pixels"             )
+MK_PFL( 530.72, GUIFWHY ,2, "TCS guider average y FWHM in pixels"             )
+MK_INT(  530.8, SKYFLUX ,   "TCS total sky flux"                              )
+
+MK_STR(  531.1,	GUINAME1,   "TCS guider #1 identification"                    )
+MK_VAL( 531.21,	GUIEQUI1,   "TCS guider #1 equinox"                           )
+MK_STR( 531.22,	GUIRADE1,   "TCS guider #1 system for equinox"                )
+MK_STR( 531.23,	GUIRA1  ,   "TCS guider #1 right ascension"                   )
+MK_STR( 531.24,	GUIDEC1 ,   "TCS guider #1 declination"                       )
+MK_PFL( 531.25, GUIRAPM1,2, "TCS guider #1 right ascen proper motion arcsec"  )
+MK_PFL( 531.26, GUIDEPM1,2, "TCS guider #1 declination proper motion arcsec"  )
+MK_STR(  531.3, GUIOBJN1,   "TCS guider #1 object name"                       )
+MK_PFL(	 531.4,	GUIMAGN1,1, "TCS guider #1 object magnitude"                  )
+MK_PFL( 531.51, GUIPOSX1,3, "TCS guider #1 probe x position"                  )
+MK_PFL( 531.52, GUIPOSY1,3, "TCS guider #1 probe y position"                  )
+MK_PFL( 531.53, GUIPOSZ1,3, "TCS guider #1 probe z position"                  )
+MK_INT(  531.6, GUIFLUX1,   "TCS guider #1 flux"                              )
+MK_PFL( 531.71, GUIFWHX1,2, "TCS guider #1 average x FWHM in pixels"          )
+MK_PFL( 531.72, GUIFWHY1,2, "TCS guider #1 average y FWHM in pixels"          )
+
+MK_STR(  532.1,	GUINAME2,   "TCS guider #2 identification"                    )
+MK_VAL( 532.21,	GUIEQUI2,   "TCS guider #2 equinox"                           )
+MK_STR( 532.22,	GUIRADE2,   "TCS guider #2 system for equinox"                )
+MK_STR( 532.23,	GUIRA2  ,   "TCS guider #2 right ascension"                   )
+MK_STR( 532.24,	GUIDEC2 ,   "TCS guider #2 declination"                       )
+MK_PFL( 532.25, GUIRAPM2,2, "TCS guider #2 right ascen proper motion arcsec"  )
+MK_PFL( 532.26, GUIDEPM2,2, "TCS guider #2 declination proper motion arcsec"  )
+MK_STR(  532.3, GUIOBJN2,   "TCS guider #2 object name"                       )
+MK_PFL(	 532.4,	GUIMAGN2,1, "TCS guider #2 object magnitude"                  )
+MK_PFL( 532.51, GUIPOSX2,3, "TCS guider #2 probe x position"                  )
+MK_PFL( 532.52, GUIPOSY2,3, "TCS guider #2 probe y position"                  )
+MK_PFL( 532.53, GUIPOSZ2,3, "TCS guider #2 probe z position"                  )
+MK_INT(  532.6, GUIFLUX2,   "TCS guider #2 flux"                              )
+MK_PFL( 532.71, GUIFWHX2,2, "TCS guider #2 average x FWHM in pixels"          )
+MK_PFL( 532.72, GUIFWHY2,2, "TCS guider #2 average y FWHM in pixels"          )
+
+MK_STR(  533.1,	GUINAME3,   "TCS guider #3 identification"                    )
+MK_VAL( 533.21,	GUIEQUI3,   "TCS guider #3 equinox"                           )
+MK_STR( 533.22,	GUIRADE3,   "TCS guider #3 system for equinox"                )
+MK_STR( 533.23,	GUIRA3  ,   "TCS guider #3 right ascension"                   )
+MK_STR( 533.24,	GUIDEC3 ,   "TCS guider #3 declination"                       )
+MK_PFL( 533.25, GUIRAPM3,2, "TCS guider #3 right ascen proper motion arcsec"  )
+MK_PFL( 533.26, GUIDEPM3,2, "TCS guider #3 declination proper motion arcsec"  )
+MK_STR(  533.3, GUIOBJN3,   "TCS guider #3 object name"                       )
+MK_PFL(	 533.4,	GUIMAGN3,1, "TCS guider #3 object magnitude"                  )
+MK_PFL( 533.51, GUIPOSX3,3, "TCS guider #3 probe x position"                  )
+MK_PFL( 533.52, GUIPOSY3,3, "TCS guider #3 probe y position"                  )
+MK_PFL( 533.53, GUIPOSZ3,3, "TCS guider #3 probe z position"                  )
+MK_INT(  533.6, GUIFLUX3,   "TCS guider #3 flux"                              )
+MK_PFL( 533.71, GUIFWHX3,2, "TCS guider #3 average x FWHM in pixels"          )
+MK_PFL( 533.72, GUIFWHY3,2, "TCS guider #3 average y FWHM in pixels"          )
+
+MK_STR(  534.1,	GUINAME4,   "TCS guider #4 identification"                    )
+MK_VAL( 534.21,	GUIEQUI4,   "TCS guider #4 equinox"                           )
+MK_STR( 534.22,	GUIRADE4,   "TCS guider #4 system for equinox"                )
+MK_STR( 534.23,	GUIRA4  ,   "TCS guider #4 right ascension"                   )
+MK_STR( 534.24,	GUIDEC4 ,   "TCS guider #4 declination"                       )
+MK_PFL( 534.25, GUIRAPM4,2, "TCS guider #4 right ascen proper motion arcsec"  )
+MK_PFL( 534.26, GUIDEPM4,2, "TCS guider #4 declination proper motion arcsec"  )
+MK_STR(  534.3, GUIOBJN4,   "TCS guider #4 object name"                       )
+MK_PFL(	 534.4,	GUIMAGN4,1, "TCS guider #4 object magnitude"                  )
+MK_PFL( 534.51, GUIPOSX4,3, "TCS guider #4 probe x position"                  )
+MK_PFL( 534.52, GUIPOSY4,3, "TCS guider #4 probe y position"                  )
+MK_PFL( 534.53, GUIPOSZ4,3, "TCS guider #4 probe z position"                  )
+MK_INT(  534.6, GUIFLUX4,   "TCS guider #4 flux"                              )
+MK_PFL( 534.71, GUIFWHX4,2, "TCS guider #4 average x FWHM in pixels"          )
+MK_PFL( 534.72, GUIFWHY4,2, "TCS guider #4 average y FWHM in pixels"          )
+
+MK_PFL(  540.1,	AIRMASS ,3, "Airmass at start of observation"                 )
+MK_PFL(  540.2, TELALT  ,2, "Telescope altitude at start of observation, deg" )
+MK_PFL(  540.3, TELAZ   ,2, "Telescope azimuth at start, deg, 0=N 90=E 270=W" )
+MK_PFL(  540.4, MOONANGL,2, "Angle from object to moon at start in degrees"   )
+MK_STR(  550.0,	FOCUSID ,   "Telescope focus in use"                          )
+MK_STR(  550.1, TELCONF ,   "Telescope focus in use"                          )
+MK_INT(  551.0,	FOCUSPOS,   "Telescope focus encoder readout"                 )
+MK_INT(  551.1,	TELFOCUS,   "Telescope focus encoder readout"                 )
+MK_PFL(  552.0,	BONANGLE,2, "Telescope bonnette rotation angle in degrees"    )
+MK_PFL(  552.1,	ROTANGLE,2, "Telescope bonnette rotation angle in degrees"    )
+
+/*
+ * The following values perhaps should have their own section, but they
+ * are also (with some stretch) a part of TCS so for now they are here.
+ * They should only be included in MegaPrime and WIRCam images.
+ */
+
+MK_PFL(  560.1, ISUGAIN ,2, "Instrument Stabilization Unit control gain"      )
+MK_PFL(  560.2, ISURATE ,2, "ISU control rate in Hz"                          )
+MK_PFL(  560.3, ISUTCSOR,2, "ISU offload rate in Hz to telescope position"    )
+MK_STR(  560.4, ISUSTATE,   "ISU control state (Off/Only/TCS/Full/Frozen)"    )
+MK_PFL(  560.5, ISUSTDVX,2, "ISU most recent minute std dev in x in arcsec"   )
+MK_PFL(  560.6, ISUSTDVY,2, "ISU most recent minute std dev in y in arcsec"   )
+
+/*
+ * The following values perhaps should have their own section, but they
+ * are also (with some stretch) a part of TCS so for now they are here.
+ * They should only be included in MegaPrime images.
+ */
+
+MK_PFL(  570.1, FSAGAIN ,2, "Focus Stage Assembly movement control gain"      )
+MK_PFL(  570.2, FSARATE ,2, "FSA control rate in Hz"                          )
+MK_PFL(  570.3, FSATHRES,3, "FSA movement threshold in mm"                    )
+MK_STR(  570.4, FSASTATE,   "FSA control state (Off/On/Paused)"               )
+MK_INT(  570.5, FSANMOVE,   "FSA number of actual moves in last 10 minutes"   )
+MK_PFL( 570.61, FSAMINZ ,3, "FSA minimum position in last 10 minutes"         )
+MK_PFL( 570.62, FSAMAXZ ,3, "FSA maximum position in last 10 minutes"         )
+MK_PFL( 570.63, FSAMEANZ,3, "FSA mean position in last 10 minutes"            )
+MK_PFL( 570.64, FSASTDVZ,3, "FSA position std dev in last 10 minutes"         )
+
+/*
+ * The following values are used to collect data for TCS pointing model
+ * tuning.  Some of the values duplicate numbers elsewhere in the headers,
+ * but where it matters these are all read at the same time in the IOC.
+ */
+
+MK_STR( 580.11, TCSGPSBC,   "TCS GPS read out in BCD"                         )
+MK_PFL( 580.12, TCSGPSTM,5, "TCS GPS clock time in decimal hours"             )
+MK_STR( 580.13, TCSRBUSS,   "TCS RBUSS clock time"                            )
+MK_STR( 580.14, TCSEPICS,   "TCS EPICS clock time"                            )
+MK_STR( 580.15, TCSAMODE,   "TCS acquisition mode - T/O/G/g for t/o/g coords" )
+MK_PFL( 580.21, TCSMJD  ,7, "TCS MJD"                                         )
+MK_PFL( 580.22, TCSLST  ,5, "TCS LST in decimal hours"                        )
+MK_PFL( 580.31, TCSAPHA ,4, "TCS apparent hour angle in degrees"              )
+MK_PFL( 580.32, TCSAPDEC,4, "TCS apparent declination in degrees"             )
+MK_PFL( 580.41, TCSOBHA ,4, "TCS observed hour angle in degrees"              )
+MK_PFL( 580.42, TCSOBDEC,4, "TCS observed declination in degrees"             )
+MK_INT( 580.51, TCSENHA ,   "TCS hour angle encoder bits reading"             )
+MK_INT( 580.52, TCSENDEC,   "TCS declination encoder bits reading"            )
+MK_PFL( 580.61, TCSEDHA ,4, "TCS hour angle encoder in degrees"               )
+MK_PFL( 580.62, TCSEDDEC,4, "TCS declination encoder in degrees"              )
+MK_PFL( 580.71, TCSMVRA ,4, "TCS right ascension acquisition move in arcsec"  )
+MK_PFL( 580.72, TCSMVDEC,4, "TCS declination acquisition move in arcsec"      )
+MK_PFL( 580.81, TCSMVX  ,3, "TCS secondary guider acquisition x move in mm"   )
+MK_PFL( 580.82, TCSMVY  ,3, "TCS secondary guider acquisition y move in mm"   )
+
+/*
+ * Adaptive Optics : 700.000 to 799.999
+ *
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT(  700.1, CMTAOB1 ,   ""                                                )
+MK_CMT(  700.2, CMTAOB2 ,   "Adaptive Optics Bonnette"                        )
+MK_CMT(  700.3, CMTAOB3 ,   "------------------------"                        )
+MK_CMT(  700.4, CMTAOB4 ,   ""                                                )
+
+/* 710 through 719 are input control values to the real time system */
+
+/*
+ * state of AO correction (terms come from original description of loop
+ * operation which was deemed not PC and changed to "correction")
+ */
+MK_STR(  711.0, AOBLOOP ,   "AOB closed loop Open/Closed"                     )
+/*
+ * primary gain in the integrator providing signals to the bimorph
+ */
+MK_PFL(  712.0, LOOPGAIN,1, "Gain of the integrator"                          )
+/*
+ * correction can be fully automatic (all modes, bimorph offloading to
+ * tip/tilt mirror - nested), manual (manually selected modes, tip/tilt
+ * mode if selected only feeds tip/tilt mirror, i.e., not via bimorph
+ * - single), or tip/tilt only (bimorph not used at all, kept flat)
+ */
+MK_STR(  713.0, LOOPNES ,   "Loop type \"Nested\"/\"Tip/Tilt\"/\"Single\""    )
+/*
+ * in automatic correction this is the gain between the bimorph and the
+ * tip/tilt mirror
+ */
+MK_PFL(  714.0, LOOPNESG,1, "Nested loop gain"                                )
+/*
+ * the individual mode gains can be fixed or optimized based on signal
+ * levels
+ */
+MK_STR(  715.0, LOOPOPT ,   "Optimized loop control True/False"               )
+/*
+ * stroke of the membrane mirror (1-256)
+ */
+MK_INT(  716.0, WFSGOPT ,   "WFS optical gain"                                )
+/*
+ * integration time for each calculation cycle
+ */
+MK_PFL(  717.0, WFSSAMP ,3, "WFS sampling period (sec)"                       )
+
+/* 720-729 are measured values calculated by the real time system */
+
+/*
+ * calculated value of R0
+ */
+MK_PFL(  721.0, R0      ,1, "Fried parameter (cm)"                            )
+/*
+ * sum of the photon counts on the 19 APD's, for the most recent integration
+ */
+MK_INT(  722.0, WFSCOUNT,   "Total flux count on WFS"                         )
+
+/* 750-769 are input control values to the bench control ProLog(tm) */
+
+/*
+ * whether the atmospheric dispersion corrector (ADC) is in or out of the
+ * optical path
+ */
+MK_STR(  751.0, ADCPOS  ,   "AOB ADC position In/Out"                         )
+/*
+ * angle of the dispersion caused by the ADC
+ */
+MK_PFL(  752.0, ADCANGLE,2, "AOB ADC angle (degrees)"                         )
+/*
+ * amount of dispersion caused by the relative angle between the ADC prisms
+ */
+MK_PFL(  753.0, ADCPOWER,4, "AOB ADC power"                                   )
+/*
+ * beam splitter id code read from slugs on the splitters
+ */
+MK_INT(  754.0, BEAMSPID,   "Beam splitter ID"                                )
+/*
+ * beam splitter description based on the above codes
+ */
+MK_STR(  755.0, BEAMSP  ,   "Beam splitter description"                       )
+/*
+ * whether the AOB central mirror is in (AO system in light path)
+ * or out (AO system not being used)
+ */
+MK_STR(  756.0, MIRSLIDE,   "AOB mirror slide \"F/20\"/\"F/8\""               )
+/*
+ * neutral density filter position (in optical path to WFS)
+ *   0 == home
+ *   1 == no filter (close but not quite the same physical position as home)
+ *   2 == 1.0 density filter
+ *   3 == 2.0    "      "
+ *   4 == 3.0    "      "
+ */
+MK_INT(  757.0, WFSNDID ,   "WFS ND filter position"                          )
+/*
+ * following 3 are the Wave Front Sensor (WFS) position in a coordinate
+ * system close to having z parallel to the optical path
+ */
+MK_PFL(  761.0, WFSX    ,1, "Translated WFS X coord (steps)"                  )
+MK_PFL(  762.0, WFSY    ,1, "Translated WFS Y coord (steps)"                  )
+MK_PFL(  763.0, WFSZ    ,1, "Translated WFS Z coord (steps)"                  )
+/*
+ * Calibration Sources : 900.000 to 999.999
+ *
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT(  900.1, CMTCAL1 ,   ""                                                )
+MK_CMT(  900.2, CMTCAL2 ,   "Calibration sources"                             )
+MK_CMT(  900.3, CMTCAL3 ,   "-------------------"                             )
+MK_CMT(  900.4, CMTCAL4 ,   ""                                                )
+
+/* 910 - 919 are flat field lamps */
+
+/*
+ * Gecko lamps are computer controlled, these give On/Off status and
+ * intensity
+ */
+MK_STR(  910.0, FFLAMPON,   "flatfield lamp status ON/OFF"                    )
+MK_INT(  911.0, FFLAMP  ,   "flatfield lamp intensity"                        )
+/* add which lamp if get control of dome flat fields */
+
+/* 920-999 are calibration lamp sources */
+
+/*
+ * Gecko has 4 lamps, these give On/Off status and descriptions
+ */
+MK_STR(  920.0, CLAMP0ON,   "comparison lamp 0 status ON/OFF"                 )
+MK_STR(  920.1, CLAMP0  ,   "comparison lamp 0 description"                   )
+MK_STR(  921.0, CLAMP1ON,   "comparison lamp 1 status ON/OFF"                 )
+MK_STR(  921.1, CLAMP1  ,   "comparison lamp 1 description"                   )
+MK_STR(  922.0, CLAMP2ON,   "comparison lamp 2 status ON/OFF"                 )
+MK_STR(  922.1, CLAMP2  ,   "comparison lamp 2 description"                   )
+MK_STR(  923.0, CLAMP3ON,   "comparison lamp 3 status ON/OFF"                 )
+MK_STR(  923.1, CLAMP3  ,   "comparison lamp 3 description"                   )
+
+/*
+ * GumBall has 10 lamps, though the last two are Fabre-Perot lamps sharing
+ * the same light path and cannot be on together, these give On/Off status
+ * for each
+ */
+MK_STR(  930.0, CALIBL0 ,   "lamp 0 ON/OFF"                                   )
+MK_STR(  931.0, CALIBL1 ,   "lamp 1 ON/OFF"                                   )
+MK_STR(  932.0, CALIBL2 ,   "lamp 2 ON/OFF"                                   )
+MK_STR(  933.0, CALIBL3 ,   "lamp 3 ON/OFF"                                   )
+MK_STR(  934.0, CALIBL4 ,   "lamp 4 ON/OFF"                                   )
+MK_STR(  935.0, CALIBL5 ,   "lamp 5 ON/OFF"                                   )
+MK_STR(  936.0, CALIBL6 ,   "lamp 6 ON/OFF"                                   )
+MK_STR(  937.0, CALIBL7 ,   "lamp 7 ON/OFF"                                   )
+MK_STR(  938.0, CALIBL8 ,   "lamp 8 ON/OFF"                                   )
+MK_STR(  939.0, CALIBL9 ,   "lamp 9 ON/OFF"                                   )
+
+/*
+ * Instrument : 1000.000 to 1999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT( 1000.1, CMTINST1,   ""                                                )
+MK_CMT( 1000.2, CMTINST2,   "Instrument Description"                          )
+MK_CMT( 1000.3, CMTINST3,   "----------------------"                          )
+MK_CMT( 1000.4, CMTINST4,   ""                                                )
+
+/*
+ * There are lots of shared keywords among the instruments and spectrographs.
+ * Where the keywords are really general purpose (e.g., FILTER) they are
+ * separated from the instrument areas.  Where the keywords are more specific,
+ * they are associated with the "first" (arbitrarily defined as starting about
+ * 1992 :-) instrument that used them.
+ */
+
+/* 1010 through 1099 are filter wheel info */
+
+/*
+ * Somewhere in the optical train there be filters.  If there is one filter
+ * use the FILTER sequence, whether it is actually in the detector or the
+ * instrument.  If there are two filters (usual case for IR), use the WHEEL
+ * sequence.  For an IR camera on an instrument with a filter, use both.
+ */
+
+/*
+ * code descriptions for all wheel identifiers
+ *
+ *  ID - numeric position number of wheel
+ *  <null> or DE - text description of filter mounted in that position
+ *  LB - lower bound of filter transmission - units Angstrom or microns?
+ *  UB - upper bound of filter transmission - units Angstrom or microns?
+ *  BW - bandwidth of filter transmission - units Angstrom or microns?
+ *  WL - center wave length of filter transmission - units Angstrom or microns?
+ */
+
+/* single filter wheel */
+MK_INT( 1010.1, FILTERID,   "wheel position"                                  )
+MK_STR( 1010.2, FILTER  ,   "description of filter"                           )
+MK_FLT( 1010.3, FILTERBW,3, "filter bandwidth"                                )
+MK_FLT( 1010.4, FILTERWL,3, "filter wavelength"                               )
+MK_FLT( 1010.5, FILTERLB,5, "lower bound of filter (units/%?)"                )
+MK_FLT( 1010.6, FILTERUB,5, "upper bound of filter (units/%?)"                )
+/* MOS/SIS have coded filter wheels, this is the code for the installed one */
+MK_INT( 1010.7, FILTSLID,   "filter drawer number"                            )
+
+/* first filter wheel of two */
+MK_INT( 1020.1, WHEELAID,   "'wheel' A position"                              )
+MK_STR( 1020.2, WHEELADE,   "description of filter"                           )
+MK_FLT( 1020.5, WHEELALB,4, "lower bound of filter A (units/%?)"              )
+MK_FLT( 1020.6, WHEELAUB,4, "upper bound of filter A (units/%?)"              )
+/* second filter wheel of two */
+MK_INT( 1030.1, WHEELBID,   "'wheel' B position"                              )
+MK_STR( 1030.2, WHEELBDE,   "description of filter"                           )
+MK_FLT( 1030.5, WHEELBLB,4, "lower bound of filter B (units/%?)"              )
+MK_FLT( 1030.6, WHEELBUB,4, "upper bound of filter B (units/%?)"              )
+
+/* 1100 through 1199 are general instrument set up values */
+
+/*
+ * For instruments that have an internal focus adjustment, this records
+ * the current position
+ */
+MK_FLT( 1101.0, INSTFOC ,7, "internal instrument focus value"                 )
+
+
+/*
+ * Spectrograph : 4000.000 to 4999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT( 4000.1, CMTSPEC1,   ""                                                )
+MK_CMT( 4000.2, CMTSPEC2,   "Spectrograph Description"                        )
+MK_CMT( 4000.3, CMTSPEC3,   "------------------------"                        )
+MK_CMT( 4000.4, CMTSPEC4,   ""                                                )
+
+/* 4100 through 4199 are MOS/SIS */
+
+/*
+ * There are a grism wheel and a mask slide on each side.  By analogy with
+ * the filter wheel names:
+ *  ID     - numeric position number of wheel or slide
+ *  <null> - text description of filter mounted in that position
+ *  SLID   - the grism wheels and mask slides have codes, this is the
+ *           number of the installed wheel or slide
+ */
+MK_INT( 4101.0, GRISMID ,   "grism position"                                  )
+MK_STR( 4102.0, GRISM   ,   "grism description"                               )
+MK_INT( 4103.0, GRISSLID,   "grism drawer number"                             )
+MK_INT( 4111.0, MASKID  ,   "mask position"                                   )
+MK_STR( 4112.0, MASK    ,   "mask description"                                )
+MK_INT( 4113.0, MASKSLID,   "mask slider number"                              )
+
+/* 4200 through 4299 are GECKO */
+
+/*
+ * Description of the grating installed
+ */
+MK_STR( 4201.0, DISPEL  ,   "grating description"                             )
+/*
+ * Dispersion axis used, always 2 now
+ */
+MK_INT( 4202.0, DISPAXIS,   "dispersion axis (1 or 2)"                        )
+/*
+ * Incidence angle
+ */
+MK_FLT( 4203.0, DISPANG ,6, "grating angle in degrees"                        )
+/*
+ * Resulting center wavelength
+ */
+MK_FLT( 4204.0, WAVELENG,10,"central wavelength in angstroms"                 )
+/*
+ * In this order
+ */
+MK_INT( 4205.0, ORDER   ,   "spectral order"                                  )
+/*
+ * Magic number
+ */
+MK_FLT( 4206.0, GRSETUP ,5, "grating setup constant in degrees"               )
+/*
+ * Another magic number
+ */
+MK_FLT( 4207.0, OPENANG2,7, "setup const in degrees (opening angle / 2)"      )
+/*
+ * Why "grism angle" if it's the angle between 2 prisms ???
+ */
+MK_FLT( 4208.0, GRISMANG,5, "rel.angle between prisms in degrees"             )
+
+/*
+ * unimplemented description of slicer used
+ */
+MK_STR( 4210.0, SLICER  ,   "image slicer in place"                           )
+
+/*
+ * OPEN or CLOSED for each hartman mask
+ */
+MK_STR( 4221.0, HART1A  ,   "hartman mask 1a position OPEN/CLOSED"            )
+MK_STR( 4221.1, HART1B  ,   "hartman mask 1b position OPEN/CLOSED"            )
+MK_STR( 4222.0, HART2   ,   "hartman mask 2 position OPEN/CLOSED"             )
+MK_STR( 4223.0, HART3   ,   "hartman mask 3 position OPEN/CLOSED"             )
+MK_STR( 4224.0, HART4   ,   "hartman mask 4 position OPEN/CLOSED"             )
+
+/*
+ * unimplemented description of train used
+ * could be UV/RED/CAFE
+ */
+MK_STR( 4230.0, COUDETRN,   "coude train color UV/RED/CAFE"                   )
+
+/*
+ * unimplemented exposure meter info
+ */
+MK_STR( 4240.0, EMFILTER,   "exposure meter filter description"               )
+MK_INT( 4241.0, EMCNTS  ,   "exposure meter counts at end"                    )
+MK_INT( 4242.0, MIDEXPTM,   "mid-exposure time (seconds)"                     )
+
+/*
+ * CAFE mode added an additional card indicating that the Coude train was
+ * not being used - this ought to be added to Gecko files with NOTUSED
+ * as the value
+ */
+MK_STR( 4290.0, CAFE    ,   "CAFE is being used Null/INUSE"                   )
+
+
+/* 4300 through 4399 are for Fabre-Perot etalons */
+
+/*
+ * Description of the etalon in use
+ */
+MK_STR( 4301.0, AUXINST ,   "fabry perot etalon description"                  )
+/*
+ * Number used to figure something
+ */
+MK_PFL( 4302.0, CONST   ,2, "fabry perot constant"                            )
+/*
+ * Number of scan positions
+ */
+MK_INT( 4303.0, NUMCHAN ,   "number of channels per scan"                     )
+/*
+ * Current scan position
+ */
+MK_INT( 4304.0, CURCHAN ,   "current channel"                                 )
+/*
+ * Actual control value sent to etalon for this position
+ */
+MK_INT( 4305.0, BINVAL  ,   "binary control value"                            )
+
+/*
+ * GriF needed a bunch more values so some of these are duplicates :-(
+ */
+/*
+ * GriF adds a Fabre-Perot etalon between AOB and KIR.  This value indicates
+ * the position of the slide holding the etalon.
+ */
+MK_STR( 4320.0, GRFPPOS ,   "GriF position of FP carriage - In/Out"           )
+/*
+ * Etalon calibration values, order and standard wavelength, and BCV at
+ * standard wavelength
+ */
+MK_FLT( 4321.1, GRWAVORD,6, "GriF wavelength of order used to scan"           )
+MK_FLT( 4321.2, GRWAVCAL,6, "GriF wavelength of calibration spectral line"    )
+MK_FLT( 4321.3, GRBCVCAL,6, "GriF BCV at calibration line"                    )
+/*
+ * This records what the driver for the scan is
+ *   bcv      - specific BCV positions given
+ *   wave     - a wavelength range given and BCV's calculated
+ *   velocity - a range of delta velocities given and BCV's calculated
+ */
+MK_STR( 4322.0, GRSCANTY,   "GriF type of scan - bcv, wave, velocity"         )
+/*
+ * Wavelength values for scan, beginning, delta, and current
+ */
+MK_FLT( 4323.1, GRWAVBEG,6, "GriF wavelength at beginning of scan"            )
+MK_FLT( 4323.2, GRWAVSTP,6, "GriF wavelength step"                            )
+MK_FLT( 4323.3, GRWAVCUR,6, "GriF current observed wavelength"                )
+/*
+ * BCV equivalents (well, these are calculated from the desired wavelengths
+ * initially, but since the etalon is integral, the current wavelength value
+ * above is a conversion back from the BCV position)
+ */
+MK_FLT( 4324.1, GRBCVBEG,6, "GriF Binary Contol Value at beginning of scan"   )
+MK_FLT( 4324.2, GRBCVSTP,6, "GriF BCV step"                                   )
+MK_INT( 4324.3, GRBCVCUR,   "GriF applied BCV"                                )
+/*
+ * The scan itself is a sequence of etalon positions rounded from the
+ * desired wavelength range and step.  These are the count and current
+ * position in the scan.  (How is GRCURRCH different from GRBCVCUR ??? )
+ */
+MK_INT( 4325.1, GRNBCHAN,   "GriF number of channels in scan"                 )
+MK_INT( 4325.2, GRCURRCH,   "GriF current channel"                            )
+/*
+ * GriF also controls the plate parallelism.  These record the x and y
+ * commands
+ */
+MK_INT( 4326.1, GRBCV_X ,   "GriF X Binary Control Value FP"                  )
+MK_INT( 4326.2, GRBCV_Y ,   "GriF Y Binary Control Value FP"                  )
+
+/*
+ * Environment : 9000.000 to 9999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+/*
+ * Data logger probe readings.  NOTE: The first two columns of the comment
+ * for these make up the authoritative probe numbers.  "loggerh" MUST BE
+ * RECOMPILED to have these changes take effect.  It takes whatever is
+ * currently in the first two columns of the COMMENT and adds /p/logger/.
+ */
+MK_PFL( 9101.0, TESPMIRE,2, "03 temp, surface, primary mirror east deg C"     )
+MK_PFL( 9102.0, TESPMIRW,2, "02 temp, surface, primary mirror west deg C"     )
+MK_PFL( 9103.0, TESPMIRS,2, "01 temp, surface, primary mirror west side degC" )
+MK_PFL( 9104.0, TEAPMCLW,2, "54 temp, air, primary mirror cell west deg C"    )
+MK_PFL( 9105.0, TEAMIRCI,2, "58 temp, air, mirror cooling in at unit deg C"   )
+MK_PFL( 9106.0, TEAMIRCO,2, "27 temp, air, mirror cooling out at cell deg C"  )
+MK_PFL( 9107.0, TEAPMSPN,2, "65 temp, air, mirror spigot north cass deg C"    )
+MK_PFL( 9108.0, TEAPMSPS,2, "64 temp, air, mirror spigot nouth M3 deg C"      )
+MK_PFL( 9109.0, TEATRNGE,2, "23 temp, air, top ring east deg C"               )
+MK_PFL( 9110.0, TEATRNGW,2, "06 temp, air, top ring west deg C"               )
+MK_PFL( 9111.0, TEANRLSB,2, "19 temp, air, north rail support beam deg C"     )
+MK_PFL( 9112.0, TESHRSET,2, "08 temp, surface, horseshoe east top deg C"      )
+MK_PFL( 9113.0, TESTELTL,2, "49 temp, surface, telescope truss low deg C"     )
+MK_PFL( 9114.0, TESTELTH,2, "52 temp, surface, telescope truss high deg C"    )
+MK_PFL( 9115.0, TEALOWWS,2, "38 temp, air, dome lower weather stat side degC" )
+MK_PFL( 9116.0, TEATOPWS,2, "36 temp, air, dome top weather stat side deg C"  )
+MK_PFL( 9117.0, TEATOPOP,2, "37 temp, air, dome top opposite weath side degC" )
+MK_PFL( 9118.0, TEA2INCH,2, "45 temp, air, two inches above fifth floor degC" )
+MK_PFL( 9119.0, TEA2INEB,2, "53 temp, air, two inches up by electronics degC" )
+MK_PFL( 9120.0, TEA6FOOT,2, "43 temp, air, six feet above fifth floor deg C"  )
+MK_PFL( 9121.0, TESCONRM,2, "61 temp, surface, floor above control room degC" )
+MK_PFL( 9122.0, TESPIERN,2, "59 temp, surface, floor by north pier deg C"     )
+MK_PFL( 9123.0, TESPIERS,2, "60 temp, surface, floor by south pier deg C"     )
+MK_PFL( 9124.0, TEAWTHRT,2, "35 temp, air, weathertron deg C"                 )
+MK_PFL( 9125.0, TEMPERAT,2, "86 temp, air, weather tower deg C"               )
+MK_PFL( 9126.0, WINDSPED,2, "84 wind speed, weather tower knots"              )
+MK_PFL( 9127.0, WINDDIR ,2, "85 wind direction, weather tower deg (N=0 E=90)" )
+MK_PFL( 9128.0, RELHUMID,2, "87 relative humidity, weather tower %"           )
+MK_PFL( 9129.0, PRESSURE,2, "31 barometric pressure, control room mb"         )
+
+/*
+ * Queue Scheduled Observing : 11000.000 to 11999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+/*
+ * Processing Pipeline : 15000.000 to 15999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+MK_CMT(15000.1, CMTPROC1,   ""                                                )
+MK_CMT(15000.2, CMTPROC2,   "Processing Pipeline"                             )
+MK_CMT(15000.3, CMTPROC3,   "-------------------"                             )
+MK_CMT(15000.4, CMTPROC4,   ""                                                )
+MK_STR(15101.0, CRUNID,     "Elixir camera run ID"                            )
+/*
+ * Archive System : 90000.000 to 99999.999
+ *
+ *TYPE --IDX--  KEYWORD- PRC -------------------COMMENT----------------------*/
+
+#endif /* !_INCLUDED_fh_registry */
Index: /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/macros.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/macros.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/fits/libfhreg/macros.h	(revision 23490)
@@ -0,0 +1,145 @@
+/*                                             -*- c-file-style: "Ellemtel" -*-
+
+`macros.h' - CPP macros to make fhreg work, automatically included
+
+This file is part of version 0 of the FITS Keyword Registry.
+Read the `License' file for terms of use and distribution.
+Copyright 2004, Pan-STARRS, isani@ifa.hawaii.edu.
+
+___This header automatically generated from `Index'. Do not edit it here!___ */
+
+/*
+ * Documentation: See http://software.cfht.hawaii.edu/fh_registry/
+ *
+ * === NOTE: That only describes the CFHT version of the registry!
+ */
+
+#ifndef _INCLUDED_fhreg_macros
+#define _INCLUDED_fhreg_macros 1
+
+/*
+ * This macro is used inside the other macros (ID_FLT, ID_INT, etc.)
+ * so that the keyword names can be referred to as fh_kw_FOO
+ * This can be used as an identifier to fh_get() or any other function
+ * instead of using the string constant "FOO".
+ */
+
+#define ID_FLT(idx, name, keyword, prec, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, double value) \
+{ fh_set_flt(hu, idx, keyword, value, prec, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, double value, const char* new_comment) \
+{ fh_set_flt(hu, idx, keyword, value, prec, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, double* value) \
+{ return fh_get_flt(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_PFL(idx, name, keyword, prec, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, double value) \
+{ fh_set_pfl(hu, idx, keyword, value, prec, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, double value, const char* new_comment) \
+{ fh_set_pfl(hu, idx, keyword, value, prec, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, double* value) \
+{ return fh_get_flt(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_INT(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, int value) \
+{ fh_set_int(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, int value, const char* new_comment) \
+{ fh_set_int(hu, idx, keyword, value, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, int* value) \
+{ return fh_get_int(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_BLN(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, fh_bool value) \
+{ fh_set_bool(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, fh_bool value, const char* new_comment) \
+{ fh_set_bool(hu, idx, keyword, value, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, fh_bool* value) \
+{ return fh_get_bool(hu, keyword, value); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_STR(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, const char* value) \
+{ fh_set_str(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setval_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, const char* value, const char* new_comment) \
+{ fh_set_str(hu, idx, keyword, value, new_comment); } \
+static inline fh_result \
+fh_get_##name (HeaderUnit hu, char* value, int maxlen) \
+{ return fh_get_str(hu, keyword, value, maxlen); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_VAL(idx, name, keyword, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu, const char* value) \
+{ fh_set_val(hu, idx, keyword, value, comment); } \
+static inline void \
+fh_setcmt_##name (HeaderUnit hu, const char* value, const char* new_comment) \
+{ fh_set_val(hu, idx, keyword, value, new_comment); } \
+static inline const char* \
+fh_kw_##name(void) { return keyword; } \
+static inline const char* \
+fh_cmt_##name(void) { return comment; }
+
+#define ID_CMT(idx, name, comment) \
+static inline void \
+fh_set_##name (HeaderUnit hu) \
+{ fh_set_com(hu, idx, "COMMENT", comment); }
+
+/*
+ * Now the auto-stringified versions of ID_*() ...
+ */
+#define MK_FLT(idx, name, dig, comment) ID_FLT(idx, name, #name, dig, comment)
+#define MK_PFL(idx, name, dec, comment) ID_PFL(idx, name, #name, dec, comment)
+#define MK_INT(idx, name, comment) ID_INT(idx, name, #name, comment)
+#define MK_STR(idx, name, comment) ID_STR(idx, name, #name, comment)
+#define MK_VAL(idx, name, comment) ID_VAL(idx, name, #name, comment)
+#define MK_BLN(idx, name, comment) ID_BLN(idx, name, #name, comment)
+#define MK_CMT(idx, name, comment) ID_CMT(idx, name, comment)
+
+#endif /* !_INCLUDED_fhreg_macros */
Index: /trunk/extsrc/gpcsw/gpcsrc/missing_protos.h
===================================================================
--- /trunk/extsrc/gpcsw/gpcsrc/missing_protos.h	(revision 23490)
+++ /trunk/extsrc/gpcsw/gpcsrc/missing_protos.h	(revision 23490)
@@ -0,0 +1,327 @@
+/* Copyright (C) 1997-2002  Canada-France-Hawaii Telescope Corp.         */
+/* This program is distributed WITHOUT any warranty, and is under the    */
+/* terms of the GNU General Public License, see the file COPYING         */
+/*****************************************************************************
+ *
+ * missing_protos.h - ANSI prototypes for systems that lack complete ANSI
+ *                    system header files (especially SunOS 4.x).  This file
+ *                    should be included with `#include <missing_protos.h>'
+ *                    from "cfht/cfht.h" so that it does not show up in
+ *                    the dependencies generated by "gcc -MM".  Proper ANSI
+ *                    systems should not need anything from this file anyway,
+ *                    and thus will not be tempted to re-compile everything
+ *                    which depends on this file every time we need to add
+ *                    a new prototype for the SunOS machines.
+ * $Id: missing_protos.h,v 1.15 2002/08/26 22:22:32 thomas Exp $
+ * $Locker:  $
+ *
+ * $Log: missing_protos.h,v $
+ * Revision 1.15  2002/08/26 22:22:32  thomas
+ * Added VxWorks to "Make.Common is not being used" #if collection
+ *
+ * Revision 1.14  2001/12/05 00:56:22  thomas
+ * Added mknod(2) for SunOS
+ *
+ * Revision 1.13  2001/12/05 00:13:28  thomas
+ * Added sys/file.h and flock for SunOS
+ *
+ * Revision 1.12  2001/10/14 20:28:32  isani
+ * optarg stuff for SUNOS.
+ * Missing socklen_t on HP 10.20.
+ *
+ * Revision 1.11  2000/02/10 13:52:23  isani
+ * Added a few more prototypes.
+ * Changed to new way of doing SELECT() call.
+ *
+ * Revision 1.10  1999/07/30 22:14:51  thomas
+ * HP added openlog/syslog in 10.X, if it out there
+ *
+ * Revision 1.9  1999/07/13 21:27:28  thomas
+ * Added WCOREDUMP for SunOS
+ *
+ * Revision 1.8  1999/07/13 00:17:24  thomas
+ * Fix 1.7, Sidik's model was not sufficient, plus GNU rcs would not let me
+ * cancel it ???
+ *
+ * Revision 1.7  1999/07/03 04:10:58  thomas
+ * Changed select for 10.20
+ *
+ * Revision 1.6  98/07/10  10:38:35  10:38:35  thomas (Jim Thomas)
+ * Added perror, strerror, memset, drand48 to SunOS prototypes
+ * 
+ * Revision 1.5  97/12/18  21:28:43  21:28:43  thomas (Jim Thomas)
+ * Put floatingpoint.h back in, added strtol, changed __STDC__ to __GNUC__
+ * 
+ * Revision 1.4  97/12/18  02:38:20  02:38:20  isani (Sidik Isani)
+ * Added redefinition of CFHT_SIG_{DFL,IGN} for SunOS
+ * 
+ * Revision 1.3  1997/12/05 20:49:44  thomas
+ * Added definition of const if not ANSI C
+ *
+ * Revision 1.2  97/12/05  20:20:44  20:20:44  jcc (Jean-Charles Cuillandre)
+ * Added include of resource.h
+ * 
+ * Revision 1.1  1997/11/23 11:29:04  isani
+ * Initial revision
+ *
+ ****************************************************************************/
+
+#ifndef _INCLUDED_missing_protos
+#define _INCLUDED_missing_protos 1
+
+/*
+ * Make.Common defines *one* of the following:
+ *             SUNOS, SOLARIS, HPUX, LINUX, VXWORKS, or CYGWIN32
+ * We will use these here, but for projects where Make.Include is used
+ * instead of Make.Common, check for some other predefined symbols like
+ * __sun__ to try to figure out the system type.
+ */
+
+#if defined(SunOS) && !defined(SUNOS)
+#define SUNOS
+#endif
+
+#if (defined(Linux) || defined(linux)) && !defined(LINUX)
+#define LINUX
+#endif
+
+/*
+ * First, make sure SUNOS didn't get defined by accident for a Solaris box.
+ * We use SOLARIS instead, because they are really different OS's.
+ */
+
+#if defined(SUNOS) && defined(__svr4__)
+#undef SUNOS
+#ifndef SOLARIS
+#define SOLARIS
+#endif
+#endif
+
+#if !defined(SUNOS) && !defined(SOLARIS) && !defined(HPUX) && !defined(LINUX) && !defined(CYGWIN32) && !defined(VXWORKS)
+/*
+ * If Make.Common isn't being used ...
+ */
+#if defined(__sun__) || defined(sun)
+#ifndef sun
+#define sun
+#endif
+#ifdef __svr4__
+#define SOLARIS
+#else
+#define SUNOS
+#endif
+#else
+#if defined(__hpux__) || defined(hpux)
+#ifndef hpux
+#define hpux
+#endif
+#define HPUX
+#else
+#if defined(vxWorks)
+#define VXWORKS
+#else
+error: Unknown system type!
+error: This software has not been tested on this platform.
+error: (comment out this block to compile anyway).
+#endif /* vxWorks */
+#endif /* __hpux__ */
+#endif /* __sun__ */
+#endif /* !SUNOS && !SOLARIS && !HPUX ... */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* "const" has been added to a bunch of definitions, but that is ANSI :-( */
+#ifndef __STDC__
+#define const
+#endif
+
+/*
+ * Here are the hacks for the old suns, so we don't have to include them
+ * in each source file.  Solaris 2.x does not need any of this stuff...
+ */
+
+#ifdef SUNOS
+#define mktime timelocal
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/resource.h>
+#ifndef WCOREDUMP
+#define WCOREDUMP(n) 0
+#endif
+#include <malloc.h>
+#include <unistd.h>
+#ifdef __GNUC__
+#include <float.h>             /* for DBL_MIN and DBL_MAX */
+#else
+#include <values.h>
+#ifndef DBL_MIN
+#define DBL_MIN MINDOUBLE
+#define DBL_MAX MAXDOUBLE
+#endif
+#endif /* !__GNUC__ */
+#ifdef __GNUC__
+void    perror(const char *s);
+char	*strerror(int);
+int     ioctl(int, int, ...);
+int	sync(void);
+int     select(int, fd_set*, fd_set*, fd_set*, struct timeval*);
+/* bzero is not ANSI, but the FD_ macros for select need it, so we need a
+ * proto here to prevent warnings.  Use memset() in your own code instead!
+ */
+void    bzero(char*, int);
+void*   memset(void*, int, size_t);
+int     socket(int, int, int);
+int     bind(int,  struct sockaddr*, int);
+int     listen(int, int);
+int     connect(int, struct sockaddr*, int);
+int     accept(int, struct sockaddr*, int*);
+int     shutdown(int, int);
+int     getsockname(int,struct sockaddr*,int*);
+int     getpeername(int,struct sockaddr*,int*);
+int     setsockopt(int,int,int,const void*,int);
+int     socketpair(int,int,int,int [2]);
+int     getrlimit(int,struct rlimit*);
+int     setrlimit(int,const struct rlimit*);
+int     gettimeofday(struct timeval *tp, struct timezone *tzp);
+int     rename(const char*, const char*);
+int     symlink(const char*, const char*);
+int     readlink(const char*, char*, int);
+int     lstat(const char*, struct stat*);
+int	mknod(char *, int, int);
+int     openlog(const char*, int, int);
+int     syslog(int, const char*, ...);
+int     getitimer(int, struct itimerval*);
+int     setitimer(int, const struct itimerval*, struct itimerval*);
+int	fchmod(int, int);
+int	getdtablesize(void);
+int	semop(int, struct sembuf*, unsigned int);
+key_t	ftok(const char *, int);
+int	semget(key_t, int, int);
+int	lockf(int, int, off_t);
+int	flock(int, int);
+int	ftruncate(int, off_t);
+/* %%% The protos for CFHT_SIG_DFL et al are defined in terms of
+ *     SIG_DFL et al defined in signal.h, but unfortunately these
+ *     are not properly prototyped either :-(  Overriding them here
+ *     is kind of dangerous, and should be checked carefully.
+ */
+#undef  CFHT_SIG_DFL
+#undef  CFHT_SIG_IGN
+#define CFHT_SIG_DFL ((PFV)(0))
+#define CFHT_SIG_IGN ((PFV)(1))
+/*
+ * C library contains these (there is NO optopt in SUNOS, but its getopt also
+ * never returns ':'.  Instead, it prints its own message about missing args.
+ */
+extern char *optarg;
+extern int optind, opterr;
+#else  /* not __GNUC__ */
+#include <floatingpoint.h>
+void perror();
+char *strerror();
+void *memset();
+double drand48();
+long strtol();
+#endif /* __GNUC__ */
+#endif /* SUNOS */
+
+/*
+ * Here are the hacks that are also needed on the newer Solaris 2.x machines.
+ */
+#if defined(SUNOS) || defined(SOLARIS)
+#include <unistd.h>
+#ifdef __STDC__
+int	gethostname(char*, int);
+int     seteuid(uid_t euid);
+int     setegid(gid_t egid);
+int	setreuid(uid_t, uid_t);
+int	setregid(gid_t, gid_t);
+char*   crypt(const char*, const char*);
+#endif
+extern char** environ;
+#endif
+
+/*
+ * HPUX has some quirks too.
+ */
+#ifdef HPUX
+#if defined(OSVersion) && (OSVersion < 10)
+/*
+ * Make.Common defines HACK_SELECT directly and doesn't use this.
+ * See #if/not HACK_SELECT below also.
+ */
+#define HACK_SELECT
+#endif
+
+/* HP 10.20 seems not to define socklen_t */
+
+#define socklen_t int
+
+/* See comments above under SUNOS */
+#undef  CFHT_SIG_DFL
+#undef  CFHT_SIG_IGN
+#define CFHT_SIG_DFL ((PFV)(0))
+#define CFHT_SIG_IGN ((PFV)(1))
+
+#define seteuid(euid) setresuid(-1,(euid),-1)
+#define setegid(egid) setresgid(-1,(egid),-1)
+#ifdef __STDC__
+/* HP-UX 9 needed these.  Shouldn't hurt under 10.20 as long as they match. */
+void openlog(const char *, int, int);
+void syslog(int, const char *, ...);
+#endif
+#else /* not HP */
+#ifdef __STDC__
+/* only HP provides a prealloc function */
+int	prealloc(int fildes, unsigned size);
+#endif
+#endif
+
+/*
+ * CYGWIN32 is still in beta, so probably much of this stuff
+ * will need to be removed once this compiler stabilizes.
+ */
+#ifdef CYGWIN32
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#define seteuid(x) (0)
+#define setegid(x) (0)
+#define setuid(x)  (0)
+#define setgid(x)  (0)
+int readlink(const char*, char*, int);
+int select(int,fd_set*,fd_set*,fd_set*,struct timeval*);
+int lstat(const char*, struct stat*);
+int gettimeofday(struct timeval*, struct timezone*);
+const char* crypt(const char*, const char*);
+#endif
+
+/*
+ * Before version 10, HP defines fd_set, but doesn't use it in the prototype
+ * for select().  Also the count is size_t (which is right, why did ANSI
+ * lose that one?  I guess because C does not really support types :-( ).
+ * So do select() like this to avoid warnings on HP
+ *
+ *   Status = SELECT(n, read, write, error, &timestruct);
+ */
+#ifdef HACK_SELECT
+#define SELECT(n, read, write, error, tp)        \
+        select((size_t) (n), (int *) (read),     \
+               (int *) (write), (int *) (error), \
+	       (tp))
+#else
+/* Let the compiler check against a real prototype. */
+#define SELECT select
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !_INCLUDED_missing_protos */
