Index: /tags/addstar-1-7/Ohana/src/addstar/Makefile
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/Makefile	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/Makefile	(revision 9206)
@@ -0,0 +1,269 @@
+default: addstar
+help:
+	@echo "make options: addstar (default)"
+
+include ../../Configure
+
+HOME 	=	$(ROOT)/src/addstar
+BIN	=	$(HOME)/bin
+INC	= 	$(HOME)/include
+SRC	=	$(HOME)/src
+MAN	=	$(HOME)/doc
+DESTBIN	=	$(LBIN)
+DESTLIB	=	$(LLIB)
+DESTINC	=	$(LINC)
+DESTMAN	=	$(LMAN)
+
+#  
+INCS	= 	-I$(INC) -I$(LINC) -I$(XINC)
+LIBS	= 	-L$(LLIB) -L$(XLIB) -ldvo -lkapa -lFITS -lohana -lz -lm
+CFLAGS	=	$(INCS)
+LFLAGS	=	$(LIBS)
+
+ADDSTAR = \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/SkyListForStars.$(ARCH).o \
+$(SRC)/SkyRegionUtils.$(ARCH).o \
+$(SRC)/SkyTableFromTychoIndex.$(ARCH).o \
+$(SRC)/addstar.$(ARCH).o \
+$(SRC)/airmass.$(ARCH).o \
+$(SRC)/args.$(ARCH).o \
+$(SRC)/build_links.$(ARCH).o \
+$(SRC)/calibrate.$(ARCH).o \
+$(SRC)/dump.$(ARCH).o \
+$(SRC)/edge_check.$(ARCH).o \
+$(SRC)/fakeimage.$(ARCH).o \
+$(SRC)/find_matches.$(ARCH).o \
+$(SRC)/find_matches_closest.$(ARCH).o \
+$(SRC)/find_matches_refstars.$(ARCH).o \
+$(SRC)/find_subset.$(ARCH).o \
+$(SRC)/get2mass.$(ARCH).o \
+$(SRC)/get2mass_as.$(ARCH).o \
+$(SRC)/get2mass_as_raw.$(ARCH).o \
+$(SRC)/get2mass_dr2.$(ARCH).o \
+$(SRC)/get2mass_ops.$(ARCH).o \
+$(SRC)/getgsc.$(ARCH).o \
+$(SRC)/gettycho.$(ARCH).o \
+$(SRC)/getusno.$(ARCH).o \
+$(SRC)/getusnob.$(ARCH).o \
+$(SRC)/gimages.$(ARCH).o \
+$(SRC)/greference.$(ARCH).o \
+$(SRC)/grefstars.$(ARCH).o \
+$(SRC)/gstars.$(ARCH).o \
+$(SRC)/in_image.$(ARCH).o \
+$(SRC)/load_subpix.$(ARCH).o \
+$(SRC)/opening_angle.$(ARCH).o \
+$(SRC)/parse_time.$(ARCH).o \
+$(SRC)/replace_match.$(ARCH).o \
+$(SRC)/resort_catalog.$(ARCH).o \
+$(SRC)/rfits.$(ARCH).o \
+$(SRC)/rtext.$(ARCH).o \
+$(SRC)/sort_lists.$(ARCH).o \
+$(SRC)/update_coords.$(ARCH).o
+
+ADDSTARD = \
+$(SRC)/CheckPassword.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/NewImage.$(ARCH).o \
+$(SRC)/NewRefcat.$(ARCH).o \
+$(SRC)/NewReflist.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/SkyListForStars.$(ARCH).o \
+$(SRC)/SkyRegionUtils.$(ARCH).o \
+$(SRC)/SkyTableFromTychoIndex.$(ARCH).o \
+$(SRC)/SocketOps.$(ARCH).o \
+$(SRC)/UpdateDatabase_Image.$(ARCH).o \
+$(SRC)/UpdateDatabase_Refcat.$(ARCH).o \
+$(SRC)/UpdateDatabase_Reflist.$(ARCH).o \
+$(SRC)/addstard.$(ARCH).o \
+$(SRC)/airmass.$(ARCH).o \
+$(SRC)/args_server.$(ARCH).o \
+$(SRC)/build_links.$(ARCH).o \
+$(SRC)/calibrate.$(ARCH).o \
+$(SRC)/edge_check.$(ARCH).o \
+$(SRC)/find_matches.$(ARCH).o \
+$(SRC)/find_matches_closest.$(ARCH).o \
+$(SRC)/find_matches_refstars.$(ARCH).o \
+$(SRC)/find_subset.$(ARCH).o \
+$(SRC)/get2mass.$(ARCH).o \
+$(SRC)/get2mass_as.$(ARCH).o \
+$(SRC)/get2mass_as_raw.$(ARCH).o \
+$(SRC)/get2mass_dr2.$(ARCH).o \
+$(SRC)/get2mass_ops.$(ARCH).o \
+$(SRC)/getgsc.$(ARCH).o \
+$(SRC)/gettycho.$(ARCH).o \
+$(SRC)/getusno.$(ARCH).o \
+$(SRC)/getusnob.$(ARCH).o \
+$(SRC)/gimages.$(ARCH).o \
+$(SRC)/greference.$(ARCH).o \
+$(SRC)/in_image.$(ARCH).o \
+$(SRC)/load_subpix.$(ARCH).o \
+$(SRC)/opening_angle.$(ARCH).o \
+$(SRC)/replace_match.$(ARCH).o \
+$(SRC)/sort_lists.$(ARCH).o \
+$(SRC)/update_coords.$(ARCH).o
+
+ADDSTART = \
+$(SRC)/addstart.$(ARCH).o \
+$(SRC)/DatasetOps.$(ARCH).o \
+$(SRC)/SocketOps.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/args_server.$(ARCH).o \
+$(SRC)/CheckPassword.$(ARCH).o \
+$(SRC)/UpdateDatabase_Image.$(ARCH).o \
+$(SRC)/UpdateDatabase_Reflist.$(ARCH).o \
+$(SRC)/UpdateDatabase_Refcat.$(ARCH).o \
+$(SRC)/airmass.$(ARCH).o \
+$(SRC)/build_links.$(ARCH).o \
+$(SRC)/calibrate.$(ARCH).o \
+$(SRC)/find_matches.$(ARCH).o \
+$(SRC)/find_matches_closest.$(ARCH).o \
+$(SRC)/find_matches_refstars.$(ARCH).o \
+$(SRC)/find_subset.$(ARCH).o \
+$(SRC)/get2mass.$(ARCH).o \
+$(SRC)/get2mass_as.$(ARCH).o \
+$(SRC)/get2mass_as_raw.$(ARCH).o \
+$(SRC)/get2mass_dr2.$(ARCH).o \
+$(SRC)/get2mass_ops.$(ARCH).o \
+$(SRC)/getgsc.$(ARCH).o \
+$(SRC)/getusno.$(ARCH).o \
+$(SRC)/getusnob.$(ARCH).o \
+$(SRC)/gettycho.$(ARCH).o \
+$(SRC)/greference.$(ARCH).o \
+$(SRC)/gimages.$(ARCH).o \
+$(SRC)/in_image.$(ARCH).o \
+$(SRC)/load_subpix.$(ARCH).o \
+$(SRC)/replace_match.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/SkyRegionUtils.$(ARCH).o \
+$(SRC)/SkyListForStars.$(ARCH).o \
+$(SRC)/sort_lists.$(ARCH).o \
+$(SRC)/update_coords.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/edge_check.$(ARCH).o \
+$(SRC)/opening_angle.$(ARCH).o \
+$(SRC)/SkyTableFromTychoIndex.$(ARCH).o \
+$(SRC)/ListenClients_Thread.$(ARCH).o \
+$(SRC)/NewImage_Thread.$(ARCH).o \
+$(SRC)/NewReflist_Thread.$(ARCH).o \
+$(SRC)/NewRefcat_Thread.$(ARCH).o 
+
+ADDSTARC = \
+$(SRC)/addstarc.$(ARCH).o \
+$(SRC)/SocketOps.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/gstars.$(ARCH).o \
+$(SRC)/grefstars.$(ARCH).o \
+$(SRC)/load_subpix.$(ARCH).o \
+$(SRC)/rfits.$(ARCH).o \
+$(SRC)/parse_time.$(ARCH).o \
+$(SRC)/rtext.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/args_client.$(ARCH).o
+
+### this program may need to be repaired (EAM 2006.08)
+MKACC-2MASS = \
+$(SRC)/mkacc-2mass.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/get2mass_as.$(ARCH).o
+
+LOAD-2MASS = \
+$(SRC)/load2mass.$(ARCH).o \
+$(SRC)/load2mass_as_rawdata.$(ARCH).o \
+$(SRC)/load2mass_catalog.$(ARCH).o \
+$(SRC)/get2mass_ops.$(ARCH).o \
+$(SRC)/find_matches_refstars.$(ARCH).o \
+$(SRC)/args_load2mass.$(ARCH).o \
+$(SRC)/sort_lists.$(ARCH).o \
+$(SRC)/replace_match.$(ARCH).o \
+$(SRC)/update_coords.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o
+
+SEDSTAR = \
+$(SRC)/sedstar.$(ARCH).o \
+$(SRC)/SEDtableLoad.$(ARCH).o \
+$(SRC)/SEDfit.$(ARCH).o \
+$(SRC)/SEDops.$(ARCH).o \
+$(SRC)/args_sedstar.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o
+
+$(ADDSTARC) : $(INC)/addstar.h
+$(ADDSTARD) : $(INC)/addstar.h
+$(ADDSTART) : $(INC)/addstar.h
+$(ADDSTAR)  : $(INC)/addstar.h
+
+addstar                : $(BIN)/addstar.$(ARCH)
+$(BIN)/addstar.$(ARCH) : $(ADDSTAR)
+
+addstard                : $(BIN)/addstard.$(ARCH)
+$(BIN)/addstard.$(ARCH) : $(ADDSTARD)
+
+addstart                : $(BIN)/addstart.$(ARCH)
+$(BIN)/addstart.$(ARCH) : $(ADDSTART)
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS) -lpthread
+
+addstarc                : $(BIN)/addstarc.$(ARCH)
+$(BIN)/addstarc.$(ARCH) : $(ADDSTARC)
+
+mkacc-2mass                : $(BIN)/mkacc-2mass.$(ARCH)
+$(BIN)/mkacc-2mass.$(ARCH) : $(MKACC-2MASS)
+mkacc-2mass.install        : $(DESTBIN)/mkacc-2mass
+
+sedstar                  : $(BIN)/sedstar.$(ARCH)
+$(BIN)/sedstar.$(ARCH)   : $(SEDSTAR)
+sedstar.install          : $(DESTBIN)/sedstar
+
+load2mass                : $(BIN)/load2mass.$(ARCH)
+$(BIN)/load2mass.$(ARCH) : $(LOAD-2MASS)
+load2mass.install        : $(DESTBIN)/load2mass
+
+gztest                  : $(BIN)/gztest.$(ARCH)
+
+all: addstar addstarc addstard addstart sedstar load2mass
+
+INSTALL = addstar
+
+# dependancy rules for binary code #########################
+.PRECIOUS: %.$(ARCH).o
+.PRECIOUS: $(BIN)/%.$(ARCH)
+
+%.$(ARCH).o : %.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+$(BIN)/%.$(ARCH) : $(SRC)/%.$(ARCH).o
+	@if [ ! -d $(BIN) ]; then mkdir -p $(BIN); fi
+	$(CC) $^ -o $@ $(LFLAGS)
+
+$(DESTBIN)/%: $(BIN)/%.$(ARCH)
+	@if [ ! -d $(DESTBIN) ]; then mkdir -p $(DESTBIN); fi
+	rm -f $(DESTBIN)/$*
+	cp $(BIN)/$*.$(ARCH) $(DESTBIN)/$*
+
+$(INSTALL) $(DEVEL): % : $(BIN)/%.$(ARCH)
+
+%.clean :
+	rm -f $(BIN)/$*.$(ARCH)
+
+%.install:
+	make $(DESTBIN)/$*
+
+# utilities #################################################
+
+install:
+	for i in $(INSTALL); do make $$i.install; done
+
+clean:	
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
Index: /tags/addstar-1-7/Ohana/src/addstar/bin/.cvsignore
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/bin/.cvsignore	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/bin/.cvsignore	(revision 9206)
@@ -0,0 +1,2 @@
+*.linux *.lin64 *.sol *.sun *.sid *.hp *.irix
+*.linrh
Index: /tags/addstar-1-7/Ohana/src/addstar/doc/ChangeLog.txt
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/doc/ChangeLog.txt	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/doc/ChangeLog.txt	(revision 9206)
@@ -0,0 +1,77 @@
+
+- addstar 1.7 (2006.10.04)
+  * converted to gfits APIs (forces libfits 1.6)
+  * added the -resort option
+  * added timeout for large operations
+  * dropped old versions now not needed
+  * converted to the new DVO APIs (forces libdvo 1.3)
+  * added 'sedstar'
+  * added 'load2mass'
+  * more error checks on config
+  * converted to 'check_dir_access' 
+  * check that catalog stars fall in image (or skip catalog)
+  * fixed memory leak issues in find_matches
+  * changed match projection to ZEA
+  * fixed some 0,360 boundary errors
+
+- addstar 1.6
+  * added the 'fakeimage' mode
+
+- addstar 1.5
+  * fixed up skyregion errors
+  * added untested threaded server version
+  * added Tycho catalog
+  * added USNO-B catalog
+  * added proper motion and parallax
+  * fixed 2MASS to work with skyregions correctly
+  * dropped IMAGE_CATALOG from config
+  * changed to used dvo_image_lock,unlock
+  * cleaned up excess verbosity for timing tests
+  * added -photcode (supplement -p)
+  * added PMTEST format
+
+- addstar 1.4
+  * major work to support SkyRegions
+  * cleaned up signed/unsigned inconsistencies
+  * fixed 2MASS time to use JD 
+
+2005.10.20 : addstar-1.3
+
+	This release incorportates many substantial improvements
+	needed to handle the panstarrs data problems:
+	- internal data representation now high precision
+	- multiple data storage formats (LONEOS, ELIXIR, PANSTARRS)
+	- multiple data storage modes (RAW, MEF, SPLIT)
+	- alternative matching scheme (-closest)
+	- sorted output tables now optional
+	- incremental updates possible for inserts
+	- client / server set now defined
+
+2005.08.15 : addstar-1.2
+
+        This is a snapshot release before I begin serious work on the
+	code to handle alternate formats and so forth needed for the
+	panstarrs support.  Minor updates since v1.1, mostly to fix
+	2MASS issues and to stay in sync with the libs.  
+
+2005.07.06 : addstar-1.1
+
+	I have made a variety of fairly substantial changes since
+        v1.0.  I have added autocode for the basic DVO data types.  I
+        have merged the functionality of addspphot, addrefs, and
+        addusno into the single addstar function.  There are now
+        options to add an ascii text table or stars from known
+        external reference catalogs (HST GSC, USNO, 2MASS).  Also, the
+        functions added for skyprobe (in-flight Mcal calculation,
+        color terms) are also incorporated.  I also substantially
+        re-organized the basic code to make the different modes more
+        sensible.  There are still a few changes needed for addstar
+        v2.0 (which will be able to handle the pan-starrs bandwidth).
+        specifically, addstar needs to handle the catalog files using
+        the TBD sky.db interfaces, it needs to interact with a DVO
+        server in a client/server way (to divide up the sky), it needs
+        to handle multiple versions of the table formats, and it might
+        need to know about the mysql backend interface.  
+
+2005.02.24 : I am adding the mosaic two-level astrometry information to the Image table.
+
Index: /tags/addstar-1-7/Ohana/src/addstar/doc/camera-sample.txt
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/doc/camera-sample.txt	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/doc/camera-sample.txt	(revision 9206)
@@ -0,0 +1,81 @@
+# example camera layout file
+
+# arcsec per mm
+PLATE_SCALE  25.0
+
+DPLATE_X     1.0e-5
+DPLATE_Y     1.0e-5
+
+NCHIPS        64
+NAXIS1      4800
+NAXIS2      4800
+
+# mm per pixel
+PIXEL_SCALE   0.010
+
+# for now, we force the chip rotation to be 0 and parity to be 1,1
+# ref      name  dX      dY
+CHIP.000   x0y0 -19200  -19200
+CHIP.001   x1y0 -14400  -19200
+CHIP.002   x2y0  -9600  -19200
+CHIP.003   x3y0  -4800  -19200
+CHIP.004   x4y0      0  -19200
+CHIP.005   x5y0   4800  -19200
+CHIP.006   x6y0   9600  -19200
+CHIP.007   x7y0  14400  -19200
+CHIP.008   x0y1 -19200  -14400
+CHIP.009   x1y1 -14400  -14400
+CHIP.010   x2y1  -9600  -14400
+CHIP.011   x3y1  -4800  -14400
+CHIP.012   x4y1      0  -14400
+CHIP.013   x5y1   4800  -14400
+CHIP.014   x6y1   9600  -14400
+CHIP.015   x7y1  14400  -14400
+CHIP.016   x0y2 -19200   -9600
+CHIP.017   x1y2 -14400   -9600
+CHIP.018   x2y2  -9600   -9600
+CHIP.019   x3y2  -4800   -9600
+CHIP.020   x4y2      0   -9600
+CHIP.021   x5y2   4800   -9600
+CHIP.022   x6y2   9600   -9600
+CHIP.023   x7y2  14400   -9600
+CHIP.024   x0y3 -19200   -4800
+CHIP.025   x1y3 -14400   -4800
+CHIP.026   x2y3  -9600   -4800
+CHIP.027   x3y3  -4800   -4800
+CHIP.028   x4y3      0   -4800
+CHIP.029   x5y3   4800   -4800
+CHIP.030   x6y3   9600   -4800
+CHIP.031   x7y3  14400   -4800
+CHIP.032   x0y4 -19200       0
+CHIP.033   x1y4 -14400       0
+CHIP.034   x2y4  -9600       0
+CHIP.035   x3y4  -4800       0
+CHIP.036   x4y4      0       0
+CHIP.037   x5y4   4800       0
+CHIP.038   x6y4   9600       0
+CHIP.039   x7y4  14400       0
+CHIP.040   x0y5 -19200    4800
+CHIP.041   x1y5 -14400    4800
+CHIP.042   x2y5  -9600    4800
+CHIP.043   x3y5  -4800    4800
+CHIP.044   x4y5      0    4800
+CHIP.045   x5y5   4800    4800
+CHIP.046   x6y5   9600    4800
+CHIP.047   x7y5  14400    4800
+CHIP.048   x0y6 -19200    9600
+CHIP.049   x1y6 -14400    9600
+CHIP.050   x2y6  -9600    9600
+CHIP.051   x3y6  -4800    9600
+CHIP.052   x4y6      0    9600
+CHIP.053   x5y6   4800    9600
+CHIP.054   x6y6   9600    9600
+CHIP.055   x7y6  14400    9600
+CHIP.056   x0y7 -19200   14400
+CHIP.057   x1y7 -14400   14400
+CHIP.058   x2y7  -9600   14400
+CHIP.059   x3y7  -4800   14400
+CHIP.060   x4y7      0   14400
+CHIP.061   x5y7   4800   14400
+CHIP.062   x6y7   9600   14400
+CHIP.063   x7y7  14400   14400
Index: /tags/addstar-1-7/Ohana/src/addstar/doc/notes.txt
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/doc/notes.txt	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/doc/notes.txt	(revision 9206)
@@ -0,0 +1,393 @@
+
+2006.04.02
+
+  I am considering an option to insert fake camera images into the
+  database.  The camera would be described with a file specifying the
+  dimensions of each chip (Nx,Ny,pixel scale), the location of each
+  chip in the focal plane, and the optical parameters of the camera
+  (plate scale at center, x,y distortion terms).  Each call to addstar
+  would specify the boresite center:
+
+  addstar -fakeimage ra dec theta
+
+  the camera parameters should be loaded via the config information.
+
+2005.10.24
+
+  I have changed addstar to use the new, more flexible, SkyRegion
+  concept to define the sky layout rather than just the GSCRegion
+  files.  This includes the ability to subdivide the existing
+  GSCRegion concept, and to have a more flexible sky table
+  arrangement.  
+
+  Names of catalog files are a bit tricky.  The SkyRegion functions
+  return base names without fullpath or extensions (ie, n0000/0012).
+  There are a few places in addstar which need the fullname:
+
+  SkyListExitingSubset () requires the path and adds .cpt
+
+  load_pt_catalog () takes the path and adds .cpt.  it also allocates
+  a filename entry for catalog, which is freed later in the loop in
+  addstars
+
+  mkcatalog uses the name in the catalog structure and replaces .cpt
+  with .cpm, .cpn, .cps as needed.
+
+  *** I need to fix the name method: common function to set it once 
+  in the dvo functions.  perhaps a pointer in the SkyRegion structure.
+  This needs some 32/64 bit care, though.  use a long long (or other 
+  type guaranteed to be 64 bit), and case to the appropriate type (size_t) 
+  when it is used?  also needs to be freed.
+
+todo:
+
+  * sky db tools 
+  * parallel servers
+  * threaded addstard
+  * dvo_load daemon
+  * getstar (program and c-client)
+  * parallal / proper-motion data
+  * other additional Average / Measure columns
+  * deal with Myyyy as sky value
+  * better way to interpret flips header info for sky?
+  * fix unlink empty file problem
+  * programs like relphot and dvo need to be provided 
+    with sorted measure tables; add this as a feature 
+    of the load_catalog API?
+
+done:
+
+  o move addstar/gstars to AddstarClientOptions
+  o add thiscode to AddstarClientOptions
+  o address MOSAIC somehow
+  o replace skyprobe mode
+  o complete server db interactions
+  o address the cat & ref modes in client/server
+  o add airmass quality to options
+
+2005.10.19
+
+	I have added the client / server mode, and tested it out to a
+	fair degree.  It handles all of the available addstar modes,
+	including -ref and -cat.  A handful of things still need to be
+	done, including pushing some of the logic to enforce sorting
+	into the dvo load_catalog functions.  Also, I need to correct
+	the idiosyncratic problem with sky vs Myyyy for the skyprobe
+	data.  There are a handful of other improvements that are
+	needed before addstar / DVO is ready for IPP release.
+	However, at this point, it is ready for internal use by the
+	grad students, but not yet ready for CFHT use with Elixir.
+
+2005.10.14
+
+  the current db interactions are somewhat in efficient wrt the image
+  table.  the basic outline is as follows:
+
+  - load image overlaps (needs entire image table)
+  - find detection matches (uses overlap information for missed)
+  - save new image (needs calculated calibration value from detection
+    matches)
+  
+  currently, I access the image table twice, and both times I load the
+  entire thing.  I really only need to append in the second case.  To
+  get to that point, I need to:
+
+  - split image overlaps from image db load
+  - define image partial load (analogous with catalog LOAD_MEAS_META)
+  
+  for the moment, I'm being wasteful so I can defer this issue.
+
+2005.10.13
+
+  I am working to minimize usage of globals and cleanup addstar
+  functions to make them more appropriate for the client / server
+  model.  
+
+  I have dropped save_pt_catalog, and modified load_pt_catalog, as
+  well as the load_catalog functions.  Now, the choice of elements to
+  load is made by setting flags in the catalog structure itself
+  (catalog.catflags).  Thus this information is carried around by the
+  catalog variable.  the load_pt_catalog function now only returns
+  true.  it is now necessary to check the state of the disk file by
+  examining Nave_disk to decide if the file is empty or not.  This is
+  perhaps too limiting: it prevents us from using only one of the
+  catalog tables (say measure without average).  The concern I have is
+  to manage the process of cleaning up the catalogs if no data is
+  added to them:  I don't want addstar to leave behind empty files
+  (plus, I think this breaks the lock/load state logic).  Thus,
+  whenever addstar unlocks / closes a file, if the Nave_disk +
+  Naverage is 0, the file should be unlinked.
+
+2005.10.12
+
+  By friday (2005.10.07), I managed to get the update process
+  working well, and tested it with some example data to demonstrate
+  that the partial update improved speed hugely.  Saturday, I started
+  to work on the client/server separation of addstar.  The first step
+  was to test out socket communication issues.  I set up a simple
+  client/server pair, in which one program listens on a socket while
+  the client connects to the socket and sends some command.  I set up
+  two autocode functions to send and receive complete structures
+  (Send_*, Recv_*) and added these to libautocode.  I have been able
+  to demonstrate sending Stars, Image, and Options to the server.
+
+  The next difficulty is in pulling out the command-line and
+  configuration options.  My original, somewhat lazy, design over-used
+  global variables to pass information between program sections.  This
+  needs to be cleaned up, especially if the server needs to have
+  multiple threads interacting with the db tables.  
+
+  Of the global variables that get set, some simply carry options on
+  how gstars should behave when it loads the data (including the
+  header interpretation information).  This can probably stay in the
+  globals for now.  Another group are configuration information used
+  only by the server-related functions, such as defining the location
+  of the database files and their format, etc.  These can also stay as
+  global, at least for now.  Another set of variables basically pass
+  information from the client to the server on how to behave *this
+  time*.  I have defined the AddstarClientOptions structure to carry
+  these, and will pass them from the client to the server along with
+  the stars and the image data.
+
+  Some outstanding issues:
+
+  sidereal time / latitude
+
+  I am carrying these as globals simply because the image structure
+  did not have them.  This is silly: I can define them as part of the
+  internal image structure without breaking any of the I/O issues.  
+
+  thiscode
+
+  I have been using this as a static photcode structure.  The
+  Send_*/Recv_* mechanisms are better suited to simple structures.  I
+  probably need to change this to just the code, and use the lookup
+  functions to the full structures where needed.  It can be part of
+  the options, and I should re-write functions which use it to accept
+  the options as an argument rather than rely on it as a global.
+
+  mosaic
+
+  this stores the coords structure for a needed mosaic.  this should
+  be kept, filled as needed by the client, and sent to the server with
+  the image.  perhaps it can be moved out of global.
+
+2005.10.06
+
+  I am getting seg faults from find_matches_closest, apparently
+  related to the partial Measure load.  They occur when trying to
+  realloc secfilt.  I tried to debug using the ohana_allocate stuff,
+  but it causes problems because fitsio does not fall under the ohana
+  memory system.  This is fairly bad; I should probably deal with that
+  issue before pursuing the other stuff.  Do I have to make libfits
+  depend on libohana, in which case I should probably split off libdvo
+  from libohana.  That is probably not a bad plan in any case...
+
+2005.10.07
+
+	I have finished the basic implementation of the update mode.
+	I have been able to demonstrate substantial improvements in
+	speed when the number of existing measurements dominates the
+	total number of measurements and the number of averages is
+	typically small compared to the number of measurements (ie,
+	most objects are real, detected in most images, and each new
+	image supplies many new measurements of objects which exist
+	and not many of objects which don't exist already).  The speed
+	gain is significant in this context because the average table
+	is small compared to the measure table; since both update and
+	full-load methods require the complete average table, there is
+	no difference in the load time for the average table.  
+
+	I was having some memory collision problems, and attempting to
+	use the ohana_allocate functions reminded me that the libFITS
+	functions were not supported under ohana_allocate.  This was
+	unhelpful.  I bit the bullet and split libohana into libohana
+	(base functions only, including ohana_allocate) and libdvo
+	(functions based on the libautocode structures).  Doing this
+	allowed me to make libFITS depend on libohana (including
+	ohana_allocate).  BUT, this forced me to change all LDFLAGS
+	entries in ohana to swap -lohana -lFITS for -lFITS -lohana,
+	and to add include <fitsio.h> in some cases.
+
+2005.10.06
+	split / nosort / update
+	I have added a few new concepts to addstar recently: split
+	catalog files, nosort for the measurement table, and
+	update-only.
+
+	split mode
+
+	The split mode is quite straightforeward.  In this mode, each
+	catalog is represented by a set of four files: *.cpt, *.cpm,
+	*.cpn, *.cps.  Each file contains only one FITS table of the
+	data, along with basic header and empty matrix.  Having
+	individual tables for each component of the database lets me
+	add entries without re-writing the entire table.  This should
+	save on I/O operations in the long run.  
+
+	The first file contains the table of averages, and is the file
+	normally identified in the table lookup functions.  The header
+	of this file contains the names of the other table files
+	(paths relative to the directory containing the cpt file).
+	The names and extensions are specified in 'mkcatalog.c'; all
+	other functions use the defined filename references, rather
+	than expecting a naming convention.
+
+	The additional files contain the measures (cpm), missings
+	(cpn), and secfilt (cps) elements of the catalog tables.  
+
+	To facilitate the handling of the additional filenames, file
+	pointers, and headers, Catalog was extended to include
+	pointers to the measure, missing, and secfilt files as
+	additional catalogs.  When the data are loaded into memory,
+	these catalogs are locked (as usual), and file information is
+	stored in the individual Catalog entries; the data segements
+	are all loaded into the main catalog pointers (eg, measures
+	are loaded into catalog[0].measure, rather than
+	catalog[0].measure_catalog[0].measure).
+	
+	The function 'load_catalog' auto-recognizes the SPLIT format
+	by looking for the header keyword MEASURE, identifying the
+	file containing the measures.  The identification of the RAW
+	format and the SPLIT format are not cross-checked: if the
+	NAXIS keyword is set to 2, the file is assumed to be RAW, even
+	if the MEASURE keyword is present.  Careful with this (though
+	there is no reason the main matrix should be used in a basic
+	database table).
+
+	nosort 
+
+	the nosort option by itself provides a minor processing
+	speed-up by deferring the re-sorting of the measurement table
+	until after multiple addstar processes are run.  addstar
+	should not require the measurements to be sorted, so this step
+	can be safetly deferred if only addstars are being performed.
+	the other DVO operations require the sorted table, so the sort
+	must be performed before they are run (either as part of the
+	catalog load, not implemented yet, or with a call to addstar
+	without the -nosort option set.  the real goal of the nosort
+	option is to enable the -update concept in addstar, in which
+	only the new rows are written out; this will only work if
+	addstar can handle unsorted measures. 
+
+	the nosort option required the addition of a 'sorted' element
+	in the Catalog structure to track if the data are sorted or
+	not.  On load, this flag is set based on the value of the
+	header keyword SORTED; if the data is sorted during addstar,
+	the flag is appropriately set, otherwise it is set FALSE be
+	default.  
+
+	The nosort option requires a function which can generate the
+	'next_meas' link sequence based on the measure table.  there
+	is now a function called 'build_meas_link' which generates a
+	correct link list; there is also the pair of functions
+	'init_meas_links' and'init_miss_links' to generate the links
+	in the event that the table is sorted (should be must
+	quicker).
+
+	The 'missing' table is problematic: the LONEOS and ELIXIR
+	formats do not carry an averef entry, thus they do not have
+	enough information to define the links based only on the
+	missing table.  This means we are forced to write out a sorted
+	missing table; the nosort option is invalid for the missing
+	table.  One future upgrade path is to add the averef entry to
+	the PANSTARRS format and then only require the missing table
+	to be sorted if the format is old and does not support
+	-nosort.  (Note also that, for the moment, the missing table
+	has only a single valid format).
+
+	In the process of defining the nosort option, I also cleaned
+	up a bit the find_matches functions to use clearer functions
+	for the links.  
+	
+	update
+
+	The 'update' process in principle allows addstar to
+	substantially reduce the amount of I/O it needs to perform by
+	only requiring addstar to write out new measures and new
+	average/secfilt entries.
+
+	The 'missing' table is problematic: since the format does not
+	support the 'nosort' option, it is not possible to use update
+	with the missing table.  This means we are forced to write out
+	a complete, sorted missing table.  This is currently
+	implemented in update_catalog_split by simply writing out the
+	complete missing table.  In fact, this choice is still flawed
+	because the average table, since it is not written out in full
+	each time, is inconsistent with the missing table: the Nn
+	entries for each average, which identifies the number of
+	missing entries, are not updated.  In practice, this means
+	that the -update option forces the use of the -missed option,
+	though at the moment, this is not forced or checked in any
+	way.
+
+	Note that the 'missed' table contains duplicate information
+	and can, in principle, be completely regenerated at any time.
+	This should be an addstar option: to re-construct the missing
+	table, potentially with constraints on the images which are
+	searched for matches.  
+
+2005.10.04
+	- moved measure/missing list manipulation to separate functions
+	- added concept of sorted / unsorted measure catalog
+	- defined build_meas_links and reorder_measure,missing
+	- some cleanup of both find_matches.c and find_matches_closest.c
+
+2005.10.03:
+	- dropping GSCRegion *region entry from find_matches (unused!)
+	- adding function find_matches_closest (alternate matches)
+
+2005.08.19:
+	changed load_photcode to handle CATMODE and CATFORMAT variations
+	- addstar.h: added CATMODE and CATFORMAT globals
+	- ConfigInit: read CATMODE and CATFORMAT from config
+	- gcatalog: set catalog.catmode from CATMODE
+	- mkcatalog: set CATFORMAT and CATMODE for new catalog
+	- wcatalog: set CATFORMAT for new catalog
+	
+	using full photometry conversions in find_matches
+	added SetZeroPoint to gstars to enable phot conversions
+	
+2005.08.15:
+	cleanup of the minor Wall,Werror messages
+
+2005.03.07 : notes related to new version of addstar
+
+- USNO seems to work fine now:
+
+  addstar -region 9.0 12.0 9.0 12.0 -cat usno -p USNO_RED
+  addstar -region 9.0 12.0 9.0 12.0 -cat usno -p USNO_BLUE
+
+- 2MASS seems to work as well:
+
+  addstar -region 3.0 12.0 12.0 14.0 -cat 2mass -p 2MASS_J
+  addstar -region 3.0 12.0 12.0 14.0 -cat 2mass -p 2MASS_H
+  addstar -region 3.0 12.0 12.0 14.0 -cat 2mass -p 2MASS_K
+
+- both of these are somewhat inefficient since they need to search
+  through the (larger) USNO/2MASS data files for each output ptolemy
+  region file.
+
+- GSC seems to work fine now:
+
+  addstar -region 3.0 12.0 12.0 14.0 -cat gsc 
+  (photcode is not needed here since there is only one)
+
+- images seems to work fine now
+
+- general concerns:
+
+  - RA 0,360 boundary is likely to have problems, especially with
+    region selection
+  - mosaic astrometry concepts still need to be added.
+
+  - average magnitudes are being set incorrectly in addstar (not
+    taking account of the zero-points).  I don't really want to apply
+    the colors here, but I need to do something, perhaps?
+
+    one option is to only apply the correction for the first
+    measurement of an object, unlike the way astrometry works
+    currently.  both of these should be updated based on
+    relphot/uniphot and eqiuvalent relastro/uniastro independently
+    from the addstar step.
+
Index: /tags/addstar-1-7/Ohana/src/addstar/etc/phottemp.cat
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/etc/phottemp.cat	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/etc/phottemp.cat	(revision 9206)
@@ -0,0 +1,296 @@
+SIMPLE  =                    F  / ASTROCAM PHOTOMETRY FILE                    \
+BITPIX  =                   16 /                                              \
+NAXIS   =                    2  / NUMBER OF AXES                              \
+NAXIS1  =                 1106  / NUMBER OF COLUMNS                           \
+NAXIS2  =                 1024  / NUMBER OF ROWS                              \
+BSCALE  =             1.000000 /                                              \
+BZERO   =             0.000000 /                                              \
+DATE    = '19/12/94'            / UT Date of file creation (DD/MM/YY)         \
+ORIGIN  = 'MDM Observatory'     / Michigan-Dartmouth-MIT                      \
+LATITUDE=              31.9500  / Latitude (degrees N)                        \
+LONGITUD=            -111.6150  / Longitude (degrees E)                       \
+OBSERVER= 'Metzger '            / Name of observer                            \
+TELESCOP= '1.3m McGraw-Hill'    / Telescope used for observation              \
+INSTRUME= 'Charlotte Direct'    / Instrument used for observation             \
+DETECTOR= 'Charlotte/Tek 1024^2 CCD'  / Detector used for observation         \
+FRAME   =                   32  / Frame number of observation                 \
+CCDPICNO=                   32  / Frame number of observation                 \
+OBJECT  = 'ocl0327 '            / Name of object                              \
+IMAGETYP= 'OBJECT  '            / Type of observation                         \
+EXPTIME =              250.000  / Integration time (seconds)                  \
+DARKTIME=              250.067  / Dark current time (seconds)                 \
+DATE-OBS= '19/12/94'            / UT Date of observation (DD/MM/YY)           \
+UT      = ' 05:25:44.00'        / Universal time (UTC) at exposure start      \
+JD      =       2449705.726204                                                \
+RA      =           50.700      / Right Ascension                             \
+DEC     =           89.000      / Declination                                 \
+DIRECTN =                 -1    / Moving South                                \
+EQUINOX =             1950.000  / Equinox of RA and DEC                       \
+HA      = ' 02:14:06.72'        / Hour angle at start                         \
+ST      = ' 03:49:36.85'        / Sidereal time at start                      \
+ZD      = ' 36:26:07.17'        / Zenith distance (degrees)                   \
+AIRMASS =                1.243  / Airmass at start                            \
+FILTER  = 'I KP    '            / Filter description                          \
+GAIN    =                3.350  / Nominal gain (e-/ADU)                       \
+SECPIX1 =                0.508  / Arcseconds per pixel in fast dir            \
+SECPIX2 =                0.508  / Arcseconds per pixel in slow dir            \
+CCDBIN1 =                    1  / On-chip column binning (fast dir)           \
+CCDBIN2 =                    1  / On-chip row binning (slow dir)              \
+GPROBE  = '  5000.00   7000.00'  / Guide probe X Y                            \
+DATASEC = '[51:1074,1:1024]'    / Image area of frame                         \
+CCDSEC  = '[1:1074,1:1024]'     / Image area relative to full chip            \
+BIASSEC = '[1080:1106,1:1023]'  / Overscan area of frame                      \
+UNSIGN  =                    T /                                              \
+NSTARS  =                    0  / NUMBER OF stars                             \
+CTYPE1  = 'RA---SIN          ' /                                               
+CTYPE2  = 'DEC--SIN          ' /                                               
+CDELT1  =             0.000733 /                                               
+CDELT2  =             0.000733 /                                               
+CRVAL1  =            50.191418 /                                               
+CRVAL2  =            88.998663 /                                               
+CRPIX1  =          1028.644173 /                                               
+CRPIX2  =           503.129830 /                                               
+PC001001=             0.999906 /                                               
+PC001002=             0.012081 /                                               
+PC002001=            -0.011936 /                                               
+PC002002=             0.999950 /                                               
+END                                                                           \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+ 246.5  352.1 13.000 020 1 3.2
+ 246.5  352.1 14.100 020 1 3.2
+ 279.4  328.9 13.800 020 1 3.2
+ 187.3  238.8  9.800 020 1 3.2
+ 187.3  238.8  9.800 020 1 3.2
+ 436.6  413.5 14.300 020 1 3.2
+   9.3  856.5 13.000 020 1 3.2
+   9.3  856.2 13.600 020 1 3.2
+ 319.7  697.9 12.000 020 1 3.2
+ 319.7  697.7 12.100 020 1 3.2
+ 244.3    9.5 14.100 020 1 3.2
+ 284.7  334.4 14.000 020 1 3.2
+ 127.1  122.8 14.200 020 1 3.2
+ 140.2  791.1 13.700 020 1 3.2
+ 140.2  790.8 14.400 020 1 3.2
+ 131.7  636.3 13.800 020 1 3.2
+ 423.8  700.6 13.800 020 1 3.2
+ 423.7  700.7 12.500 020 1 3.2
+ 266.2  290.7 13.800 020 1 3.2
+ 266.0  290.7 13.100 020 1 3.2
+ 570.7  721.6 13.600 020 1 3.2
+ 570.7  721.6 13.100 020 1 3.2
+ 548.7  673.0 13.700 020 1 3.2
+ 264.2  219.7 12.800 020 1 3.2
+ 264.0  219.7 12.100 020 1 3.2
+ 161.9  797.4 11.900 020 1 3.2
+ 162.0  797.2 12.200 020 1 3.2
+ 505.8  851.8 13.700 020 1 3.2
+  88.2  419.0 11.400 020 1 3.2
+  88.2  419.0 11.800 020 1 3.2
+ 426.9  613.2  9.400 020 1 3.2
+ 427.4  613.5  7.600 020 1 3.2
+ 326.1  595.2 12.100 020 1 3.2
+ 326.2  595.1 12.600 020 1 3.2
+ 444.4  845.2 14.200 020 1 3.2
+ 254.1  916.8 14.500 020 1 3.2
+ 502.6  882.4 14.200 020 1 3.2
+ 128.3  275.7 12.300 020 1 3.2
+ 128.3  275.7 12.900 020 1 3.2
+ 230.9  554.8 13.300 020 1 3.2
+ 230.9  554.7 14.200 020 1 3.2
+  47.5  685.2 13.500 020 1 3.2
+  47.5  684.9 14.200 020 1 3.2
+ 382.6  658.7 14.000 020 1 3.2
+ 182.2  330.3 14.200 020 1 3.2
+ 245.1  548.3 12.600 020 1 3.2
+ 245.3  548.0 13.200 020 1 3.2
+  50.3  849.0 13.700 020 1 3.2
+  50.5  848.8 14.300 020 1 3.2
+  17.9  772.7 14.200 020 1 3.2
+ 499.8  712.8 13.500 020 1 3.2
+ 499.8  712.6 14.400 020 1 3.2
+ 294.5  349.4 14.000 020 1 3.2
+ 497.7  747.8 11.000 020 1 3.2
+ 497.5  747.8 10.900 020 1 3.2
+ 109.7  323.5 14.000 020 1 3.2
+  59.5  917.6 14.300 020 1 3.2
+  59.4  917.8 13.700 020 1 3.2
+  82.2  880.5 13.800 020 1 3.2
+ 145.1  341.2 14.500 020 1 3.2
+ 452.7  592.4 14.400 020 1 3.2
+ 623.4  820.0 13.700 020 1 3.2
+ 609.7  829.3 13.500 020 1 3.2
+ 481.8  938.3 14.400 020 1 3.2
+ 617.0  792.7 13.500 020 1 3.2
+ 183.2  539.7 14.400 020 1 3.2
+ 133.9  679.6 14.400 020 1 3.2
+ 423.7  667.8  6.500 020 1 3.2
+ 434.7  111.9 13.200 020 1 3.2
+ 434.5  111.9 13.200 020 1 3.2
+ 434.6  111.9 14.200 020 1 3.2
+1222.3  684.2 13.900 020 1 3.2
+1077.6  282.5 14.000 020 1 3.2
+1077.8  282.5 13.400 020 1 3.2
+ 720.8  562.1 14.100 020 1 3.2
+ 721.1  561.9 14.400 020 1 3.2
+1182.1  944.4 12.100 020 1 3.2
+1181.9  944.4 11.800 020 1 3.2
+1181.9  944.4 12.300 020 1 3.2
+ 761.2  423.1 14.300 020 1 3.2
+ 761.0  423.1 14.100 020 1 3.2
+ 926.7  436.8 13.400 020 1 3.2
+ 926.6  436.8 14.200 020 1 3.2
+1209.1   45.0 13.200 020 1 3.2
+1209.2   43.6 12.800 020 1 3.2
+1135.2  653.1  8.100 020 1 3.2
+1135.6  653.4  8.200 020 1 3.2
+1123.5  735.8 12.000 020 1 3.2
+1123.6  735.8 11.800 020 1 3.2
+1123.7  735.7 11.600 020 1 3.2
+ 730.7   28.6 12.100 020 1 3.2
+ 730.7   28.6 12.200 020 1 3.2
+ 783.1  267.5 14.200 020 1 3.2
+ 783.2  267.5 13.400 020 1 3.2
+ 876.2  462.7 13.800 020 1 3.2
+ 876.4  462.7 14.200 020 1 3.2
+ 917.2  399.9 13.700 020 1 3.2
+ 917.3  399.9 13.200 020 1 3.2
+1227.5  218.4 10.400 020 1 3.2
+1227.7  218.4 10.500 020 1 3.2
+1022.7  146.0 13.300 020 1 3.2
+1022.5  146.0 14.100 020 1 3.2
+1324.7   72.3 12.900 020 1 3.2
+1324.6   72.3 13.200 020 1 3.2
+ 743.2  379.4 14.300 020 1 3.2
+ 742.9  379.4 13.900 020 1 3.2
+1255.9  544.0 12.600 020 1 3.2
+1256.0  543.9 12.300 020 1 3.2
+ 848.9  251.1 13.200 020 1 3.2
+ 849.0  251.1 12.700 020 1 3.2
+ 495.6  147.4 11.400 020 1 3.2
+ 495.6  147.4 11.300 020 1 3.2
+ 495.5  147.4 11.000 020 1 3.2
+1016.4  735.5 14.200 020 1 3.2
+1016.3  735.7 13.900 020 1 3.2
+ 795.2  675.9 14.400 020 1 3.2
+ 887.2  968.8 10.800 020 1 3.2
+ 626.8  726.9 14.400 020 1 3.2
+ 718.6  800.1  9.700 020 1 3.2
+ 675.4  301.6 14.400 020 1 3.2
+ 801.6  436.8 14.200 020 1 3.2
+1066.4  870.0 13.700 020 1 3.2
+1066.5  869.9 13.800 020 1 3.2
+ 644.5  662.9  9.900 020 1 3.2
+ 639.1  760.4 13.000 020 1 3.2
+ 822.7  663.1 12.800 020 1 3.2
+ 822.7  663.1 13.100 020 1 3.2
+ 677.2  716.2 12.900 020 1 3.2
+ 765.6  641.5 13.200 020 1 3.2
+ 765.7  641.4 13.500 020 1 3.2
+ 998.3  425.8 14.400 020 1 3.2
+ 713.7  716.2 13.800 020 1 3.2
+ 814.7  887.6  2.000 020 1 3.2
+ 808.7  884.1  8.200 020 1 3.2
+1812.3  259.3 14.500 020 1 3.2
+1655.9  655.4 12.200 020 1 3.2
+1655.9  655.4 12.100 020 1 3.2
+1577.2  839.6 11.500 020 1 3.2
+1577.2  839.6 11.400 020 1 3.2
+1643.7  597.0 14.100 020 1 3.2
+1552.8  251.1 10.100 020 1 3.2
+1552.8  251.1 10.300 020 1 3.2
+1410.0  999.9 13.900 020 1 3.2
+1335.6  687.0 13.000 020 1 3.2
+1335.8  686.8 12.700 020 1 3.2
+1471.4  262.0 14.200 020 1 3.2
+1479.6  608.3 14.200 020 1 3.2
+1478.1  211.5 12.000 020 1 3.2
+1478.3  211.5 12.000 020 1 3.2
+1552.5   46.4 14.500 020 1 3.2
+2042.4  548.3 10.800 020 1 3.2
+2042.6  548.3 11.000 020 1 3.2
+1448.0  915.7 14.100 020 1 3.2
+1462.3  989.2 13.000 020 1 3.2
+1462.3  989.0 12.700 020 1 3.2
+1316.9  787.3 14.100 020 1 3.2
+1787.6  883.5 12.200 020 1 3.2
+1787.6  883.5 12.200 020 1 3.2
+1979.1  300.3 12.900 020 1 3.2
+1979.1  300.3 12.900 020 1 3.2
+1677.2  106.4 13.100 020 1 3.2
+1677.0  106.4 13.300 020 1 3.2
+1324.2  429.9  9.200 020 1 3.2
+1324.2  429.9  9.000 020 1 3.2
+1462.8  214.3 13.700 020 1 3.2
+1462.8  214.3 14.200 020 1 3.2
+1405.4   95.5 11.700 020 1 3.2
+1405.2   95.5 11.600 020 1 3.2
+1604.8   90.0 11.200 020 1 3.2
+1604.8   90.0 11.300 020 1 3.2
+1921.5  738.1 13.500 020 1 3.2
+1921.5  738.1 13.500 020 1 3.2
+1459.8  473.6 13.400 020 1 3.2
+1459.7  473.6 13.800 020 1 3.2
+1438.7   77.8 12.200 020 1 3.2
+1438.6   77.8 12.200 020 1 3.2
+1355.0  114.6 13.000 020 1 3.2
+1354.9  114.6 13.200 020 1 3.2
+1941.4  940.7 13.000 020 1 3.2
+1941.6  940.7 12.900 020 1 3.2
+1994.0  800.8 13.900 020 1 3.2
+1993.8  800.8 14.000 020 1 3.2
+2024.4  907.0 13.700 020 1 3.2
+2024.4  907.0 13.800 020 1 3.2
+2035.7  881.6 13.900 020 1 3.2
+2035.9  881.6 13.800 020 1 3.2
+1994.0  924.2 12.100 020 1 3.2
+1994.0  924.2 12.000 020 1 3.2
Index: /tags/addstar-1-7/Ohana/src/addstar/etc/template.cat
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/etc/template.cat	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/etc/template.cat	(revision 9206)
@@ -0,0 +1,296 @@
+SIMPLE  =                    F  / ASTROCAM PHOTOMETRY FILE                    \
+BITPIX  =                   16 /                                              \
+NAXIS   =                    2  / NUMBER OF AXES                              \
+NAXIS1  =                 1106  / NUMBER OF COLUMNS                           \
+NAXIS2  =                 1024  / NUMBER OF ROWS                              \
+BSCALE  =             1.000000 /                                              \
+BZERO   =             0.000000 /                                              \
+DATE    = '19/12/94'            / UT Date of file creation (DD/MM/YY)         \
+ORIGIN  = 'MDM Observatory'     / Michigan-Dartmouth-MIT                      \
+LATITUDE=              31.9500  / Latitude (degrees N)                        \
+LONGITUD=            -111.6150  / Longitude (degrees E)                       \
+OBSERVER= 'Metzger '            / Name of observer                            \
+TELESCOP= '1.3m McGraw-Hill'    / Telescope used for observation              \
+INSTRUME= 'Charlotte Direct'    / Instrument used for observation             \
+DETECTOR= 'Charlotte/Tek 1024^2 CCD'  / Detector used for observation         \
+FRAME   =                   32  / Frame number of observation                 \
+CCDPICNO=                   32  / Frame number of observation                 \
+OBJECT  = 'ocl0327 '            / Name of object                              \
+IMAGETYP= 'OBJECT  '            / Type of observation                         \
+EXPTIME =              250.000  / Integration time (seconds)                  \
+DARKTIME=              250.067  / Dark current time (seconds)                 \
+DATE-OBS= '19/12/94'            / UT Date of observation (DD/MM/YY)           \
+UT      = ' 05:25:44.00'        / Universal time (UTC) at exposure start      \
+JD      =       2449705.726204                                                \
+RA      =           50.700      / Right Ascension                             \
+DEC     =           89.000      / Declination                                 \
+DIRECTN =                 -1    / Moving South                                \
+EQUINOX =             1950.000  / Equinox of RA and DEC                       \
+HA      = ' 02:14:06.72'        / Hour angle at start                         \
+ST      = ' 03:49:36.85'        / Sidereal time at start                      \
+ZD      = ' 36:26:07.17'        / Zenith distance (degrees)                   \
+AIRMASS =                1.243  / Airmass at start                            \
+FILTER  = 'I KP    '            / Filter description                          \
+GAIN    =                3.350  / Nominal gain (e-/ADU)                       \
+SECPIX1 =                0.508  / Arcseconds per pixel in fast dir            \
+SECPIX2 =                0.508  / Arcseconds per pixel in slow dir            \
+CCDBIN1 =                    1  / On-chip column binning (fast dir)           \
+CCDBIN2 =                    1  / On-chip row binning (slow dir)              \
+GPROBE  = '  5000.00   7000.00'  / Guide probe X Y                            \
+DATASEC = '[51:1074,1:1024]'    / Image area of frame                         \
+CCDSEC  = '[1:1074,1:1024]'     / Image area relative to full chip            \
+BIASSEC = '[1080:1106,1:1023]'  / Overscan area of frame                      \
+UNSIGN  =                    T /                                              \
+NSTARS  =                    0  / NUMBER OF stars                             \
+CTYPE1  = 'RA---SIN          ' /                                               
+CTYPE2  = 'DEC--SIN          ' /                                               
+CDELT1  =             0.000733 /                                               
+CDELT2  =             0.000733 /                                               
+CRVAL1  =            50.191418 /                                               
+CRVAL2  =            88.998663 /                                               
+CRPIX1  =          1028.644173 /                                               
+CRPIX2  =           503.129830 /                                               
+PC001001=             0.999906 /                                               
+PC001002=             0.012081 /                                               
+PC002001=            -0.011936 /                                               
+PC002002=             0.999950 /                                               
+END                                                                           \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+ 246.5  352.1 13.000 020 1 3.2
+ 246.5  352.1 14.100 020 1 3.2
+ 279.4  328.9 13.800 020 1 3.2
+ 187.3  238.8  9.800 020 1 3.2
+ 187.3  238.8  9.800 020 1 3.2
+ 436.6  413.5 14.300 020 1 3.2
+   9.3  856.5 13.000 020 1 3.2
+   9.3  856.2 13.600 020 1 3.2
+ 319.7  697.9 12.000 020 1 3.2
+ 319.7  697.7 12.100 020 1 3.2
+ 244.3    9.5 14.100 020 1 3.2
+ 284.7  334.4 14.000 020 1 3.2
+ 127.1  122.8 14.200 020 1 3.2
+ 140.2  791.1 13.700 020 1 3.2
+ 140.2  790.8 14.400 020 1 3.2
+ 131.7  636.3 13.800 020 1 3.2
+ 423.8  700.6 13.800 020 1 3.2
+ 423.7  700.7 12.500 020 1 3.2
+ 266.2  290.7 13.800 020 1 3.2
+ 266.0  290.7 13.100 020 1 3.2
+ 570.7  721.6 13.600 020 1 3.2
+ 570.7  721.6 13.100 020 1 3.2
+ 548.7  673.0 13.700 020 1 3.2
+ 264.2  219.7 12.800 020 1 3.2
+ 264.0  219.7 12.100 020 1 3.2
+ 161.9  797.4 11.900 020 1 3.2
+ 162.0  797.2 12.200 020 1 3.2
+ 505.8  851.8 13.700 020 1 3.2
+  88.2  419.0 11.400 020 1 3.2
+  88.2  419.0 11.800 020 1 3.2
+ 426.9  613.2  9.400 020 1 3.2
+ 427.4  613.5  7.600 020 1 3.2
+ 326.1  595.2 12.100 020 1 3.2
+ 326.2  595.1 12.600 020 1 3.2
+ 444.4  845.2 14.200 020 1 3.2
+ 254.1  916.8 14.500 020 1 3.2
+ 502.6  882.4 14.200 020 1 3.2
+ 128.3  275.7 12.300 020 1 3.2
+ 128.3  275.7 12.900 020 1 3.2
+ 230.9  554.8 13.300 020 1 3.2
+ 230.9  554.7 14.200 020 1 3.2
+  47.5  685.2 13.500 020 1 3.2
+  47.5  684.9 14.200 020 1 3.2
+ 382.6  658.7 14.000 020 1 3.2
+ 182.2  330.3 14.200 020 1 3.2
+ 245.1  548.3 12.600 020 1 3.2
+ 245.3  548.0 13.200 020 1 3.2
+  50.3  849.0 13.700 020 1 3.2
+  50.5  848.8 14.300 020 1 3.2
+  17.9  772.7 14.200 020 1 3.2
+ 499.8  712.8 13.500 020 1 3.2
+ 499.8  712.6 14.400 020 1 3.2
+ 294.5  349.4 14.000 020 1 3.2
+ 497.7  747.8 11.000 020 1 3.2
+ 497.5  747.8 10.900 020 1 3.2
+ 109.7  323.5 14.000 020 1 3.2
+  59.5  917.6 14.300 020 1 3.2
+  59.4  917.8 13.700 020 1 3.2
+  82.2  880.5 13.800 020 1 3.2
+ 145.1  341.2 14.500 020 1 3.2
+ 452.7  592.4 14.400 020 1 3.2
+ 623.4  820.0 13.700 020 1 3.2
+ 609.7  829.3 13.500 020 1 3.2
+ 481.8  938.3 14.400 020 1 3.2
+ 617.0  792.7 13.500 020 1 3.2
+ 183.2  539.7 14.400 020 1 3.2
+ 133.9  679.6 14.400 020 1 3.2
+ 423.7  667.8  6.500 020 1 3.2
+ 434.7  111.9 13.200 020 1 3.2
+ 434.5  111.9 13.200 020 1 3.2
+ 434.6  111.9 14.200 020 1 3.2
+1222.3  684.2 13.900 020 1 3.2
+1077.6  282.5 14.000 020 1 3.2
+1077.8  282.5 13.400 020 1 3.2
+ 720.8  562.1 14.100 020 1 3.2
+ 721.1  561.9 14.400 020 1 3.2
+1182.1  944.4 12.100 020 1 3.2
+1181.9  944.4 11.800 020 1 3.2
+1181.9  944.4 12.300 020 1 3.2
+ 761.2  423.1 14.300 020 1 3.2
+ 761.0  423.1 14.100 020 1 3.2
+ 926.7  436.8 13.400 020 1 3.2
+ 926.6  436.8 14.200 020 1 3.2
+1209.1   45.0 13.200 020 1 3.2
+1209.2   43.6 12.800 020 1 3.2
+1135.2  653.1  8.100 020 1 3.2
+1135.6  653.4  8.200 020 1 3.2
+1123.5  735.8 12.000 020 1 3.2
+1123.6  735.8 11.800 020 1 3.2
+1123.7  735.7 11.600 020 1 3.2
+ 730.7   28.6 12.100 020 1 3.2
+ 730.7   28.6 12.200 020 1 3.2
+ 783.1  267.5 14.200 020 1 3.2
+ 783.2  267.5 13.400 020 1 3.2
+ 876.2  462.7 13.800 020 1 3.2
+ 876.4  462.7 14.200 020 1 3.2
+ 917.2  399.9 13.700 020 1 3.2
+ 917.3  399.9 13.200 020 1 3.2
+1227.5  218.4 10.400 020 1 3.2
+1227.7  218.4 10.500 020 1 3.2
+1022.7  146.0 13.300 020 1 3.2
+1022.5  146.0 14.100 020 1 3.2
+1324.7   72.3 12.900 020 1 3.2
+1324.6   72.3 13.200 020 1 3.2
+ 743.2  379.4 14.300 020 1 3.2
+ 742.9  379.4 13.900 020 1 3.2
+1255.9  544.0 12.600 020 1 3.2
+1256.0  543.9 12.300 020 1 3.2
+ 848.9  251.1 13.200 020 1 3.2
+ 849.0  251.1 12.700 020 1 3.2
+ 495.6  147.4 11.400 020 1 3.2
+ 495.6  147.4 11.300 020 1 3.2
+ 495.5  147.4 11.000 020 1 3.2
+1016.4  735.5 14.200 020 1 3.2
+1016.3  735.7 13.900 020 1 3.2
+ 795.2  675.9 14.400 020 1 3.2
+ 887.2  968.8 10.800 020 1 3.2
+ 626.8  726.9 14.400 020 1 3.2
+ 718.6  800.1  9.700 020 1 3.2
+ 675.4  301.6 14.400 020 1 3.2
+ 801.6  436.8 14.200 020 1 3.2
+1066.4  870.0 13.700 020 1 3.2
+1066.5  869.9 13.800 020 1 3.2
+ 644.5  662.9  9.900 020 1 3.2
+ 639.1  760.4 13.000 020 1 3.2
+ 822.7  663.1 12.800 020 1 3.2
+ 822.7  663.1 13.100 020 1 3.2
+ 677.2  716.2 12.900 020 1 3.2
+ 765.6  641.5 13.200 020 1 3.2
+ 765.7  641.4 13.500 020 1 3.2
+ 998.3  425.8 14.400 020 1 3.2
+ 713.7  716.2 13.800 020 1 3.2
+ 814.7  887.6  2.000 020 1 3.2
+ 808.7  884.1  8.200 020 1 3.2
+1812.3  259.3 14.500 020 1 3.2
+1655.9  655.4 12.200 020 1 3.2
+1655.9  655.4 12.100 020 1 3.2
+1577.2  839.6 11.500 020 1 3.2
+1577.2  839.6 11.400 020 1 3.2
+1643.7  597.0 14.100 020 1 3.2
+1552.8  251.1 10.100 020 1 3.2
+1552.8  251.1 10.300 020 1 3.2
+1410.0  999.9 13.900 020 1 3.2
+1335.6  687.0 13.000 020 1 3.2
+1335.8  686.8 12.700 020 1 3.2
+1471.4  262.0 14.200 020 1 3.2
+1479.6  608.3 14.200 020 1 3.2
+1478.1  211.5 12.000 020 1 3.2
+1478.3  211.5 12.000 020 1 3.2
+1552.5   46.4 14.500 020 1 3.2
+2042.4  548.3 10.800 020 1 3.2
+2042.6  548.3 11.000 020 1 3.2
+1448.0  915.7 14.100 020 1 3.2
+1462.3  989.2 13.000 020 1 3.2
+1462.3  989.0 12.700 020 1 3.2
+1316.9  787.3 14.100 020 1 3.2
+1787.6  883.5 12.200 020 1 3.2
+1787.6  883.5 12.200 020 1 3.2
+1979.1  300.3 12.900 020 1 3.2
+1979.1  300.3 12.900 020 1 3.2
+1677.2  106.4 13.100 020 1 3.2
+1677.0  106.4 13.300 020 1 3.2
+1324.2  429.9  9.200 020 1 3.2
+1324.2  429.9  9.000 020 1 3.2
+1462.8  214.3 13.700 020 1 3.2
+1462.8  214.3 14.200 020 1 3.2
+1405.4   95.5 11.700 020 1 3.2
+1405.2   95.5 11.600 020 1 3.2
+1604.8   90.0 11.200 020 1 3.2
+1604.8   90.0 11.300 020 1 3.2
+1921.5  738.1 13.500 020 1 3.2
+1921.5  738.1 13.500 020 1 3.2
+1459.8  473.6 13.400 020 1 3.2
+1459.7  473.6 13.800 020 1 3.2
+1438.7   77.8 12.200 020 1 3.2
+1438.6   77.8 12.200 020 1 3.2
+1355.0  114.6 13.000 020 1 3.2
+1354.9  114.6 13.200 020 1 3.2
+1941.4  940.7 13.000 020 1 3.2
+1941.6  940.7 12.900 020 1 3.2
+1994.0  800.8 13.900 020 1 3.2
+1993.8  800.8 14.000 020 1 3.2
+2024.4  907.0 13.700 020 1 3.2
+2024.4  907.0 13.800 020 1 3.2
+2035.7  881.6 13.900 020 1 3.2
+2035.9  881.6 13.800 020 1 3.2
+1994.0  924.2 12.100 020 1 3.2
+1994.0  924.2 12.000 020 1 3.2
Index: /tags/addstar-1-7/Ohana/src/addstar/include/2mass.h
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/include/2mass.h	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/include/2mass.h	(revision 9206)
@@ -0,0 +1,43 @@
+
+/* structure for data on a catalog region */
+typedef struct {
+  char filename[256];
+  double RA[2];
+  int Nrec;
+} TM_Region;
+
+typedef struct {
+  double Rmin, Rmax, Dmin, Dmax;
+  int index[20];
+  int Nindex;
+} TMBands;
+
+typedef struct {
+  double R, D;
+  int offset;
+  int flag;
+} TMStars;
+
+short TM_J, TM_H, TM_K;
+
+SkyTable *get2mass_acc (SkyRegion *patch, char *path, char *accel);
+Stars    *get2mass_2DR_data (SkyRegion *region, char *filename, SkyRegion *patch, int photcode, int *nstars);
+Stars    *get2mass_AS_data (SkyRegion *region, char *filename, SkyRegion *patch, int phocode, int *nstars);
+Stars    *get2mass_AS_rawdata (SkyRegion *region, char *filename, SkyRegion *patch, int phocode, int *nstars);
+
+SkyTable *scan2mass_acc (char *path, char *accel);
+int       scan2mass_as_data (char *filename);
+
+char     *skipNbounds (char *line, char bound, int Nbound, int Nbyte);
+e_time    get2mass_time (char *ptr, int Nbound, int Nbyte);
+e_time    get2mass_date (char *ptr, int Nbound, int Nmax);
+
+int       load2mass_as_rawdata (SkyTable *skytable, char *filename, AddstarClientOptions options);
+SkyTable *load2mass_acc (char *path, char *accel);
+int       get2mass_3star (Stars *star, char *line, int Nmax);
+int       load2mass_catalog (Catalog *catalog, Stars *stars, int Nstars);
+
+int       get2mass_setup (int photcode);
+int       get2mass_coords (char *line, double *R, double *D, int Nmax);
+int       get2mass_star (Stars *star, char *line, int Nmax);
+int       get2mass_3star (Stars *star, char *line, int Nmax);
Index: /tags/addstar-1-7/Ohana/src/addstar/include/addstar.h
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/include/addstar.h	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/include/addstar.h	(revision 9206)
@@ -0,0 +1,227 @@
+# include <ohana.h>
+# include <dvo.h>
+# include <signal.h>
+# include <sys/time.h>
+# include <time.h>
+# include <zlib.h>
+# include <netinet/ip.h>
+# include <netdb.h>
+# include <arpa/inet.h>
+
+/* used in find_matches, find_matches_refstars */
+# define IN_CATALOG(R,D) ( \
+((D) >= region[0].Dmin) && ((D) < region[0].Dmax) && \
+((R) >= region[0].Rmin)  && ((R) < region[0].Rmax))
+
+/* grab named photcode */
+# define NAMED_PHOTCODE(CODE,NAME) \
+  CODE = GetPhotcodeCodebyName (NAME); \
+  if (!CODE) { \
+    fprintf (stderr, "ERROR:  photcode %s not found in photcode table\n", NAME); \
+    exit (0); }
+
+typedef struct {
+  int Nstars;
+  Stars *stars;
+  Image *image;
+  Coords *mosaic;
+  SkyRegion *patch;
+  AddstarClientOptions *options;
+  char *refcat;
+} DVO_DATA;
+
+typedef struct sockaddr_in SockAddress;
+
+enum {M_IMAGE, M_REFLIST, M_REFCAT, M_FAKEIMAGE, M_RESORT};
+
+/* global which define database info / data sources (KEEP) */
+char   ImageCat[256];
+char   GSCFILE[256];
+char   CATDIR[256];
+char   CATMODE[16];    /* raw, mef, split, mysql */
+char   CATFORMAT[16];  /* internal, elixir, loneos, panstarrs */
+char   TWO_MASS_DIR_AS[256];
+char   TWO_MASS_DIR_DR2[256];
+char   GSCDIR[256];
+char   USNO_A_DIR[256];
+char   USNO_B_DIR[256];
+char   TYCHO_DIR[256];
+char   SubpixDatafile[256];
+char   PASSWORD[80];
+char   HOSTNAME[80];
+int    NVALID, *VALID_IP;
+char   SKY_TABLE[256];
+int    SKY_DEPTH;  /** XXX EAM : depth of catalog tables, fix usage */
+char   CameraLayout[256];
+SkyTable *ServerSky;
+
+/* used to select entries from header (gstars or parse_time) (KEEP) */
+char   DateKeyword[64];
+char   DateMode[64];
+char   UTKeyword[64];
+char   MJDKeyword[64];
+char   JDKeyword[64];
+char   ExptimeKeyword[64];
+char   AirmassKeyword[64];
+char   CCDNumKeyword[64];
+char   STKeyword[64];
+
+/* these globals modify the behavior of gstars (KEEP) */
+double 	SNLIMIT;
+int    	ACCEPT_ASTROM;  // accept even bad astrometry solutions (NASTRO == 0)
+int    	ACCEPT_MOTION;  // accept reference proper motion measurements
+int    	TEXTMODE;       // force input file to be loaded as RAW
+int     SUBPIX;         // apply a subpix correction
+char   *DUMP;           // dump out intermediate results
+int    	XOVERSCAN;      // used to modify stored image dimensions 
+int    	YOVERSCAN;      // used to modify stored image dimensions 
+int    	XMIN;           // used to filter loaded star list 
+int    	XMAX;           // used to filter loaded star list 
+int    	YMIN;           // used to filter loaded star list 
+int    	YMAX;           // used to filter loaded star list 
+double 	Latitude;       // carried into image structure from config
+double 	Longitude;      // carried into image structure from config
+Coords *MOSAIC;         // carries the mosaic into gstars
+double  FAKE_RA;        // boresite coords for fake images
+double  FAKE_DEC;       // boresite coords for fake images
+double  FAKE_THETA;     // boresite angle for fake images
+
+/* these globals are used separately by both client and server (KEEP) */
+double ZeroPt;  // double check for consistency
+double CAL_INSTMAG_MAX;
+double CAL_INSTMAG_MIN;
+int    VERBOSE;
+int    PLOT;
+
+/* modify server behavior (make this an addstar cleanup mode?) */
+int    FORCE_READ;
+
+// XXX this should be replaced with 
+// 1) an airmass accuracy option
+// 2) an alternative CATFORMAT with the sky element correctly defined.
+
+/* these depend on HOW we implement the client/server interaction for CAT/REF modes */
+time_t    TIMEREF;    // used by MODE REF
+SkyRegion UserPatch;  // used by MODE CAT
+char     *SELECT_2MASS_QUALITY;  // used only by get2mass_as
+
+/*** addstar prototypes ***/
+void       AddToCalibration       PROTO((Average *average, Measure *measure, Measure *new, int *next, int Nstar));
+AddstarClientOptions ConfigInit   PROTO((int *argc, char **argv));
+void       FindCalibration        PROTO((Image *image));
+FILE      *GetDB                  PROTO((int *state));
+void       InitCalibration        PROTO(());
+void       SaveCalibration        PROTO((float Mo, float dMo, float Mr, float dMr, float Mi, int N));
+void       SetProtect             PROTO((int mode));
+int        SetSignals             PROTO(());
+int        Shutdown               PROTO((char *message, ...); ) 
+void       TrapSignal             PROTO((int sig));
+float      airmass                PROTO((float secz_image, double ra, double dec, double st, double latitude));
+void       SetAirmassQuality      PROTO((int quality));
+SkyTable  *SkyTableFromTychoIndex PROTO((char *filename, int VERBOSE));
+AddstarClientOptions args         PROTO((int argc, char **argv, AddstarClientOptions options));
+void       check_permissions      PROTO((char *basefile));
+int        dump_rawstars          PROTO((Stars *stars, int Nstars));
+int        edge_check             PROTO((double *x1, double *y1, double *x2, double *y2));
+Image     *fakeimage              PROTO((char *rootname, int *Nimage, int photcode));
+int        find_matches           PROTO((SkyRegion *region, Stars *stars, int Nstars, Catalog *catalog, Image *image, Image *overlap, int Noverlap, Coords *mosaic, AddstarClientOptions options));
+int        find_matches_closest   PROTO((SkyRegion *region, Stars *stars, int Nstars, Catalog *catalog, Image *image, Image *overlap, int Noverlap, Coords *mosaic, AddstarClientOptions options));
+int        find_matches_refstars  PROTO((SkyRegion *region, Stars **stars, int Nstars, Catalog *catalog, AddstarClientOptions options));
+Stars    **find_subset            PROTO((SkyRegion *region, Stars *stars, int Nstars, int *NSTARS));
+int        gcatalog               PROTO((Catalog *catalog));
+Stars     *get2mass               PROTO((SkyRegion *patch, int photcode, int mode, int *NSTARS));
+double     get_subpix             PROTO((double x, double y));
+Stars     *getgsc                 PROTO((SkyRegion *patch, int *NSTARS));
+Stars     *gettycho               PROTO((SkyRegion *catstats, int photcode, int *Nstars));
+Stars     *getusno                PROTO((SkyRegion *catstats, int photcode, int *Nstars));
+Stars     *getusnob               PROTO((SkyRegion *catstats, int photcode, int *Nstars));
+Image     *gimages                PROTO((FITS_DB *db, Image *image, Coords *mosaic, int *Npimage));
+Stars     *grefcat                PROTO((char *Refcat, SkyRegion *catstats, int photcode, int *nstars));
+Stars     *grefstars              PROTO((char *file, int photcode, int *Nstars));
+Stars     *gstars                 PROTO((char *file, int *NSTARS, int photcode, Image *image));
+int        in_image               PROTO((double r, double d, Image *image));
+int        load_pt_catalog        PROTO((Catalog *catalog, SkyRegion *region));  /*** choose new name ***/
+void       load_subpix            PROTO(());
+void       lock_image_db          PROTO((FITS_DB *db, char *filename));
+int        main                   PROTO((int argc, char **argv));
+void       make_backup            PROTO((char *filename));
+int        match_refstars         PROTO((Stars *stars, int Nstars));
+void       mkcatalog              PROTO((SkyRegion *region, Catalog *catalog));
+double     opening_angle          PROTO((double x1, double y1, double x2, double y2, double x3, double y3));
+int        parse_time             PROTO((Header *header));
+Stars     *rd_gsc                 PROTO((char *filename, int *nstars));
+int        replace_match          PROTO((Average *average, Measure *measure, Stars *star));
+void       resort_catalog         PROTO((Catalog *catalog));
+Stars     *rfits                  PROTO((FILE *f, unsigned int *nstars));
+Stars     *rtext                  PROTO((FILE *f, unsigned int *nstars));
+void       save_pt_catalog        PROTO((Catalog *catalog));  /*** choose new name ***/
+double     scat_subpix            PROTO((double x, double y));
+time_t     short_date_to_sec      PROTO((char *date));
+void       sort_lists             PROTO((float *X, float *Y, int *S, int N));
+void       sort_stars             PROTO((Stars *stars, int N));
+int        str_to_radec           PROTO((double *ra, double *dec, char *str1, char *str2));
+void       unlock_image_db        PROTO((FITS_DB *db));
+void       update_coords          PROTO((Average *average, Measure *measure, int *next));
+void       wcatalog               PROTO((Catalog *catalog));
+void       free_catalog           PROTO((Catalog *catalog));
+void       wimage                 PROTO((FITS_DB *db, Image *image));
+void       create_image_db        PROTO((FITS_DB *db));
+void       set_db                 PROTO((FITS_DB *in));
+
+void       uppercase              PROTO((char *string));
+void       fsort                  PROTO((float *X, int N));
+void       fsort2                 PROTO((float *X, float *Y, int N));
+
+int *init_measure_links (Average *average, int Naverage, Measure *measure, int Nmeasure);
+int *init_missing_links (Average *average, int Naverage, Missing *missing, int Nmissing);
+int add_meas_link (Average *average, int *next, int Nmeasure, int NMEASURE);
+int add_miss_link (Average *average, int *next, int Nmissing);
+int *build_measure_links (Average *average, int Naverage, Measure *measure, int Nmeasure);
+Measure *sort_measure (Average *average, int Naverage, Measure *measure, int Nmeasure, int *next);
+Missing *sort_missing (Average *average, int Naverage, Missing *missing, int Nmissing, int *next_miss);
+
+/** 
+    there is an inconsistency to be resolved: fixed structures (like Image)
+    need a fixed bit-length time (e_time), but these functions all use the
+    UNIX time_t types, which may be 32 or 64 bits, depending on the machine.
+    This can be resolved by using time_t with these functions, but casting 
+    between e_time and time_t when necessary (ie, cannot return data to an
+    e_time pointer from one of these functions)
+**/
+
+/** function for client / server **/ 
+
+AddstarClientOptions args_client (int argc, char **argv, AddstarClientOptions options);
+AddstarClientOptions args_load2mass (int argc, char **argv, AddstarClientOptions options);
+AddstarClientOptions args_sedstar (int argc, char **argv, AddstarClientOptions options);
+
+void args_server (int argc, char **argv);
+
+int CheckPassword (int BindSocket);
+int NewImage (int BindSocket);
+int NewReflist (int BindSocket);
+int NewRefcat (int BindSocket);
+
+int InitServerSocket (SockAddress *Address);
+int WaitServerSocket (int InitSocket, SockAddress *Address, int *validIP, int Nvalid);
+int GetClientSocket (char *hostname);
+
+int UpdateDatabase_Image (AddstarClientOptions *options, Image *image, Coords *mosaic, Stars *stars, int Nstars);
+int UpdateDatabase_Reflist (AddstarClientOptions *options, Stars *stars, int Nstars);
+int UpdateDatabase_Refcat (AddstarClientOptions *options, SkyRegion *UserPatch, char *refcat);
+
+SkyList *SkyListForStars (SkyTable *table, int depth, Stars *stars, int Nstars);
+SkyList *SkyListExistingSubset (SkyList *input, char *path);
+int SkyListSetPath (SkyList *list, char *path);
+SkyTable *SkyTableLoadOptimal ();
+
+int InitDataset ();
+int PushDataset (DVO_DATA *data);
+DVO_DATA *PopDataset (void);
+void *ListenClients_Thread (void *data);
+int NewImage_Thread (int BindSocket);
+int NewRefcat_Thread (int BindSocket);
+int NewReflist_Thread (int BindSocket);
+
+// this is a gnu extension?? caution!
+void *memrchr(const void *s, int c, size_t n);
Index: /tags/addstar-1-7/Ohana/src/addstar/include/sedstar.h
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/include/sedstar.h	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/include/sedstar.h	(revision 9206)
@@ -0,0 +1,45 @@
+# include "addstar.h"
+# include "kapa.h"
+
+typedef enum {
+  SED_FIT,
+  SED_REQ,
+  SED_MODEL,
+  SED_SAMPLE,
+} SEDtableModes;
+
+typedef struct {
+  float *mags;
+  float color;
+  float Temp;
+  float Av;
+} SEDtableRow;
+
+typedef struct {
+  float chisq;
+  float Md;
+  int row;
+} SEDfit;
+
+typedef struct {
+  int Nfilter;
+  float *wavecode;
+  float *vegaToAB;
+  int *mode;
+  int *hashcode;
+  int *code;
+  int codeP;
+  int codeM;
+  SEDtableRow **row;
+  int Nrow;
+} SEDtable;
+
+SEDtableRow **sort_SEDtable (SEDtableRow *raw, int N);
+SEDfit SEDchisq (SEDtableRow *ref, SEDtableRow *data, SEDtableRow *error, int Nfilter);
+SEDtable *SEDtableLoad (char *filename);
+int SEDcolorBracket (SEDtable *table, float color, float delta);
+int SEDfitInit (SEDtable *table);
+int SEDfitPlot (SEDtable *table, double R, double D, SEDfit *minFit, SEDtableRow *sourceValue, SEDtableRow *sourceError);
+int SEDfitClear ();
+int SEDfitCatalog (Catalog *outcat, Catalog *incat, SEDtable *table);
+void SetLimitsRaw (float *xvec, float *yvec, int Nelements, Graphdata *graphmode);
Index: /tags/addstar-1-7/Ohana/src/addstar/src/CheckPassword.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/CheckPassword.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/CheckPassword.c	(revision 9206)
@@ -0,0 +1,22 @@
+# include "addstar.h"
+
+int CheckPassword (int BindSocket) {
+
+  IOBuffer message;
+  int status;
+
+  status = ExpectCommand (BindSocket, strlen(PASSWORD), 0.1, &message);
+  if (status != 0) {
+    if (VERBOSE) fprintf (stderr, "failed connection\n");
+    FreeIOBuffer (&message);
+    close (BindSocket);
+    return (FALSE);
+  }
+  if (strncmp (message.buffer, PASSWORD, strlen(PASSWORD))) {
+    if (VERBOSE) fprintf (stderr, "invalid password\n");
+    close (BindSocket);
+    return (FALSE);
+  }
+  
+  return (TRUE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/ConfigInit.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/ConfigInit.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/ConfigInit.c	(revision 9206)
@@ -0,0 +1,169 @@
+# include "addstar.h"
+
+void GetConfig (char *config, char *field, char *format, int N, void *ptr);
+
+AddstarClientOptions ConfigInit (int *argc, char **argv) {
+
+  char *config, *file;
+  char RadiusWord[80];
+  char PhotCodeFile[256];
+  AddstarClientOptions options;
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find configuration file %s\n", file);
+    if (file != (char *) NULL) free (file);
+    exit (1);
+  }
+  if (VERBOSE) fprintf (stderr, "loaded config file: %s\n", file);
+
+
+  /* exclude overscan region from the dB image boundaries */
+  XOVERSCAN = YOVERSCAN = 0;
+  ScanConfig (config, "XOVERSCAN",              "%d",  0, &XOVERSCAN);
+  ScanConfig (config, "YOVERSCAN",              "%d",  0, &YOVERSCAN);
+
+  /* only upload stars within region; a value of 0 means ignore the limit */
+  XMIN = XMAX = YMIN = YMAX = 0;
+  ScanConfig (config, "ADDSTAR_XMIN",           "%d",  0, &XMIN);
+  ScanConfig (config, "ADDSTAR_XMAX",           "%d",  0, &XMAX);
+  ScanConfig (config, "ADDSTAR_YMIN",           "%d",  0, &YMIN);
+  ScanConfig (config, "ADDSTAR_YMAX",           "%d",  0, &YMAX);
+
+  /* exclude stars with SN > SNLIMIT (ADDSTAR_SNLIMIT overrides old name MIN_SN_FSTAT) */
+  SNLIMIT = 0;
+  ScanConfig (config, "MIN_SN_FSTAT",           "%lf", 0, &SNLIMIT);
+  ScanConfig (config, "ADDSTAR_SNLIMIT",        "%lf", 0, &SNLIMIT);
+
+  /* used by parse_time to find time-related keywords */
+  strcpy (DateKeyword, "NONE");
+  strcpy (DateMode, "NONE");
+  strcpy (UTKeyword, "NONE");
+  strcpy (JDKeyword, "NONE");
+  strcpy (MJDKeyword, "NONE");
+  ScanConfig (config, "DATE-KEYWORD",           "%s",  0, DateKeyword);
+  ScanConfig (config, "DATE-MODE",              "%s",  0, DateMode);
+  ScanConfig (config, "UT-KEYWORD",             "%s",  0, UTKeyword);
+  ScanConfig (config, "MJD-KEYWORD",            "%s",  0, MJDKeyword);
+  ScanConfig (config, "JD-KEYWORD",             "%s",  0, JDKeyword);
+
+  ScanConfig (config, "EXPTIME-KEYWORD",        "%s",  0, ExptimeKeyword);
+  ScanConfig (config, "AIRMASS-KEYWORD",        "%s",  0, AirmassKeyword);
+  ScanConfig (config, "CCDNUM-KEYWORD",         "%s",  0, CCDNumKeyword);
+  ScanConfig (config, "ST-KEYWORD",             "%s",  0, STKeyword);
+  ScanConfig (config, "OBSERVATORY-LATITUDE",   "%lf", 0, &Latitude);
+  ScanConfig (config, "OBSERVATORY-LONGITUDE",  "%lf", 0, &Longitude);
+  ScanConfig (config, "SUBPIX_DATAFILE",        "%s",  0, SubpixDatafile);
+
+  /* instrumental magnitude range for calibration mode */
+  CAL_INSTMAG_MAX =  -9.0;
+  CAL_INSTMAG_MIN = -13.0;
+  ScanConfig (config, "CAL_INSTMAG_MAX",   "%lf", 0, &CAL_INSTMAG_MAX);
+  ScanConfig (config, "CAL_INSTMAG_MIN",   "%lf", 0, &CAL_INSTMAG_MIN);
+
+  /* location of needed data sources */
+  ScanConfig (config, "2MASS_DIR_AS",           "%s",  0, TWO_MASS_DIR_AS);
+  ScanConfig (config, "2MASS_DIR_DR2",          "%s",  0, TWO_MASS_DIR_DR2);
+  ScanConfig (config, "GSCDIR",                 "%s",  0, GSCDIR);
+
+  if (!ScanConfig (config, "USNO_A_DIR",             "%s",  0, USNO_A_DIR)) {
+    ScanConfig (config, "USNO_CDROM",             "%s",  0, USNO_A_DIR);
+  }
+  ScanConfig (config, "USNO_B_DIR",             "%s",  0, USNO_B_DIR);
+
+  ScanConfig (config, "TYCHO_DIR",             "%s",  0, TYCHO_DIR);
+
+  GetConfig (config, "GSCFILE",                "%s",  0, GSCFILE);
+  GetConfig (config, "CATDIR",                 "%s",  0, CATDIR);
+  GetConfig (config, "PHOTCODE_FILE",          "%s",  0, PhotCodeFile);
+  ScanConfig (config, "CATMODE",                "%s",  0, CATMODE);
+  ScanConfig (config, "CATFORMAT",              "%s",  0, CATFORMAT);
+  if (!ScanConfig (config, "SKY_DEPTH",         "%d",  0, &SKY_DEPTH)) {
+    SKY_DEPTH = SKY_DEPTH_HST;
+  }
+  if (!ScanConfig (config, "SKY_TABLE",         "%s",  0, SKY_TABLE)) {
+    SKY_TABLE[0] = 0;
+  }
+  sprintf (ImageCat, "%s/Images.dat", CATDIR);
+
+  /* dropped: GetConfig (config, "IMAGE_CATALOG",          "%s",  0, ImageCat); */
+
+  ScanConfig (config, "CAMERA_LAYOUT",          "%s",  0, CameraLayout);
+
+  /* used by client/server setup */
+  ScanConfig (config, "PASSWORD",               "%s",  0, PASSWORD);
+  ScanConfig (config, "HOSTNAME",               "%s",  0, HOSTNAME);
+  
+  /* load valid ip list */
+  {
+    int i, Nvalid, ip1, ip2, ip3, ip4, test, status;
+    char string[80];
+
+    Nvalid = 0;
+    NVALID = 10;
+    ALLOCATE (VALID_IP, int, NVALID);
+    for (i = 0; ScanConfig (config, "VALID_IP", "%s", i, string) != NULL; i++) {
+      status = sscanf (string, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
+      test = TRUE;
+      test &= (status == 4);
+      test &= ((ip1 > 0) && (ip1 < 256)); 
+      test &= ((ip2 > 0) && (ip2 < 256)); 
+      test &= ((ip3 > 0) && (ip3 < 256)); 
+      test &= ((ip4 >=0) && (ip4 < 256)); 
+      if (!test) {
+	fprintf (stderr, "invalid IP address %s\n", string);
+	exit (2);
+      }
+      VALID_IP[Nvalid] = ip1 | (ip2 << 8) | (ip3 << 16) | (ip4 << 24);
+      Nvalid ++;
+      CHECK_REALLOCATE (VALID_IP, int, NVALID, Nvalid, 10);
+    }
+    NVALID = Nvalid;
+    REALLOCATE (VALID_IP, int, NVALID);
+    if (NVALID == 0) {
+      free (VALID_IP);
+      VALID_IP = NULL;
+    }
+  }
+
+  /* set the default search radius */
+  if (!ScanConfig (config, "ADDSTAR_RADIUS", "%s", 0, RadiusWord)) {
+    GetConfig (config, "RADIUS", "%s", 0, RadiusWord);
+  }
+  /* XXX this does not work for refcat and reflist modes... */
+  if (!strcasecmp (RadiusWord, "header")) {
+    options.radius = 0;
+    if (!ScanConfig (config, "ADDSTAR_NSIGMA", "%lf", 0, &options.Nsigma)) {
+      GetConfig (config, "NSIGMA", "%lf", 0, &options.Nsigma);
+    }
+  } else {
+    options.radius = atof (RadiusWord);
+  }
+
+  /* default mode, format, if not specified */
+  if (*CATMODE == 0) strcpy (CATMODE, "RAW");
+  if (*CATFORMAT == 0) strcpy (CATFORMAT, "ELIXIR");
+
+  if (!LoadPhotcodes (PhotCodeFile)) {
+    fprintf (stderr, "error loading photcode file %s\n", PhotCodeFile);
+    exit (1);
+  }
+
+  free (config);
+  free (file);
+  return (options);
+}
+
+void GetConfig (char *config, char *field, char *format, int N, void *ptr) {
+
+  char *status;
+
+  status = ScanConfig (config, field, format, N, ptr);
+  if (status == NULL) {
+    fprintf (stderr, "error in config, cannot find %s\n", field);
+    exit (1);
+  }
+  return;
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/DatasetOps.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/DatasetOps.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/DatasetOps.c	(revision 9206)
@@ -0,0 +1,70 @@
+# include "addstar.h"
+# include <pthread.h>
+
+/* the init function is an alternative */
+/* pthread_mutex_init(&mutex, const pthread_mutexattr_t *mutexattr); */
+pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int Ndataset = 0;
+static int NDATASET = 0;
+static DVO_DATA **dataset = NULL;
+
+int InitDataset () {
+
+  int i;
+
+
+  Ndataset = 0;
+  NDATASET = 100;
+  ALLOCATE (dataset, DVO_DATA *, NDATASET);
+  for (i = 0; i < NDATASET; i++) {
+    dataset[i] = NULL;
+  }
+  return (TRUE);
+}
+
+/* data a set dataset to the end of the stack */
+int PushDataset (DVO_DATA *data) {
+
+  int N;
+
+  pthread_mutex_lock(&fastmutex);
+
+  N = Ndataset;
+  Ndataset ++;
+  CHECK_REALLOCATE (dataset, DVO_DATA *, NDATASET, Ndataset, 100);
+
+  dataset[N] = data;
+
+  pthread_mutex_unlock(&fastmutex);
+  return (TRUE);
+}
+
+/* remove and return first dataset */
+DVO_DATA *PopDataset (void) {
+
+  int i;
+  DVO_DATA *data;
+
+  pthread_mutex_lock(&fastmutex);
+
+  if (Ndataset == 0) {
+    pthread_mutex_unlock(&fastmutex);
+    return (NULL);
+  }
+
+  data = dataset[0];
+  
+  for (i = 0; i < Ndataset - 1; i++) {
+    dataset[i] = dataset[i+1];
+  }
+  Ndataset --;
+  if ((Ndataset < NDATASET / 2) && (Ndataset > 50)) {
+    NDATASET = Ndataset / 2;
+    REALLOCATE (dataset, DVO_DATA *, NDATASET);
+  }
+
+  pthread_mutex_unlock(&fastmutex);
+  return (data);
+}
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/ListenClients_Thread.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/ListenClients_Thread.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/ListenClients_Thread.c	(revision 9206)
@@ -0,0 +1,54 @@
+# include "addstar.h"
+
+/* wait for incoming messages from clients */
+void *ListenClients_Thread (void *data) {
+
+  int status, InitSocket, BindSocket;
+  SockAddress Address;
+  IOBuffer message;
+  
+  /* if we have multiple threads, each one creates its own socket? */
+  InitSocket = InitServerSocket (&Address);
+  
+  while (1) {
+
+    /* wait for clients to make connection */
+    BindSocket = WaitServerSocket (InitSocket, &Address, VALID_IP, NVALID);
+    if (BindSocket == -1) continue;
+
+    /* validate : wait for password */
+    if (!CheckPassword (BindSocket)) continue;
+    
+    /* accept command : XXX EAM : long-enough timeout? */
+    status = ExpectCommand (BindSocket, 5, 0.1, &message);
+    if (status != 0) {
+      if (VERBOSE) fprintf (stderr, "failed connection\n");
+      FreeIOBuffer (&message);
+      close (BindSocket);
+      continue;
+    }
+
+    /* message options */
+    if (!strcmp (message.buffer, "IMAGE")) {
+      fprintf (stderr, "Image\n");
+      NewImage_Thread (BindSocket);
+      continue;
+    }
+    if (!strcmp (message.buffer, "REFLS")) {
+      fprintf (stderr, "Reflist\n");
+      NewReflist_Thread (BindSocket);
+      continue;
+    }
+    if (!strcmp (message.buffer, "REFCT")) {
+      fprintf (stderr, "Refcat\n");
+      NewRefcat_Thread (BindSocket);
+      continue;
+    }
+    if (!strcmp (message.buffer, "EXIT")) {
+      /* need to send this signal to the main thread */
+      fprintf (stderr, "Exit\n");
+      exit (2);
+    }
+  }    
+  exit (1);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/NewImage.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/NewImage.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/NewImage.c	(revision 9206)
@@ -0,0 +1,56 @@
+# include "addstar.h"
+
+int NewImage (int BindSocket) {
+
+  int N, Nstars;
+  Stars *stars;
+  Image *image;
+  Coords *mosaic;
+  AddstarClientOptions *options;
+
+  /* accept incoming data set */
+  if (!Recv_AddstarClientOptions (BindSocket, &options, &N)) {
+    fprintf (stderr, "error: problem receiving options\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: too many option sets (%d)\n", N);
+    goto reject;
+  }
+
+  if (!Recv_Image (BindSocket, &image, &N)) {
+    fprintf (stderr, "error: problem receiving image data\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: invalid number of images (%d)\n", N);
+    goto reject;
+  }
+
+  if (options[0].mosaic) {
+    if (!Recv_Coords (BindSocket, &mosaic, &N)) {
+      fprintf (stderr, "error: problem receiving mosaic coordinates\n");
+      goto reject;
+    }
+    if (N != 1) {
+      fprintf (stderr, "error: invalid number of mosaic coords (%d)\n", N);
+      goto reject;
+    }
+  }    
+
+  if (!Recv_Stars (BindSocket, &stars, &Nstars)) {
+    fprintf (stderr, "error: problem receiving star data\n");
+    goto reject;
+  }
+  fprintf (stderr, "accepted %s, %d stars\n", image[0].name, Nstars);
+
+  /* add to db */
+  UpdateDatabase_Image (options, image, mosaic, stars, Nstars);
+
+  close (BindSocket);
+  return (TRUE);
+
+reject:
+  close (BindSocket);
+  return (FALSE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/NewImage_Thread.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/NewImage_Thread.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/NewImage_Thread.c	(revision 9206)
@@ -0,0 +1,68 @@
+# include "addstar.h"
+
+int NewImage_Thread (int BindSocket) {
+
+  int N, Nstars;
+  Stars *stars;
+  Image *image;
+  Coords *mosaic;
+  AddstarClientOptions *options;
+  DVO_DATA *dataset;
+
+  /* accept incoming data set */
+  if (!Recv_AddstarClientOptions (BindSocket, &options, &N)) {
+    fprintf (stderr, "error: problem receiving options\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: too many option sets (%d)\n", N);
+    goto reject;
+  }
+
+  if (!Recv_Image (BindSocket, &image, &N)) {
+    fprintf (stderr, "error: problem receiving image data\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: invalid number of images (%d)\n", N);
+    goto reject;
+  }
+
+  if (options[0].mosaic) {
+    if (!Recv_Coords (BindSocket, &mosaic, &N)) {
+      fprintf (stderr, "error: problem receiving mosaic coordinates\n");
+      goto reject;
+    }
+    if (N != 1) {
+      fprintf (stderr, "error: invalid number of mosaic coords (%d)\n", N);
+      goto reject;
+    }
+  }    
+
+  if (!Recv_Stars (BindSocket, &stars, &Nstars)) {
+    fprintf (stderr, "error: problem receiving star data\n");
+    goto reject;
+  }
+  fprintf (stderr, "accepted %s, %d stars\n", image[0].name, Nstars);
+
+  /* create new dataset to store the incoming data */
+  ALLOCATE (dataset, DVO_DATA, 1);
+  dataset[0].options = options;
+  dataset[0].patch   = NULL;
+  dataset[0].refcat  = NULL;
+  dataset[0].image   = image;
+  dataset[0].mosaic  = mosaic;
+  dataset[0].stars   = stars;
+  dataset[0].Nstars  = Nstars;
+
+  /* place on dataset stack */
+  PushDataset (dataset);
+
+  /* close connection, return */
+  close (BindSocket);
+  return (TRUE);
+
+reject:
+  close (BindSocket);
+  return (FALSE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/NewRefcat.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/NewRefcat.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/NewRefcat.c	(revision 9206)
@@ -0,0 +1,45 @@
+# include "addstar.h"
+
+int NewRefcat (int BindSocket) {
+
+  int N, status;
+  AddstarClientOptions *options;
+  IOBuffer message;
+  SkyRegion *patch;
+
+  /* accept incoming data set */
+  if (!Recv_AddstarClientOptions (BindSocket, &options, &N)) {
+    fprintf (stderr, "error: problem receiving options\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: too many option sets (%d)\n", N);
+    goto reject;
+  }
+
+  if (!Recv_SkyRegion (BindSocket, &patch, &N)) {
+    fprintf (stderr, "error: problem receiving patch\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: too many patches (%d)\n", N);
+    goto reject;
+  }
+
+  status = ExpectMessage (BindSocket, 0.25, &message);
+  if (status != 0) {
+    if (VERBOSE) fprintf (stderr, "failed connection\n");
+    FreeIOBuffer (&message);
+    goto reject;
+  }
+
+  /* add to db */
+  UpdateDatabase_Refcat (options, patch, message.buffer);
+
+  close (BindSocket);
+  return (TRUE);
+
+reject:
+  close (BindSocket);
+  return (FALSE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/NewRefcat_Thread.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/NewRefcat_Thread.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/NewRefcat_Thread.c	(revision 9206)
@@ -0,0 +1,59 @@
+# include "addstar.h"
+
+int NewRefcat_Thread (int BindSocket) {
+
+  int N, status;
+  AddstarClientOptions *options;
+  IOBuffer message;
+  SkyRegion *patch;
+  DVO_DATA *dataset;
+
+  /* accept incoming data set */
+  if (!Recv_AddstarClientOptions (BindSocket, &options, &N)) {
+    fprintf (stderr, "error: problem receiving options\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: too many option sets (%d)\n", N);
+    goto reject;
+  }
+
+  if (!Recv_SkyRegion (BindSocket, &patch, &N)) {
+    fprintf (stderr, "error: problem receiving patch\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: too many patches (%d)\n", N);
+    goto reject;
+  }
+
+  status = ExpectMessage (BindSocket, 0.25, &message);
+  if (status != 0) {
+    if (VERBOSE) fprintf (stderr, "failed connection\n");
+    FreeIOBuffer (&message);
+    goto reject;
+  }
+
+  /* add to db */
+  UpdateDatabase_Refcat (options, patch, message.buffer);
+
+  /* create new dataset to store the incoming data */
+  ALLOCATE (dataset, DVO_DATA, 1);
+  dataset[0].options = options;
+  dataset[0].patch   = patch;
+  dataset[0].refcat  = message.buffer;
+  dataset[0].image   = NULL;
+  dataset[0].mosaic  = NULL;
+  dataset[0].stars   = NULL;
+  dataset[0].Nstars  = 0;
+
+  /* place on dataset stack */
+  PushDataset (dataset);
+
+  close (BindSocket);
+  return (TRUE);
+
+reject:
+  close (BindSocket);
+  return (FALSE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/NewReflist.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/NewReflist.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/NewReflist.c	(revision 9206)
@@ -0,0 +1,34 @@
+# include "addstar.h"
+
+int NewReflist (int BindSocket) {
+
+  int N, Nstars;
+  Stars *stars;
+  AddstarClientOptions *options;
+
+  /* accept incoming data set */
+  if (!Recv_AddstarClientOptions (BindSocket, &options, &N)) {
+    fprintf (stderr, "error: problem receiving options\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: too many option sets (%d)\n", N);
+    goto reject;
+  }
+
+  if (!Recv_Stars (BindSocket, &stars, &Nstars)) {
+    fprintf (stderr, "error: problem receiving star data\n");
+    goto reject;
+  }
+  fprintf (stderr, "accepted %d stars\n", Nstars);
+
+  /* add to db */
+  UpdateDatabase_Reflist (options, stars, Nstars);
+
+  close (BindSocket);
+  return (TRUE);
+
+reject:
+  close (BindSocket);
+  return (FALSE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/NewReflist_Thread.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/NewReflist_Thread.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/NewReflist_Thread.c	(revision 9206)
@@ -0,0 +1,45 @@
+# include "addstar.h"
+
+int NewReflist_Thread (int BindSocket) {
+
+  int N, Nstars;
+  Stars *stars;
+  AddstarClientOptions *options;
+  DVO_DATA *dataset;
+
+  /* accept incoming data set */
+  if (!Recv_AddstarClientOptions (BindSocket, &options, &N)) {
+    fprintf (stderr, "error: problem receiving options\n");
+    goto reject;
+  }
+  if (N != 1) {
+    fprintf (stderr, "error: too many option sets (%d)\n", N);
+    goto reject;
+  }
+
+  if (!Recv_Stars (BindSocket, &stars, &Nstars)) {
+    fprintf (stderr, "error: problem receiving star data\n");
+    goto reject;
+  }
+  fprintf (stderr, "accepted %d stars\n", Nstars);
+
+  /* create new dataset to store the incoming data */
+  ALLOCATE (dataset, DVO_DATA, 1);
+  dataset[0].options = options;
+  dataset[0].patch   = NULL;
+  dataset[0].refcat  = NULL;
+  dataset[0].image   = NULL;
+  dataset[0].mosaic  = NULL;
+  dataset[0].stars   = stars;
+  dataset[0].Nstars  = Nstars;
+
+  /* place on dataset stack */
+  PushDataset (dataset);
+
+  close (BindSocket);
+  return (TRUE);
+
+reject:
+  close (BindSocket);
+  return (FALSE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/SEDfit.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/SEDfit.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/SEDfit.c	(revision 9206)
@@ -0,0 +1,225 @@
+# include "sedstar.h"
+
+// XXX a couple of fixes should speed this up a bit: test
+
+int SEDfitCatalog (Catalog *outcat, Catalog *incat, SEDtable *table) {
+  
+  int i, j, m, n, idx, start, done, row, Nsec, Nfit, Nphot;
+  int Nave, Nmeas, NAVE, NMEAS, Nmodel, Nreq;
+  unsigned short USNOred, USNOblu;
+  float color;
+  int *found, valid, *modelRow, *reqRow;
+
+  SEDtableRow sourceValue, sourceError;
+  SEDfit minFit, testFit;
+
+  Nmodel = Nreq = 0;
+  for (i = 0; i < table[0].Nfilter; i++) {
+    if (table[0].mode[i] == SED_REQ) Nreq ++;
+    if (table[0].mode[i] == SED_MODEL) Nmodel ++;
+  }
+  if (Nmodel < 1) {
+    fprintf (stderr, "no model filter defined\n!");
+    exit (2);
+  }
+  if (Nreq < 1) {
+    fprintf (stderr, "no required filter defined\n!");
+    exit (2);
+  }
+
+  ALLOCATE (modelRow, int, Nmodel);
+  for (j = i = 0; i < table[0].Nfilter; i++) {
+    if (table[0].mode[i] == SED_MODEL) { 
+      modelRow[j] = i;
+      j++;
+    }
+  }
+  ALLOCATE (reqRow, int, Nreq);
+  for (j = i = 0; i < table[0].Nfilter; i++) {
+    if (table[0].mode[i] == SED_REQ) { 
+      reqRow[j] = i;
+      j++;
+    }
+  }
+
+  sourceValue.mags = NULL;
+  sourceError.mags = NULL;
+
+  Nsec = GetPhotcodeNsecfilt ();
+  Nave = outcat[0].Naverage;
+  Nmeas = outcat[0].Nmeasure;
+
+  NAVE = 100;
+  NMEAS = 100;
+  REALLOCATE (outcat[0].average, Average, NAVE);
+  REALLOCATE (outcat[0].secfilt, SecFilt, NAVE*Nsec);
+  REALLOCATE (outcat[0].measure, Measure, NMEAS);
+
+  // artificially set USNOred and blu errors to 0.3
+  USNOred = GetPhotcodeCodebyName ("USNO_RED");
+  USNOblu = GetPhotcodeCodebyName ("USNO_BLUE");
+
+  // create holder for the source data
+  ALLOCATE (sourceValue.mags, float, table[0].Nfilter);
+  ALLOCATE (sourceError.mags, float, table[0].Nfilter);
+  ALLOCATE (found, int, table[0].Nfilter);
+
+  if (PLOT) SEDfitInit (table);
+
+  // perform the fit to all sources
+  for (i = 0; i < incat[0].Naverage; i++) {
+
+    // blank out the source array
+    for (j = 0; j < table[0].Nfilter; j++) {
+      sourceValue.mags[j] = 100;
+      found[j] = FALSE;
+    }	
+
+    // load the measurements for this source
+    m = incat[0].average[i].offset;
+    Nphot = 0;
+    for (j = 0; j < incat[0].average[i].Nm; j++) {
+      idx = table[0].hashcode[incat[0].measure[m+j].source];
+      if (idx == -1) continue;
+      // only fit the selected photcodes (mode == "fit")
+      if (table[0].mode[idx] == SED_MODEL) continue; 
+      if (table[0].mode[idx] == SED_SAMPLE) continue; 
+      // XXX do something more clever if more than one value exists per photcode
+      sourceValue.mags[idx] = incat[0].measure[m+j].M_PS + table[0].vegaToAB[idx];
+      sourceError.mags[idx] = incat[0].measure[m+j].dM_PS;
+      if (incat[0].measure[m+j].source == USNOred) sourceError.mags[idx] = 0.3;
+      if (incat[0].measure[m+j].source == USNOblu) sourceError.mags[idx] = 0.3;
+      found[idx] = TRUE;
+      Nphot ++;
+    }
+    if (Nphot < 3) continue;
+
+    // XXX pre-select list of REQ entries; loop over only those?
+    valid = TRUE;
+    for (j = 0; valid && (j < Nreq); j++) {
+      if ((table[0].mode[reqRow[j]] == SED_REQ) && !found[reqRow[j]]) valid = FALSE;
+    }
+    if (!valid) continue;
+
+    // skip sources without ref color
+    if (sourceValue.mags[table[0].codeP] > 50) continue;
+    if (sourceValue.mags[table[0].codeM] > 50) continue;
+    color = sourceValue.mags[table[0].codeP] - sourceValue.mags[table[0].codeM];
+
+    // find tableRow within 0.1 mag of color 
+    // XXX : check on the delta value
+    start = SEDcolorBracket (table, color, 0.05);
+    minFit = SEDchisq (table[0].row[start], &sourceValue, &sourceError, table[0].Nfilter);
+    minFit.row = start;
+
+    // search for min chisq backwards
+    // XXX : check on the delta value
+    done = FALSE;
+    row = start - 1;
+    while (!done && (row > 0)) {
+      testFit = SEDchisq (table[0].row[row], &sourceValue, &sourceError, table[0].Nfilter);
+      if (testFit.chisq < minFit.chisq) {
+	minFit = testFit;
+	minFit.row = row;
+      }
+      if (fabs(table[0].row[row][0].color - color) > 0.25) done = TRUE;
+      row --;
+    }
+
+    // search for min chisq forwards
+    // XXX : check on the delta value
+    done = FALSE;
+    row = start + 1;
+    while (!done && (row < table[0].Nrow)) {
+      testFit = SEDchisq (table[0].row[row], &sourceValue, &sourceError, table[0].Nfilter);
+      if (testFit.chisq < minFit.chisq) {
+	minFit = testFit;
+	minFit.row = row;
+      }
+      if (fabs(table[0].row[row][0].color - color) > 0.25) done = TRUE;
+      row ++;
+    }
+
+    Nfit ++;
+    // create the vectors for the example plots
+    if (PLOT) SEDfitPlot (table, incat[0].average[i].R, incat[0].average[i].D, &minFit, &sourceValue, &sourceError);
+
+    // construct an average object for this object
+    // XXX for now, the output objects will have limited astrometric interpretation...
+    outcat[0].average[Nave].R         = incat[0].average[i].R;
+    outcat[0].average[Nave].D         = incat[0].average[i].D;
+    outcat[0].average[Nave].dR    = 0;
+    outcat[0].average[Nave].dD    = 0;
+    outcat[0].average[Nave].uR    = 0;
+    outcat[0].average[Nave].uD    = 0;
+    outcat[0].average[Nave].duR   = 0;
+    outcat[0].average[Nave].duD   = 0;
+    outcat[0].average[Nave].P     = 0;
+    outcat[0].average[Nave].dP    = 0;
+
+    // XXX for now, set the average mag data to NULL
+    outcat[0].average[Nave].M         = NO_MAG;
+    outcat[0].average[Nave].dM        = NO_MAG;
+    outcat[0].average[Nave].Nm        = 0;
+    outcat[0].average[Nave].Nn        = 0;
+    outcat[0].average[Nave].Xp        = NO_MAG;
+    outcat[0].average[Nave].Xm        = NO_MAG;
+    outcat[0].average[Nave].Xg        = NO_MAG;
+    outcat[0].average[Nave].offset    = Nmeas;
+    outcat[0].average[Nave].missing   = -1;
+    outcat[0].average[Nave].code      = 0;
+
+    for (j = 0; j < Nsec; j++) {
+      outcat[0].secfilt[Nave*Nsec+j].M_PS  = NO_MAG;
+      outcat[0].secfilt[Nave*Nsec+j].dM_PS = NO_MAG;
+      outcat[0].secfilt[Nave*Nsec+j].Xm    = NO_MAG;
+    }
+
+    // we now have the min chisq row. use this to supply the other filter values....
+    // XXX pre-select the SED_MODEL rows...
+    if (Nmeas + table[0].Nfilter >= NMEAS) {
+	NMEAS += 100 + table[0].Nfilter;
+	REALLOCATE (outcat[0].measure, Measure, NMEAS);
+    }
+
+    for (j = 0; valid && (j < Nmodel); j++) {
+      n = modelRow[j];
+      outcat[0].measure[Nmeas].dR_PS       = 0.0;
+      outcat[0].measure[Nmeas].dD_PS       = 0.0;
+      outcat[0].measure[Nmeas].M_PS        = MIN (table[0].row[minFit.row][0].mags[n] + minFit.Md,  NO_MAG);
+      outcat[0].measure[Nmeas].dM_PS       = 0.0;
+      outcat[0].measure[Nmeas].Mcal_PS     = 0;
+      outcat[0].measure[Nmeas].t           = TIMEREF;
+      outcat[0].measure[Nmeas].averef      = Nave;
+      outcat[0].measure[Nmeas].source      = table[0].code[n];
+      outcat[0].measure[Nmeas].dophot      = 0;
+      outcat[0].measure[Nmeas].flags       = 0;
+      outcat[0].measure[Nmeas].dt_PS       = 0xffff;
+
+      outcat[0].measure[Nmeas].Mgal_PS     = NO_MAG;
+      outcat[0].measure[Nmeas].airmass_PS  = 0;
+      outcat[0].measure[Nmeas].FWx         = NO_MAG;
+      outcat[0].measure[Nmeas].FWy         = NO_ERR;
+      outcat[0].measure[Nmeas].theta       = NO_ERR;
+
+      outcat[0].average[Nave].Nm++;
+      Nmeas ++;
+    }
+
+    Nave ++;
+    if (Nave >= NAVE) {
+      NAVE += 100;
+      REALLOCATE (outcat[0].average, Average, NAVE);
+      REALLOCATE (outcat[0].secfilt, SecFilt, NAVE*Nsec);
+    }
+  }
+  outcat[0].Naverage = Nave;
+  outcat[0].Nmeasure = Nmeas;
+  
+  free (sourceValue.mags);
+  free (sourceError.mags);
+  free (found);
+
+  SEDfitClear ();
+  return (TRUE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/SEDops.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/SEDops.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/SEDops.c	(revision 9206)
@@ -0,0 +1,269 @@
+# include "sedstar.h"
+
+// fit the data (with errors) to the given table row
+SEDfit SEDchisq (SEDtableRow *ref, SEDtableRow *data, SEDtableRow *error, int Nfilter) {
+
+  int i;
+  double Sm, Sd, S2, wt, dM;
+  SEDfit fit;
+
+  Sm = Sd = S2 = 0.0;
+
+  for (i = 0; i < Nfilter; i++) {
+    if (data[0].mags[i] > 50.0) continue;
+
+    if (error[0].mags[i] == 0.0) {
+      wt = 1.0;
+    } else {
+      wt = 1.0 / SQ(error[0].mags[i]);
+    }
+
+    dM = data[0].mags[i] - ref[0].mags[i];
+    S2 += SQ(dM) * wt;
+    Sm += dM * wt;
+    Sd += wt;
+  }
+    
+  // row is assigned after fit
+  fit.row = -1;
+  fit.Md = Sm / Sd;
+  fit.chisq = S2 + SQ(fit.Md) * Sd - 2*fit.Md*Sm;
+
+  return (fit);
+}
+
+// find the first table row within 0.1 mag of the requested color (or within 10)
+int SEDcolorBracket (SEDtable *table, float color, float delta) {
+
+  int Nlo, Nhi, N;
+  float tcolor;
+
+  N = Nlo = 0; Nhi = table[0].Nrow;
+  tcolor = table[0].row[Nlo][0].color;
+  while ((Nhi - Nlo > 10) && (fabs(tcolor-color) > delta)) {
+    N = 0.5*(Nlo + Nhi);
+    N = MAX (N, 0);
+    N = MIN (N, table[0].Nrow - 1);
+    tcolor = table[0].row[N][0].color;
+    if (tcolor < color) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  return (N);
+}
+
+SEDtableRow **sort_SEDtable (SEDtableRow *raw, int N) {
+
+  int l,j,ir,i;
+  SEDtableRow **value, *temp;
+  
+  if (N <= 0) return (NULL);
+
+  ALLOCATE (value, SEDtableRow *, N);
+  for (i = 0; i < N; i++) {
+    value[i] = &raw[i];
+  }
+  if (N < 2) return (value);
+
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      temp = value[l];
+    }
+    else {
+      temp = value[ir];
+      value[ir] = value[0];
+      if (--ir == 0) {
+	value[0] = temp;
+	return (value);
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[j][0].color < value[j+1][0].color) ++j;
+      if (temp[0].color < value[j][0].color) {
+	value[i] = value[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    value[i] = temp;
+  }
+
+  return (value);
+}
+
+static Graphdata graphdata;
+static KapaSection magSection, resSection;
+static int Xgraph;
+static float *fitmags, *fiterrs;
+
+int SEDfitInit (SEDtable *table) {
+
+  Xgraph = KiiOpen ("kapa", "sedstar");
+  KapaInitGraph (&graphdata);
+  SetLimitsRaw (table[0].wavecode, NULL, table[0].Nfilter, &graphdata);
+  graphdata.style = 2;
+  graphdata.ptype = 2;
+  KapaClear (Xgraph, TRUE);
+  magSection.name = strcreate ("mag");
+  magSection.x  = 0;
+  magSection.dx = 1;
+  magSection.y  = 0.5;
+  magSection.dy = 0.5;
+  resSection.name = strcreate ("res");
+  resSection.x  = 0.0;
+  resSection.dx = 1.0;
+  resSection.y  = 0.0;
+  resSection.dy = 0.5;
+    
+  KiiResize (Xgraph, 900, 500);
+  KapaSetFont (Xgraph, "helvetica", 14);
+  ALLOCATE (fitmags, float, table[0].Nfilter);
+  ALLOCATE (fiterrs, float, table[0].Nfilter);
+  return (TRUE);
+}
+
+int SEDfitClear () {
+
+  free (fitmags);
+  free (fiterrs);
+  KiiClose (Xgraph);
+  return (TRUE);
+}
+
+int SEDfitPlot (SEDtable *table, double R, double D, SEDfit *minFit, SEDtableRow *sourceValue, SEDtableRow *sourceError) {
+
+  int j, minRow, Nfilter;
+  double X, Y;
+  char line[1024], key[20];
+
+  minRow = minFit[0].row;
+  Nfilter = table[0].Nfilter;
+
+  // we want to plot the OBSERVED magnitudes
+  for (j = 0; j < Nfilter; j++) {
+    fitmags[j] = table[0].row[minRow][0].mags[j] + minFit[0].Md;
+  }
+
+  // find plot range
+  SetLimitsRaw (NULL, fitmags, Nfilter, &graphdata);
+  SWAP (graphdata.ymin, graphdata.ymax);
+
+  KapaClear (Xgraph, TRUE);
+  KapaSetSection (Xgraph, &magSection);
+  KapaSetLimits (Xgraph, &graphdata);
+  KapaBox (Xgraph, &graphdata);
+  graphdata.color = KapaColorByName ("blue");
+  graphdata.etype = 0;
+  graphdata.ptype = 7;
+  KapaPrepPlot (Xgraph, Nfilter, &graphdata);
+  KapaPlotVector (Xgraph, Nfilter, table[0].wavecode);
+  KapaPlotVector (Xgraph, Nfilter, fitmags);
+
+  graphdata.color = KapaColorByName ("red");
+  graphdata.etype = 1;
+  graphdata.ptype = 2;
+  for (j = 0; j < Nfilter; j++) {
+    fitmags[j] = 100;
+    fiterrs[j] = 0;
+    if (sourceValue[0].mags[j] > 50) continue;
+    fitmags[j] = sourceValue[0].mags[j];
+    fiterrs[j] = sourceError[0].mags[j];
+  }
+  KapaPrepPlot (Xgraph, Nfilter, &graphdata);
+  KapaPlotVector (Xgraph, Nfilter, table[0].wavecode);
+  KapaPlotVector (Xgraph, Nfilter, fitmags);
+  KapaPlotVector (Xgraph, Nfilter, fiterrs);
+  KapaPlotVector (Xgraph, Nfilter, fiterrs);
+  KapaSendLabel (Xgraph, "model,fit (mags)", 1);
+
+  sprintf (line, "star: %10.6f %10.6f  T: %5.0fK  A_V|: %4.2f  M_D|: %5.2f  &sc&h^2|: %5.2f", 
+	   R, D, 
+	   table[0].row[minRow][0].Temp, 
+	   table[0].row[minRow][0].Av, 
+	   minFit[0].Md, minFit[0].chisq);
+  KapaSendLabel (Xgraph, line, 2);
+  KapaSendLabel (Xgraph, "model,fit (mags)", 1);
+
+  KapaSetSection (Xgraph, &resSection);
+  graphdata.ymin = -1.0;
+  graphdata.ymax = +1.0;
+  KapaSetLimits (Xgraph, &graphdata);
+  KapaBox (Xgraph, &graphdata);
+  graphdata.color = KapaColorByName ("red");
+  graphdata.etype = 1;
+
+  for (j = 0; j < Nfilter; j++) {
+    fitmags[j] = 100;
+    fiterrs[j] = 0;
+    if (sourceValue[0].mags[j] > 50) continue;
+    fitmags[j] = sourceValue[0].mags[j] - minFit[0].Md - table[0].row[minRow][0].mags[j];
+    fiterrs[j] = sourceError[0].mags[j];
+  }
+  KapaPrepPlot (Xgraph, Nfilter, &graphdata);
+  KapaPlotVector (Xgraph, Nfilter, table[0].wavecode);
+  KapaPlotVector (Xgraph, Nfilter, fitmags);
+  KapaPlotVector (Xgraph, Nfilter, fiterrs);
+  KapaPlotVector (Xgraph, Nfilter, fiterrs);
+  KapaSendLabel (Xgraph, "wavelength (nm)", 0);
+  KapaSendLabel (Xgraph, "resid (mags)", 1);
+
+  KiiCursorOn (Xgraph);
+  while (KiiCursorRead (Xgraph, &X, &Y, key)) {
+    // fprintf (stderr, "window: %f %f (%s)\n", X, Y, key);
+    if (!strcasecmp (key, "Q")) {
+      KiiCursorOff (Xgraph);
+      break;
+    }
+    if (!strcasecmp (key, "ESCAPE")) {
+      KiiCursorOff (Xgraph);
+      PLOT = FALSE;
+      return (TRUE);
+    }
+    if (!strcasecmp (key, "X")) {
+      KiiCursorOff (Xgraph);
+      Shutdown ("quitting sedstar");
+    }
+  }
+  return (TRUE);
+}
+
+void SetLimitsRaw (float *xvec, float *yvec, int Nelements, Graphdata *graphmode) {
+
+  double maxX, minX, maxY, minY, range;
+  int i;
+
+  if (xvec != NULL) {
+    maxX = minX = xvec[0];
+    for (i = 1; i < Nelements; i++) {
+      if (!finite(xvec[i])) continue;
+      maxX = MAX (maxX, xvec[i]);
+      minX = MIN (minX, xvec[i]);
+    }
+    range = maxX - minX;
+    if (range == 0) range = 0.001 * maxX;
+    if (range == 0) range = 0.001;
+    graphmode[0].xmin = minX - 0.05*range;
+    graphmode[0].xmax = maxX + 0.05*range;
+  }
+
+  if (yvec != NULL) {
+    maxY = minY = yvec[0];
+    for (i = 1; i < Nelements; i++) {
+      if (!finite(yvec[i])) continue;
+      maxY = MAX (maxY, yvec[i]);
+      minY = MIN (minY, yvec[i]);
+    }
+    range = maxY - minY;
+    if (range == 0) range = 0.0011 * maxY;
+    if (range == 0) range = 0.0011;
+    graphmode[0].ymin = minY - 0.05*range;
+    graphmode[0].ymax = maxY + 0.05*range;
+  }
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/SEDtableLoad.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/SEDtableLoad.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/SEDtableLoad.c	(revision 9206)
@@ -0,0 +1,83 @@
+# include "sedstar.h"
+
+// XXX where do the colorP and colorM codes come from?
+SEDtable *SEDtableLoad (char *filename) {
+
+  FILE *f;
+  char line[1024], name[64], mode[64];
+  char colornameP[64], colornameM[64];
+  int colorP, colorM, code;
+  int i, Nrow, NROW;
+  SEDtable *table;
+  SEDtableRow *raw;
+
+  ALLOCATE (table, SEDtable, 1);
+
+  // load SED table
+  f = fopen (filename, "r");
+  if (f == NULL) Shutdown ("failure to open SED table");
+
+
+  // XXX add error checks for header data
+  scan_line (f, line);
+  sscanf (line, "%*s %*s %d", &table[0].Nfilter);
+
+  // load SED table photcodes, generate the photcode hashtable
+  ALLOCATE (table[0].hashcode, int, 0x10000);
+  ALLOCATE (table[0].wavecode, float, table[0].Nfilter);
+  ALLOCATE (table[0].vegaToAB, float, table[0].Nfilter);
+  ALLOCATE (table[0].mode,     int,   table[0].Nfilter);
+  ALLOCATE (table[0].code,     int,   table[0].Nfilter);
+
+  for (i = 0; i < 0x10000; i++) table[0].hashcode[i] = -1;
+  for (i = 0; i < table[0].Nfilter; i++) {
+    scan_line (f, line);
+    sscanf (line, "%*s %s %f %f %s", name, &table[0].wavecode[i], &table[0].vegaToAB[i], mode);
+    code = GetPhotcodeCodebyName (name);
+    table[0].code[i] = code;
+    if (code == 0) Shutdown ("undefined photcode in SED table");
+    table[0].hashcode[code] = i;
+
+    table[0].mode[i] = -1;     
+    if (!strcasecmp(mode, "fit")) table[0].mode[i] = SED_FIT; 
+    if (!strcasecmp(mode, "req")) table[0].mode[i] = SED_REQ; 
+    if (!strcasecmp(mode, "model")) table[0].mode[i] = SED_MODEL; 
+    if (!strcasecmp(mode, "sample")) table[0].mode[i] = SED_SAMPLE; 
+    if (table[0].mode[i] == -1) Shutdown ("invalid photcode mode in SED table");
+  }
+
+  // load color key
+  scan_line (f, line);
+
+  // define the selection color codes
+  sscanf (line, "# %s - %s", colornameP, colornameM);
+  colorP = GetPhotcodeCodebyName (colornameP);
+  colorM = GetPhotcodeCodebyName (colornameM);
+  table[0].codeP = table[0].hashcode[colorP];
+  table[0].codeM = table[0].hashcode[colorM];
+  if (table[0].codeP == -1) Shutdown ("missing positive color filter");
+  if (table[0].codeM == -1) Shutdown ("missing positive color filter");
+    
+  // load the SED raw table rows
+  Nrow = 0;
+  NROW = 100;
+  ALLOCATE (raw, SEDtableRow, NROW);
+  while (scan_line(f, line) != EOF) {
+    stripwhite (line);
+    if (line[0] == '#') continue;
+    fparse (&raw[Nrow].Temp, 1, line);
+    fparse (&raw[Nrow].Av, 2, line);
+    ALLOCATE (raw[Nrow].mags, float, table[0].Nfilter);
+    for (i = 0; i < table[0].Nfilter; i++) {
+      fparse (&raw[Nrow].mags[i], i + 3, line);
+    }
+    raw[Nrow].color = raw[Nrow].mags[table[0].codeP] - raw[Nrow].mags[table[0].codeM];
+    Nrow ++;
+    CHECK_REALLOCATE (raw, SEDtableRow, NROW, Nrow, 100);
+  }      
+
+  // sort the SEDtable by the reference colors
+  table[0].row = sort_SEDtable (raw, Nrow);
+  table[0].Nrow = Nrow;
+  return (table);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/SetSignals.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/SetSignals.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/SetSignals.c	(revision 9206)
@@ -0,0 +1,118 @@
+# include "addstar.h"
+
+static int Protect = FALSE;
+static int Trapped = FALSE;
+
+void TrapSignal (int sig) {
+    fprintf (stderr, "trapped signal %d\n", sig);
+    if (sig == 11) {
+      fprintf (stderr, "seg fault\n");
+      exit (1);
+    }
+    if (Protect) {
+      Trapped = TRUE;
+      fprintf (stderr, "blocking until protected sections are clear\n");
+      return;
+    }
+    Shutdown ("halted by signal (trapped)");
+}    
+
+void SetProtect (int mode) {
+  Protect = mode;
+  if (Trapped && !Protect) Shutdown ("halted by signal (protect)");
+}
+
+int SetSignals () {
+
+  int i;
+
+  /* disable almost all signal interrupts */
+  for (i = 0; i < 36; i++) {
+    switch (i) {
+      /* can't redirect this signals */
+    case SIGKILL:    /* kill -9: cannot be caught or ignored */
+    case SIGSTOP:    /* SIGSTOP: cannot be caught or ignored */
+      /* ignore these signals */
+    case SIGCHLD:    /* child halted: ignore */
+    case SIGPWR:     /* power failure - why ignore this? */
+    case SIGWINCH:   /* window resized */
+    case SIGCONT:    /* continue - maintain this action */
+    case SIGTSTP:    /* stop signal sent from tty - why ignore? */
+    case SIGURG:     /* socket signal, ignore this */
+      break;
+      
+    default:
+      signal (i, TrapSignal);
+    }
+  }
+  return (TRUE);
+}
+/*
+
+       Signal     Value     Action   Comment
+       -------------------------------------------------------------------------
+       SIGHUP        1        A      Hangup detected on controlling terminal
+                                     or death of controlling process
+       SIGINT        2        A      Interrupt from keyboard
+       SIGQUIT       3        A      Quit from keyboard
+       SIGILL        4        A      Illegal Instruction
+       SIGABRT       6        C      Abort signal from abort(3)
+       SIGFPE        8        C      Floating point exception
+       SIGKILL       9       AEF     Kill signal
+       SIGSEGV      11        C      Invalid memory reference
+       SIGPIPE      13        A      Broken pipe: write to pipe with no readers
+       SIGALRM      14        A      Timer signal from alarm(2)
+       SIGTERM      15        A      Termination signal
+       SIGUSR1   30,10,16     A      User-defined signal 1
+       SIGUSR2   31,12,17     A      User-defined signal 2
+       SIGCHLD   20,17,18     B      Child stopped or terminated
+       SIGCONT   19,18,25            Continue if stopped
+       SIGSTOP   17,19,23    DEF     Stop process
+       SIGTSTP   18,20,24     D      Stop typed at tty
+       SIGTTIN   21,21,26     D      tty input for background process
+       SIGTTOU   22,22,27     D      tty output for background process
+
+       Next various other signals.
+
+       Signal       Value     Action   Comment
+       ---------------------------------------------------------------------
+       SIGTRAP        5         CG     Trace/breakpoint trap
+       SIGIOT         6         CG     IOT trap. A synonym for SIGABRT
+       SIGEMT       7,-,7       G
+       SIGBUS      10,7,10      AG     Bus error
+       SIGSYS      12,-,12      G      Bad argument to routine (SVID)
+       SIGSTKFLT    -,16,-      AG     Stack fault on coprocessor
+       SIGURG      16,23,21     BG     Urgent condition on socket (4.2 BSD)
+       SIGIO       23,29,22     AG     I/O now possible (4.2 BSD)
+       SIGPOLL                  AG     A synonym for SIGIO (System V)
+       SIGCLD       -,-,18      G      A synonym for SIGCHLD
+       SIGXCPU     24,24,30     AG     CPU time limit exceeded (4.2 BSD)
+       SIGXFSZ     25,25,31     AG     File size limit exceeded (4.2 BSD)
+       SIGVTALRM   26,26,28     AG     Virtual alarm clock (4.2 BSD)
+       SIGPROF     27,27,29     AG     Profile alarm clock
+       SIGPWR      29,30,19     AG     Power failure (System V)
+       SIGINFO      29,-,-      G      A synonym for SIGPWR
+       SIGLOST      -,-,-       AG     File lock lost
+       SIGWINCH    28,28,20     BG     Window resize signal (4.3 BSD, Sun)
+       SIGUNUSED    -,31,-      AG     Unused signal
+       (Here - denotes that a signal is absent; there where three values are given, the first one is usually  valid  for  alpha  and
+       sparc,  the  middle  one  for i386 and ppc, the last one for mips. Signal 29 is SIGINFO / SIGPWR on an alpha but SIGLOST on a
+       sparc.)
+
+       The letters in the "Action" column have the following meanings:
+
+       A      Default action is to terminate the process.
+
+       B      Default action is to ignore the signal.
+
+       C      Default action is to dump core.
+
+       D      Default action is to stop the process.
+
+       E      Signal cannot be caught.
+
+       F      Signal cannot be ignored.
+
+       G      Not a POSIX.1 conformant signal.
+
+*/
Index: /tags/addstar-1-7/Ohana/src/addstar/src/Shutdown.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/Shutdown.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/Shutdown.c	(revision 9206)
@@ -0,0 +1,28 @@
+# include "addstar.h"
+
+static FITS_DB *db;
+
+void set_db (FITS_DB *in) {
+  db = in;
+}
+
+/* clean up open / locked ImageCat before shutting down */
+int Shutdown (char *format, ...) {  
+  va_list argp;
+  char *formatplus;
+  
+  ALLOCATE (formatplus, char, strlen(format) + 2);
+  strcpy (formatplus, format);
+  strcat (formatplus, "\n");
+
+  va_start (argp, format);
+  vfprintf (stderr, formatplus, argp);
+  free (formatplus);
+  va_end (argp);
+
+  SetProtect (TRUE);
+  if (db != NULL) gfits_db_close (db);
+  fprintf (stderr, "ERROR: addstar halted\n");
+  exit (1);
+}
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/SkyListForStars.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/SkyListForStars.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/SkyListForStars.c	(revision 9206)
@@ -0,0 +1,57 @@
+# include "addstar.h"
+
+SkyList *SkyListForStars (SkyTable *table, int depth, Stars *stars, int Nstars) {
+  
+  int i, j, Nr, NR;
+  SkyList *here;
+  SkyList *list;
+  
+  Nr = 0;
+  NR = 10;
+  ALLOCATE (list, SkyList, 1);
+  ALLOCATE (list[0].regions,  SkyRegion *, NR);
+  ALLOCATE (list[0].filename, char *, NR);
+  list[0].Nregions = Nr;
+
+  sort_stars (stars, Nstars); /* sort by RA */
+  for (i = 0; i < Nstars; i++) {
+    if (stars[i].found) continue;
+    here = SkyRegionByPoint (table, depth, stars[i].R, stars[i].D);
+    stars[i].found = TRUE;
+    /* search forward for all contained stars */
+    for (j = i; j < Nstars; j++) {
+      if (stars[j].R >= here[0].regions[0][0].Rmax) break;
+      if (stars[j].R <  here[0].regions[0][0].Rmin) break;
+      if (stars[j].D <  here[0].regions[0][0].Dmin) continue;
+      if (stars[j].D >= here[0].regions[0][0].Dmax) continue;
+      stars[j].found = TRUE;
+    }
+    list[0].regions[Nr] = here[0].regions[0];
+    list[0].filename[Nr] = here[0].filename[0];
+    SkyListFree (here, FALSE); 
+    Nr ++;
+    if (Nr >= NR) {
+	NR += 32;
+	REALLOCATE (list[0].regions, SkyRegion *, NR);
+	REALLOCATE (list[0].filename, char *, NR);
+    }
+    list[0].Nregions = Nr;
+  }
+
+  /* reset to -1 for all stars: required start for find_match_refstars */
+  for (i = 0; i < Nstars; i++) stars[i].found = -1; 
+  return (list);
+}
+
+/* given a list of stars, find all region files which contain them 
+
+   - sort by ra
+   - loop over stars
+     - find region file which contains star
+     - go forwards until ra > Rmax
+       - mark all stars in this region file
+     
+   - use DEC band information?
+   - would like to minimize the number of disk reads
+
+*/
Index: /tags/addstar-1-7/Ohana/src/addstar/src/SkyRegionUtils.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/SkyRegionUtils.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/SkyRegionUtils.c	(revision 9206)
@@ -0,0 +1,26 @@
+# include "addstar.h"
+
+SkyList *SkyListExistingSubset (SkyList *input, char *path) {
+  
+  int i, status, Nsubset, NSUBSET;
+  SkyList *subset;
+  struct stat filestats;
+  
+  Nsubset = 0;
+  NSUBSET = 100;
+  ALLOCATE (subset, SkyList, 1);
+  ALLOCATE (subset[0].regions, SkyRegion *, NSUBSET);
+
+  /* match the basename against the GSCRegion file names */
+  for (i = 0; i < input[0].Nregions; i++) {
+    status = stat (input[0].filename[i], &filestats);
+    if ((status == -1) && (errno == ENOENT)) continue;
+    /* give an error for other conditions? */
+
+    subset[0].regions[Nsubset] = input[0].regions[i];
+    Nsubset ++;
+    CHECK_REALLOCATE (subset[0].regions, SkyRegion *, NSUBSET, Nsubset, 100);
+    subset[0].Nregions = Nsubset;
+  }
+  return (subset);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/SkyTableFromTychoIndex.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/SkyTableFromTychoIndex.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/SkyTableFromTychoIndex.c	(revision 9206)
@@ -0,0 +1,152 @@
+# include "dvo.h"
+# define NBANDS 24
+# define NDIV 4
+
+static double DecBands[] = {0.0, +7.5, +15.0, +22.5, +30.0, +37.5, +45.0, +52.5, +60.0, +67.5, +75.0, +82.5, +90.0,
+			    0.0, -7.5, -15.0, -22.5, -30.0, -37.5, -45.0, -52.5, -60.0, -67.5, -75.0, -82.5, -90.0};
+
+static char *DecNames[] = {"n0000", "n0730", "n1500", "n2230", "n3000", "n3730", "n4500", "n5230", "n6000", "n6730", "n7500", "n8230", "none",
+			   "s0000", "s0730", "s1500", "s2230", "s3000", "s3730", "s4500", "s5230", "s6000", "s6730", "s7500", "s8230", "none"};
+
+SkyTable *SkyTableFromTychoIndex (char *filename, int VERBOSE) {
+
+  int i, No, Nr, NR, Ntycho;
+  double Dmin, Dmax;
+  char line[256];
+  FILE *f;
+  SkyTable *skytable;
+  SkyRegion *regions;
+  SkyRegion *tycho;
+  
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    if (VERBOSE) fprintf (stderr, "can't find Tycho Index file %s\n", filename);
+    return (NULL);
+  }
+
+  /* load in table data */
+  ALLOCATE (tycho, SkyRegion, 10000);
+  for (i = 0; i < 10000; i++) {
+    if (scan_line (f, line) == EOF) break;
+    tycho[i].Rmin = atof (&line[15]);
+    tycho[i].Rmax = atof (&line[22]);
+    tycho[i].Dmin = atof (&line[29]);
+    tycho[i].Dmax = atof (&line[36]);
+
+    bzero (tycho[i].name, 21);
+    strncpy (tycho[i].name, line, 7);
+    tycho[i].name[7] = 0;
+  }
+  Ntycho = i;
+  fclose (f);
+
+  /* build supporting level 0 and 1 regions */
+  Nr = 0;
+  NR = 100;
+  ALLOCATE (regions, SkyRegion, 100);
+  
+  /* level 0 : full sky */
+  regions[Nr].Rmin 	=   0;
+  regions[Nr].Rmax 	= 360;
+  regions[Nr].Dmin 	= -90;
+  regions[Nr].Dmax 	= +90;
+  regions[Nr].index  	=  0;
+  regions[Nr].depth  	=  0;
+  regions[Nr].parent 	= -1;
+  regions[Nr].child  	=  TRUE;
+  regions[Nr].table  	=  FALSE;
+  bzero (regions[Nr].name, 21);
+  strcpy (regions[Nr].name, "fullsky");
+  
+  No = Nr;
+  Nr ++;
+
+  /* level 1 : add the dec bands */
+  regions[No].childS = Nr;
+  /* first north */
+  for (i = 0; i < 12; i++, Nr++) {
+    regions[Nr].Rmin   	  =   0;
+    regions[Nr].Rmax   	  = 360;
+    regions[Nr].Dmin   	  = DecBands[i];
+    regions[Nr].Dmax   	  = DecBands[i+1];
+    regions[Nr].index  	  =  i+1;
+    regions[Nr].depth  	  =  1;
+    regions[Nr].parent 	  =  0;
+    regions[Nr].child  	  =  TRUE;
+    regions[Nr].table  	  =  FALSE;
+    bzero (regions[Nr].name, 21);
+    strcpy (regions[Nr].name, DecNames[i]);
+  }
+  /* now south */
+  for (i = 0; i < 12; i++, Nr++) {
+    regions[Nr].Rmin   	  =   0;
+    regions[Nr].Rmax   	  = 360;
+    regions[Nr].Dmin   	  = DecBands[i+14];
+    regions[Nr].Dmax   	  = DecBands[i+13];
+    regions[Nr].index  	  =  i+1;
+    regions[Nr].depth  	  =  1;
+    regions[Nr].parent 	  =  0;
+    regions[Nr].child  	  =  TRUE;
+    regions[Nr].table  	  =  FALSE;
+    bzero (regions[Nr].name, 21);
+    strcpy (regions[Nr].name, DecNames[i+13]);
+  }
+  regions[No].childE = Nr;
+
+  CHECK_REALLOCATE (regions, SkyRegion, NR, Nr, 100);
+
+  /* level 2 : copy the data from the GSC Region files */
+  No = 1;
+  Dmin = regions[No].Dmin - 0.2;
+  Dmax = regions[No].Dmax + 0.2;
+  regions[No].childS = Nr;
+
+  for (i = 0; i < Ntycho; i++) {
+    /* if we are outside of current region, go to the next one */
+    if ((tycho[i].Dmin < Dmin) || (tycho[i].Dmax > Dmax)) {
+      regions[No].childE = Nr;
+
+      No++;
+      Dmin = regions[No].Dmin - 0.2;
+      Dmax = regions[No].Dmax + 0.2;
+      regions[No].childS = Nr;
+
+      if ((tycho[i].Dmin < Dmin) || (tycho[i].Dmax > Dmax)) {
+	fprintf (stderr, "ERROR: tycho index is not in order!\n");
+	exit (1);
+      }
+    }
+
+    /* set the values for this region */
+    regions[Nr].Rmin = tycho[i].Rmin;
+    regions[Nr].Rmax = tycho[i].Rmax;
+    regions[Nr].Dmin = tycho[i].Dmin;
+    regions[Nr].Dmax = tycho[i].Dmax;
+    strcpy (regions[Nr].name, tycho[i].name);
+
+    regions[Nr].index    =  Nr;
+    regions[Nr].depth    =  2;
+    regions[Nr].parent   =  No;
+    regions[Nr].child    =  FALSE;
+    regions[Nr].table    =  FALSE;
+    regions[Nr].childS   =  0;
+    regions[Nr].childE   =  0;
+
+    Nr ++;
+    CHECK_REALLOCATE (regions, SkyRegion, NR, Nr, 100);
+  }
+
+  free (tycho);
+
+  ALLOCATE (skytable, SkyTable, 1);
+  skytable[0].regions = regions;
+  skytable[0].Nregions = Nr;
+
+  ALLOCATE (skytable[0].filename, char *, skytable[0].Nregions);
+  for (i = 0; i < skytable[0].Nregions; i++) {
+    skytable[0].filename[i] = NULL;
+  }
+  if (VERBOSE) fprintf (stderr, "loaded %d tables from tycho index\n", skytable[0].Nregions);
+
+  return (skytable);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/SocketOps.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/SocketOps.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/SocketOps.c	(revision 9206)
@@ -0,0 +1,210 @@
+# include "addstar.h"
+
+# define MY_PORT 2000
+# define MY_WAIT 500
+
+int InitServerSocket (SockAddress *Address) {
+
+  int status, InitSocket, length;
+
+# if (0)
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+# endif
+  
+  Address[0].sin_family = AF_INET;
+  Address[0].sin_port   = MY_PORT;
+  Address[0].sin_addr.s_addr = INADDR_ANY; // use this line to bind any address / port?
+
+# if (0)  
+  status = inet_aton (hostip, &Address[0].sin_addr);
+  if (!status) {
+    fprintf (stderr, "invalid address\n");
+    exit (2);
+  }
+# endif
+
+  length = sizeof(Address[0]);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  fprintf (stderr, "init sock: %d, len: %d\n", InitSocket, length);
+  status = bind (InitSocket, (struct sockaddr *) Address, length);
+  if (status == -1) {
+    perror ("bind: ");
+    exit (2);
+  }
+
+  status = listen (InitSocket, 10);
+  if (status == -1) {
+    perror ("listen: ");
+    exit (2);
+  }
+
+  // if (VERBOSE) fprintf (stderr, "socket listening on %s (%s:%d)\n", host[0].h_name, hostip, MY_PORT);
+  return (InitSocket);
+}
+
+int WaitServerSocket (int InitSocket, SockAddress *Address, int *validIP, int Nvalid) {
+
+  int i, BindSocket, length;
+  SockAddress Address_in;
+  u_int32_t addr;
+
+  Address_in = Address[0];
+
+  length = sizeof(Address_in);
+
+  /* this is a blocking wait; use in a separate thread */
+  fcntl (InitSocket, F_SETFL, !O_NONBLOCK); 
+
+  fprintf (stderr, "init sock: %d, len: %d\n", InitSocket, length);
+  BindSocket = accept (InitSocket, (struct sockaddr *) &Address_in, &length);
+  fprintf (stderr, "bind sock: %d\n", BindSocket);
+  if (BindSocket == -1) {
+    perror ("accept: ");
+    exit (2);
+  }
+
+  addr = Address_in.sin_addr.s_addr;
+  if (VERBOSE) {
+    fprintf (stderr, "incoming connection from: ");
+    fprintf (stderr, " %u", (0xff & (addr >>  0)));
+    fprintf (stderr, ".%u", (0xff & (addr >>  8)));
+    fprintf (stderr, ".%u", (0xff & (addr >> 16)));
+    fprintf (stderr, ".%u", (0xff & (addr >> 24)));
+    fprintf (stderr, "\n");
+  }
+
+  if (Nvalid == 0) goto accepted;
+
+  for (i = 0; i < Nvalid; i++) {
+    /* valid IP addresses may be machines (120.90.121.142) or 
+       class C networks (120.90.121.0) */
+       
+    /* for machine, address must match */
+    if ((0xff & (validIP[i] >> 24)) != 0) {
+      if (addr == validIP[i]) goto accepted;
+    }
+
+    /* for network, lower three bytes of address must match */
+    if ((0xff & (validIP[i] >> 24)) == 0) {
+      if ((0x00ffffff & addr) == validIP[i]) goto accepted;
+    }
+  }
+
+  if (VERBOSE) fprintf (stderr, "connection rejected\n");
+  close (BindSocket);
+  return (-1);
+
+accepted:
+  if (VERBOSE) fprintf (stderr, "connection accepted\n");
+  fcntl (BindSocket, F_SETFL, O_NONBLOCK); 
+  return (BindSocket);
+}
+
+int GetClientSocket (char *hostname) {
+
+  int i, status, InitSocket, length;
+  SockAddress Address;
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "trying %s (%s:%d)...", host[0].h_name, hostip, MY_PORT);
+  }
+
+  Address.sin_family = AF_INET;
+  Address.sin_port   = MY_PORT;
+  status = inet_aton (hostip, &Address.sin_addr);
+  if (!status) {
+    fprintf (stderr, "invalid address\n");
+    exit (2);
+  }
+
+  length = sizeof(Address);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  status = connect (InitSocket, (struct sockaddr *) &Address, length);
+  if (status == -1) {
+    perror ("connect: ");
+    exit (2);
+  }
+
+  if (VERBOSE) fprintf (stderr, "connected\n");
+  fcntl (InitSocket, F_SETFL, O_NONBLOCK); 
+  return (InitSocket);
+}
+
+int InitServerSocket_Named (char *hostname, SockAddress *Address) {
+
+  int i, status, InitSocket, length;
+  struct hostent  *host;
+  char tmpline[80], hostip[80];
+
+  host = gethostbyname (hostname);
+  bzero (hostip, 80);
+  for (i = 0; i < host[0].h_length; i++) {
+    sprintf (tmpline, "%u", (0xff & host[0].h_addr[i]));
+    strcat (hostip, tmpline);
+    if (i < host[0].h_length - 1) strcat (hostip, ".");
+  }
+  
+  Address[0].sin_family = AF_INET;
+  Address[0].sin_port   = MY_PORT;
+  status = inet_aton (hostip, &Address[0].sin_addr);
+  if (!status) {
+    fprintf (stderr, "invalid address\n");
+    exit (2);
+  }
+
+  length = sizeof(Address[0]);
+
+  InitSocket = socket (PF_INET, SOCK_STREAM, 0);
+  if (InitSocket == -1) {
+    perror ("socket: ");
+    exit (2);
+  }
+
+  fprintf (stderr, "init sock: %d, len: %d\n", InitSocket, length);
+  status = bind (InitSocket, (struct sockaddr *) Address, length);
+  if (status == -1) {
+    perror ("bind: ");
+    exit (2);
+  }
+
+  status = listen (InitSocket, 10);
+  if (status == -1) {
+    perror ("listen: ");
+    exit (2);
+  }
+
+  if (VERBOSE) fprintf (stderr, "socket listening on %s (%s:%d)\n", host[0].h_name, hostip, MY_PORT);
+  return (InitSocket);
+}
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Image.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Image.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Image.c	(revision 9206)
@@ -0,0 +1,116 @@
+# include "addstar.h"
+
+int UpdateDatabase_Image (AddstarClientOptions *options, Image *image, Coords *mosaic, Stars *stars, int Nstars) {
+
+  int i, Noverlap, status;
+  Image *overlap;
+  Catalog catalog;
+  SkyList *skylist;
+
+  if (options[0].mode != M_IMAGE) {
+    fprintf (stderr, "error: expecting only IMAGE mode\n");
+    return (FALSE);
+  }
+
+  catalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+  if (options[0].update) catalog.catflags = LOAD_AVES | LOAD_MEAS_META | LOAD_MISS | LOAD_SECF;
+  
+  SetAirmassQuality (options[0].quality_airmass);
+
+  /*** find image overlaps, if needed ***/
+  Noverlap = 0;
+  overlap = NULL;
+  if (!options[0].skip_missed) { 
+    FITS_DB db;
+
+    set_db (&db);
+    status = dvo_image_lock (&db, ImageCat, 60.0, LCK_SOFT);
+    if (!status) Shutdown ("ERROR: failure to lock image catalog %s", db.filename);
+
+    /* load images / build overlap : XXX EAM : split into two functions? */
+    overlap = gimages (&db, image, mosaic, &Noverlap);
+    dvo_image_unlock (&db);
+  }
+
+  /*** update catalog: average, measure, etc ***/
+
+  /* find correpsonding regions for image */
+  RegisterMosaic (mosaic);
+  skylist = SkyListByImage (ServerSky, -1, image);
+
+  /* reduce regions to existing subset, if necessary */
+  if (options[0].only_match || options[0].existing_regions) {
+    SkyList *tmp;
+    tmp = SkyListExistingSubset (skylist, CATDIR);
+    SkyListFree (skylist, FALSE);
+    skylist = tmp;
+  }
+  if (VERBOSE) fprintf (stderr, "writing to %d regions\n", skylist[0].Nregions);
+
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    // set the parameters which guide catalog open/load/create
+    catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+    catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+    catalog.filename  = skylist[0].filename[i];
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    catalog.catflags  = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+    if (options[0].update) catalog.catflags = LOAD_AVES | LOAD_MEAS_META | LOAD_MISS | LOAD_SECF;
+
+    // an error exit status here is a significant error
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+      exit (2);
+    }
+
+    // Nave_disk == 0 implies an empty catalog file
+    // for only_match, skip empty catalogs 
+    if ((catalog.Nave_disk == 0) && options[0].only_match) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    if (options[0].closest) {
+      find_matches_closest (skylist[0].regions[i], stars, Nstars, &catalog, image, overlap, Noverlap, mosaic, options[0]);
+    } else {
+      find_matches (skylist[0].regions[i], stars, Nstars, &catalog, image, overlap, Noverlap, mosaic, options[0]);
+    }
+
+    if (!options[0].only_images) {
+      SetProtect (TRUE);
+      dvo_catalog_save (&catalog, VERBOSE);
+      SetProtect (FALSE);
+    }
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+  }
+
+  if (options[0].calibrate) { FindCalibration (image); }
+  
+  /*** load image db, save new image ***/
+  { 
+    FITS_DB db;
+
+    set_db (&db);
+
+    status = dvo_image_lock (&db, ImageCat, 60.0, LCK_XCLD);
+    if (!status) Shutdown ("ERROR: failure to lock image catalog %s", db.filename);
+
+    /* load images / build overlap : XXX EAM : split into two functions? */
+    overlap = gimages (&db, image, mosaic, &Noverlap);
+
+    if (db.dbstate == LCK_EMPTY) dvo_image_create (&db, ZeroPt);
+  
+    /* write out new image */
+    dvo_image_addrows (&db, image, 1);
+    SetProtect (TRUE);
+    dvo_image_update (&db, VERBOSE);
+    SetProtect (FALSE);
+    dvo_image_unlock (&db);
+  }
+  free (mosaic);
+  free (image);
+  free (stars);
+  return (TRUE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Refcat.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Refcat.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Refcat.c	(revision 9206)
@@ -0,0 +1,72 @@
+# include "addstar.h"
+
+int UpdateDatabase_Refcat (AddstarClientOptions *options, SkyRegion *patch, char *refcat) {
+
+  int i, Nstars, Nsubset;
+  Catalog catalog;
+  Stars *stars, **subset;
+  SkyList *skylist;
+
+  if (options[0].mode != M_REFCAT) {
+    fprintf (stderr, "error: expecting only REFCAT mode\n");
+    return (FALSE);
+  }
+
+  if (!check_dir_access (CATDIR, VERBOSE)) exit (1);
+
+  /*** update catalog: average, measure, etc ***/
+  
+  /* find correpsonding regions for image */
+  skylist = SkyListByPatch (ServerSky, -1, patch);
+
+  /* reduce regions to existing subset, if necessary */
+  if (options[0].only_match || options[0].existing_regions) {
+    SkyList *tmp;
+    tmp = SkyListExistingSubset (skylist, CATDIR);
+    SkyListFree (skylist, FALSE);
+    skylist = tmp;
+  }
+  if (VERBOSE) fprintf (stderr, "writing to %d regions\n", skylist[0].Nregions);
+
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    // set the parameters which guide catalog open/load/create
+    catalog.filename  = skylist[0].filename[i];
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+    catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+    catalog.catflags  = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+    if (options[0].update) catalog.catflags = LOAD_AVES | LOAD_MEAS_META | LOAD_MISS | LOAD_SECF;
+  
+    // an error exit status here is a significant error
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+      exit (2);
+    }
+
+    // Nave_disk == 0 implies an empty catalog file
+    // for only_match, skip empty catalogs
+    if ((catalog.Nave_disk == 0) && options[0].only_match) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    // load stars from corresponding catalog 
+    stars = grefcat (refcat, skylist[0].regions[i], options[0].photcode, &Nstars);
+
+    subset = find_subset (skylist[0].regions[i], stars, Nstars, &Nsubset);
+    find_matches_refstars (skylist[0].regions[i], subset, Nsubset, &catalog, options[0]);
+    if (Nsubset) free (subset);
+
+    if (!options[0].only_images) {
+      SetProtect (TRUE);
+      dvo_catalog_save (&catalog, VERBOSE);
+      SetProtect (FALSE);
+    }
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+    free (stars);
+  }
+  return (TRUE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Reflist.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Reflist.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/UpdateDatabase_Reflist.c	(revision 9206)
@@ -0,0 +1,69 @@
+# include "addstar.h"
+
+int UpdateDatabase_Reflist (AddstarClientOptions *options, Stars *stars, int Nstars) {
+
+  int i, Nsubset;
+  Catalog catalog;
+  Stars **subset;
+  SkyList *skylist;
+
+  if (options[0].mode != M_REFLIST) {
+    fprintf (stderr, "error: expecting only REFLIST mode\n");
+    return (FALSE);
+  }
+
+  if (!check_dir_access (CATDIR, VERBOSE)) exit (1);
+
+  /*** update catalog: average, measure, etc ***/
+  
+  /* find correpsonding regions for image */
+  skylist = SkyListForStars (ServerSky, -1, stars, Nstars);
+
+  /* reduce regions to existing subset, if necessary */
+  if (options[0].only_match || options[0].existing_regions) {
+    SkyList *tmp;
+    tmp = SkyListExistingSubset (skylist, CATDIR);
+    SkyListFree (skylist, FALSE);
+    skylist = tmp;
+  }
+  if (VERBOSE) fprintf (stderr, "writing to %d regions\n", skylist[0].Nregions);
+
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    // set the parameters which guide catalog open/load/create
+    catalog.filename  = skylist[0].filename[i];
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+    catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+    catalog.catflags  = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+    if (options[0].update) catalog.catflags = LOAD_AVES | LOAD_MEAS_META | LOAD_MISS | LOAD_SECF;
+
+    // an error exit status here is a significant error
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+      exit (2);
+    }
+
+    /* for only_match, skip empty catalogs XXX EAM : this leaves behind empty files */
+    if ((catalog.Nave_disk == 0) && options[0].only_match) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    subset = find_subset (skylist[0].regions[i], stars, Nstars, &Nsubset);
+    find_matches_refstars (skylist[0].regions[i], subset, Nsubset, &catalog, options[0]);
+    if (Nsubset) free (subset);
+
+    if (!options[0].only_images) {
+      SetProtect (TRUE);
+      dvo_catalog_save (&catalog, VERBOSE);
+      SetProtect (FALSE);
+    }
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+  }
+
+  free (stars);
+  return (TRUE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/addstar.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/addstar.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/addstar.c	(revision 9206)
@@ -0,0 +1,182 @@
+# include "addstar.h"
+
+int main (int argc, char **argv) {
+
+  int Nmatch, status;
+  int i, Nstars, Nimage, Noverlap, Nsubset;
+  unsigned long long Naverage, Nmeasure;
+  Stars *stars, **subset;
+  Image image, *imageSet, *overlap;
+  Catalog catalog;
+  FITS_DB db;
+  AddstarClientOptions options;
+
+  SkyTable *sky = NULL;
+  SkyList *skylist = NULL;
+
+  double dtime;
+  struct timeval start, stop;
+
+  gettimeofday (&start, NULL);
+
+  SetSignals ();
+  options = ConfigInit (&argc, argv);
+  options = args (argc, argv, options);
+
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  stars = NULL;
+  overlap = NULL;
+  set_db (&db);
+
+  /* we use the image table to lock db access -- perhaps this is not necessary? */
+  db.mode   = dvo_catalog_catmode (CATMODE);
+  db.format = dvo_catalog_catformat (CATFORMAT);
+  status    = dvo_image_lock (&db, ImageCat, 3600.0, LCK_XCLD);
+  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", db.filename);
+
+  switch (options.mode) {
+    case M_IMAGE:
+      stars = gstars (argv[1], &Nstars, options.photcode, &image);
+      if ((DUMP != NULL) && !strcmp (DUMP, "rawstars")) dump_rawstars (stars, Nstars);
+      RegisterMosaic (MOSAIC);
+      skylist = SkyListByImage (sky, -1, &image);
+      overlap = gimages (&db, &image, MOSAIC, &Noverlap);
+      break;
+    case M_REFLIST:
+      stars = grefstars (argv[1], options.photcode, &Nstars);
+      skylist = SkyListForStars (sky, -1, stars, Nstars);
+      break;
+    case M_RESORT:
+    case M_REFCAT:
+      skylist = SkyListByPatch (sky, -1, &UserPatch);
+      break;
+    case M_FAKEIMAGE:
+      imageSet = fakeimage (argv[1], &Nimage, options.photcode);
+      RegisterMosaic (MOSAIC);
+
+      if (db.dbstate == LCK_EMPTY) {
+	dvo_image_create (&db, ZeroPt);
+      } else {
+	if (!dvo_image_load (&db, VERBOSE, FORCE_READ)) {
+	  Shutdown ("can't read image catalog %s", db.filename);
+	}
+      }	  
+
+      dvo_image_addrows (&db, imageSet, Nimage);
+      SetProtect (TRUE);
+      dvo_image_update (&db, VERBOSE);
+      SetProtect (FALSE);
+
+      ohana_memcheck (FALSE);
+      dvo_image_unlock (&db); /* unlock? */
+
+      gettimeofday (&stop, NULL);
+      dtime = DTIME (stop, start);
+      fprintf (stderr, "SUCCESS: elapsed time %9.4f sec for fake image\n", dtime);
+      exit (0);
+  }
+  if (options.only_match || options.existing_regions) {
+    SkyList *tmp;
+    tmp = SkyListExistingSubset (skylist, CATDIR);
+    SkyListFree (skylist, FALSE);
+    skylist = tmp;
+  }
+  if (VERBOSE) fprintf (stderr, "writing to %d regions\n", skylist[0].Nregions);
+
+  /* XXX clean this up a bit : for only_image, I don't need to do this loop
+     unless we are getting the calibration. */
+  Nmatch = Naverage = Nmeasure = 0;
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    // set the parameters which guide catalog open/load/create
+    catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+    catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+    catalog.filename  = skylist[0].filename[i];
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    catalog.catflags  = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+    if (options.update) catalog.catflags = LOAD_AVES | LOAD_MEAS_META | LOAD_MISS | LOAD_SECF;
+
+    // an error exit status here is a significant error
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+      exit (2);
+    }
+    // Nave_disk == 0 implies an empty catalog file
+    // for only_match, skip empty catalogs
+    if ((catalog.Nave_disk == 0) && options.only_match) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    Naverage += catalog.Naverage;
+    Nmeasure += catalog.Nmeasure;
+
+    switch (options.mode) {
+      case M_IMAGE:
+	Nsubset = Nstars;
+	if (options.closest) {
+	  Nmatch += find_matches_closest (skylist[0].regions[i], stars, Nstars, &catalog, &image, overlap, Noverlap, MOSAIC, options);
+	} else {
+	  Nmatch += find_matches (skylist[0].regions[i], stars, Nstars, &catalog, &image, overlap, Noverlap, MOSAIC, options);
+	}
+	break;
+      case M_REFCAT:
+	stars = grefcat (argv[1], skylist[0].regions[i], options.photcode, &Nstars);
+      case M_REFLIST:
+	subset = find_subset (skylist[0].regions[i], stars, Nstars, &Nsubset);
+	Nmatch += find_matches_refstars (skylist[0].regions[i], subset, Nsubset, &catalog, options);
+	if (Nsubset) free (subset);
+	break;
+      case M_RESORT:
+	if (options.nosort == 3) catalog.sorted = FALSE;
+	resort_catalog (&catalog);
+	Nsubset = 1;
+	break;
+    }
+
+    // write out catalog, if appropriate
+    if (Nsubset && !options.only_images) {
+      SetProtect (TRUE);
+      dvo_catalog_save (&catalog, VERBOSE);
+      SetProtect (FALSE);
+    }
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+
+    if (options.mode == M_REFCAT) free (stars);
+  }
+
+  // XXX is it necessary to lock the image catalog during this entire process?
+  if (options.calibrate) { FindCalibration (&image); }
+
+  if (db.dbstate == LCK_EMPTY) {
+    if (VERBOSE) fprintf (stderr, "can't find %s, creating a new one\n", ImageCat);
+    dvo_image_create (&db, ZeroPt);
+  }
+  
+  ohana_memcheck (FALSE);
+
+  /* write out new image */
+  if (options.mode == M_IMAGE) {
+    dvo_image_addrows (&db, &image, 1);
+    SetProtect (TRUE);
+    dvo_image_update (&db, VERBOSE);
+    SetProtect (FALSE);
+  }
+  ohana_memcheck (FALSE);
+  dvo_image_unlock (&db); /* unlock? */
+
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec for %5d stars (%5d matches), %6lld average, %7lld measure\n", dtime, Nstars, Nmatch, Naverage, Nmeasure);
+  exit (0);
+}
+
+/* names:
+   catalog - existing object db table
+   regions - sky area which may or may not contain data
+   patch   - RA,DEC bounded portion of sky
+*/
Index: /tags/addstar-1-7/Ohana/src/addstar/src/addstarc.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/addstarc.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/addstarc.c	(revision 9206)
@@ -0,0 +1,58 @@
+# include "addstar.h"
+
+int main (int argc, char **argv) {
+
+  int Nstars;
+  int BindSocket;
+  AddstarClientOptions options;
+  Stars *stars;
+  Image image;
+
+  /* load config and options */
+  options = ConfigInit (&argc, argv);
+  options = args_client (argc, argv, options);
+
+  /* set up server connection */
+  BindSocket = GetClientSocket (HOSTNAME);
+  SendCommand (BindSocket, strlen(PASSWORD), PASSWORD);
+
+  /* send new data to server */
+  switch (options.mode) {
+    case M_IMAGE:
+      /* load data */
+      stars = gstars (argv[1], &Nstars, options.photcode, &image);
+
+      /* send data to server */
+      SendCommand (BindSocket, 5, "IMAGE");
+      Send_AddstarClientOptions (BindSocket, &options, 1, TRUE);
+      Send_Image (BindSocket, &image, 1, FALSE);
+      if (options.mosaic) {
+	Send_Coords (BindSocket, MOSAIC, 1, FALSE);
+      }
+      Send_Stars (BindSocket, stars, Nstars, FALSE);
+      break;
+
+    case M_REFLIST:
+      /* load data */
+      stars = grefstars (argv[1], options.photcode, &Nstars);
+      
+      /* send data to server */
+      SendCommand (BindSocket, 5, "REFLS");
+      Send_AddstarClientOptions (BindSocket, &options, 1, TRUE);
+      Send_Stars (BindSocket, stars, Nstars, FALSE);
+      break;
+
+    case M_REFCAT:
+      /* send data to server */
+      SendCommand (BindSocket, 5, "REFCT");
+      Send_AddstarClientOptions (BindSocket, &options, 1, TRUE);
+      Send_SkyRegion (BindSocket, &UserPatch, 1, TRUE);
+      SendMessage (BindSocket, argv[1]);
+      break;
+
+    default:
+      fprintf (stderr, "unknown addstar mode\n");
+      exit (1);
+  }
+  exit (0);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/addstard.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/addstard.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/addstard.c	(revision 9206)
@@ -0,0 +1,62 @@
+# include "addstar.h"
+
+int main (int argc, char **argv) {
+
+  int status, InitSocket, BindSocket;
+  SockAddress Address;
+  IOBuffer message;
+  AddstarClientOptions options;
+
+  options = ConfigInit (&argc, argv);
+  args_server (argc, argv);
+
+  /* store the sky table in a global for internal use */
+  ServerSky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (ServerSky, CATDIR, "cpt");
+
+  /* if we separate the incoming data from db update, spawn db thread here */
+
+  VERBOSE = TRUE;
+  InitSocket = InitServerSocket (&Address);
+  
+  while (1) {
+
+    /* wait for clients to make connection */
+    BindSocket = WaitServerSocket (InitSocket, &Address, VALID_IP, NVALID);
+    if (BindSocket == -1) continue;
+
+    /* validate : wait for password */
+    if (!CheckPassword (BindSocket)) continue;
+    
+    /* accept command : XXX EAM : long-enough timeout? */
+    status = ExpectCommand (BindSocket, 5, 0.1, &message);
+    if (status != 0) {
+      if (VERBOSE) fprintf (stderr, "failed connection\n");
+      FreeIOBuffer (&message);
+      close (BindSocket);
+      continue;
+    }
+
+    /* message options */
+    if (!strcmp (message.buffer, "IMAGE")) {
+      fprintf (stderr, "Image\n");
+      NewImage (BindSocket);
+      continue;
+    }
+    if (!strcmp (message.buffer, "REFLS")) {
+      fprintf (stderr, "Reflist\n");
+      NewReflist (BindSocket);
+      continue;
+    }
+    if (!strcmp (message.buffer, "REFCT")) {
+      fprintf (stderr, "Refcat\n");
+      NewRefcat (BindSocket);
+      continue;
+    }
+    if (!strcmp (message.buffer, "EXIT")) {
+      fprintf (stderr, "Exit\n");
+      exit (2);
+    }
+  }    
+  exit (1);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/addstart.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/addstart.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/addstart.c	(revision 9206)
@@ -0,0 +1,50 @@
+# include "addstar.h"
+# include <pthread.h>
+
+int main (int argc, char **argv) {
+
+  AddstarClientOptions options;
+  pthread_t thread;
+  DVO_DATA *dataset;
+
+  options = ConfigInit (&argc, argv);
+  args_server (argc, argv);
+
+  /* store the sky table in a global for internal use */
+  ServerSky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (ServerSky, CATDIR, "cpt");
+
+  VERBOSE = TRUE;
+
+  InitDataset ();
+
+  // launch thread to listen for client data
+  pthread_create (&thread, NULL, &ListenClients_Thread, NULL);
+
+  // XXX need to watch for shutdown message
+  while (1) {
+
+    dataset = PopDataset ();
+    if (dataset == NULL) {
+      usleep (50000);
+    }
+
+    switch (dataset[0].options[0].mode) {
+      case M_IMAGE:
+	UpdateDatabase_Image (dataset[0].options, dataset[0].image, dataset[0].mosaic, dataset[0].stars, dataset[0].Nstars);
+	continue;
+
+      case M_REFLIST:
+	UpdateDatabase_Reflist (dataset[0].options, dataset[0].stars, dataset[0].Nstars);
+	continue;
+
+      case M_REFCAT:
+	UpdateDatabase_Refcat (dataset[0].options, dataset[0].patch, dataset[0].refcat);
+	continue;
+
+      default:
+	fprintf (stderr, "error: unexpected dataset\n");
+    }
+  }    
+  exit (1);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/airmass.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/airmass.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/airmass.c	(revision 9206)
@@ -0,0 +1,26 @@
+# include "addstar.h"
+
+static int AirmassQuality = FALSE;
+
+void SetAirmassQuality (int quality) {
+  AirmassQuality = quality;
+}
+
+float airmass (float secz_image, double ra, double dec, double st, double latitude) {
+
+  double hour, cosz, secz;
+  double rdec, rlat;
+
+  if (!AirmassQuality) return (secz_image);
+
+  /*** make this optional? we may not have ST... ***/
+  /* ra, dec, latitude in dec deg; st in dec hours */
+
+  /* hour : hour angle in degrees */
+  rdec = RAD_DEG*dec;
+  rlat = RAD_DEG*latitude;
+  hour = 15.0*st - ra;
+  cosz = sin (rdec) * sin (rlat) + cos (rdec) * cos (RAD_DEG*hour) * cos (rlat);
+  secz = 1.000 / cosz;
+  return (secz);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/args.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/args.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/args.c	(revision 9206)
@@ -0,0 +1,340 @@
+# include "addstar.h"
+static void help (void);
+
+AddstarClientOptions args (int argc, char **argv, AddstarClientOptions options) {
+  
+  int i, N;
+  int QUALITY_AIRMASS;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  /*** check for command line options ***/
+
+  /* basic mode: image, list, refcat */
+  options.mode = M_IMAGE;
+  if ((N = get_argument (argc, argv, "-ref"))) {
+    options.mode = M_REFLIST;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-cat"))) {
+    options.mode = M_REFCAT;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-fakeimage"))) {
+    options.mode = M_FAKEIMAGE;
+    remove_argument (N, &argc, argv);
+    FAKE_RA = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    FAKE_DEC = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    FAKE_THETA = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-resort"))) {
+    options.mode = M_RESORT;
+    remove_argument (N, &argc, argv);
+  }
+
+  /*** provide additional data ***/ 
+  /* restrict to a portion of the sky? (REFCAT only) */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax = 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  } else {
+      if (options.mode == M_IMAGE) goto allow;
+      if (options.mode == M_FAKEIMAGE) goto allow;
+      if (options.mode == M_REFLIST) goto allow;
+      if (options.mode == M_REFCAT) {
+	  fprintf (stderr, "you have requested uploading from a catalog to the entire sky in one pass\n");
+      }
+      if (options.mode == M_RESORT) {
+	  fprintf (stderr, "you have requested resorting the entire sky in one pass\n");
+      }
+      fprintf (stderr, "this could be a time consuming operation.  type Ctrl-C within 5 seconds to cancel\n");
+      for (i = 5; i > 0; i--) {
+	  fprintf (stderr, "%d.. ", i);
+	  usleep (1000000);
+      }
+      fprintf (stderr, "\n");
+  }
+allow:
+  /* override any header PHOTCODE values */
+  options.photcode = 0;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    remove_argument (N, &argc, argv);
+    options.photcode = GetPhotcodeCodebyName (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-photcode"))) {
+    remove_argument (N, &argc, argv);
+    options.photcode = GetPhotcodeCodebyName (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* provide a time for dataset */
+  TIMEREF = 0; 
+  if ((N = get_argument (argc, argv, "-time"))) {
+    time_t tmp;
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tmp)) { 
+      fprintf (stderr, "syntax error in time\n");
+      exit (1);
+    }
+    TIMEREF = tmp;
+    remove_argument (N, &argc, argv);
+  }
+  /* provide a mosaic for distortion */
+  MOSAIC = NULL;
+  options.mosaic = FALSE;
+  if ((N = get_argument (argc, argv, "-mosaic"))) {
+    Header header;
+    ALLOCATE (MOSAIC, Coords, 1);
+
+    remove_argument (N, &argc, argv);
+    if (!gfits_read_header (argv[N], &header)) {
+      fprintf (stderr, "ERROR: can't read header for mosaic %s\n", argv[N]);
+      exit (1);
+    }
+    if (!GetCoords (MOSAIC, &header)) {
+      fprintf (stderr, "ERROR: no astrometric solution in header\n");
+      exit (1);
+    }
+    if (strcmp(&MOSAIC[0].ctype[4], "-DIS")) {
+      fprintf (stderr, "ERROR: not a mosaic distortion header\n");
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    gfits_free_header (&header);
+    options.mosaic = TRUE;
+  }
+  
+  /*** modify behavior ***/
+  /* only add to existing objects */
+  options.existing_regions = FALSE;
+  if ((N = get_argument (argc, argv, "-existing-regions"))) {
+    options.existing_regions = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* only add to existing objects */
+  options.only_match = FALSE;
+  if ((N = get_argument (argc, argv, "-only-match"))) {
+    options.only_match = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* don't add missed pts to Missed table (image only) */
+  options.skip_missed = FALSE;
+  if ((N = get_argument (argc, argv, "-missed"))) {
+    options.skip_missed = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* replace measurement, don't duplicate (ref/cat only) */
+  options.replace = FALSE;
+  if ((N = get_argument (argc, argv, "-replace"))) {
+    options.replace = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* use 'closest star' matching, rather than traditional method */
+  options.closest = FALSE;
+  if ((N = get_argument (argc, argv, "-closest"))) {
+    options.closest = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* don't re-sort the measure sequence */
+  options.nosort = FALSE;
+  if ((N = get_argument (argc, argv, "-nosort"))) {
+    options.nosort = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* only add new rows (-update) or re-write complete measure table (forces -nosort) */
+  options.update = FALSE;
+  if ((N = get_argument (argc, argv, "-update"))) {
+    options.update = TRUE;
+    options.nosort = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-force-sort"))) {
+    options.nosort = 3;  // temporary mode to mean 'force-sort'
+    remove_argument (N, &argc, argv);
+  }
+
+  /* only add image potion to image table */
+  options.only_images = FALSE;
+  if ((N = get_argument (argc, argv, "-image"))) {
+    options.only_images = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* apply average zpt offset calibration (image only) */
+  options.calibrate = FALSE;
+  if ((N = get_argument (argc, argv, "-cal"))) {
+    options.calibrate = TRUE;
+    remove_argument (N, &argc, argv);
+    InitCalibration (FALSE);
+  }
+  if ((N = get_argument (argc, argv, "-excal"))) {
+    options.calibrate = TRUE;
+    remove_argument (N, &argc, argv);
+    InitCalibration (FALSE);
+  }
+  if ((N = get_argument (argc, argv, "-incal"))) {
+    options.calibrate = TRUE;
+    remove_argument (N, &argc, argv);
+    InitCalibration (TRUE);
+  }
+
+  /*** optional situations ***/
+  /* choose high quality airmass vs low quality airmass (per-star vs per-image) */
+  QUALITY_AIRMASS = FALSE;
+  if ((N = get_argument (argc, argv, "-quality-airmass"))) {
+    remove_argument (N, &argc, argv);
+    QUALITY_AIRMASS = TRUE;
+  }
+  /* choose high quality airmass vs low quality airmass (per-star vs per-image) */
+  SUBPIX = FALSE;
+  if ((N = get_argument (argc, argv, "-subpix"))) {
+    remove_argument (N, &argc, argv);
+    SUBPIX = TRUE;
+  }
+  /* skyprobe means: subpix correction and quality airmass */ 
+  if ((N = get_argument (argc, argv, "-skyprobe"))) {
+    remove_argument (N, &argc, argv);
+    QUALITY_AIRMASS = TRUE;
+    SUBPIX = TRUE;
+  }
+  SetAirmassQuality (QUALITY_AIRMASS);
+  if (SUBPIX) load_subpix ();
+
+  /* define 2MASS quality flags to keep */
+  SELECT_2MASS_QUALITY = NULL;
+  if ((N = get_argument (argc, argv, "-2massquality"))) {
+    remove_argument (N, &argc, argv);
+    SELECT_2MASS_QUALITY = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* accept bad header astrometry */
+  ACCEPT_ASTROM = FALSE;
+  if ((N = get_argument (argc, argv, "-accept"))) {
+    ACCEPT_ASTROM = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-accept-astrom"))) {
+    ACCEPT_ASTROM = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* accept proper-motion data from reference */
+  ACCEPT_MOTION = FALSE;
+  if ((N = get_argument (argc, argv, "-accept-motion"))) {
+    ACCEPT_MOTION = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* force read of image database with mismatched NSTARS & size */ 
+  FORCE_READ = FALSE;
+  if ((N = get_argument (argc, argv, "-force"))) {
+    FORCE_READ = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* force read of image database with mismatched NSTARS & size */ 
+  TEXTMODE = FALSE;
+  if ((N = get_argument (argc, argv, "-textmode"))) {
+    TEXTMODE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  DUMP = NULL;
+  if ((N = get_argument (argc, argv, "-dump"))) {
+    remove_argument (N, &argc, argv);
+    DUMP = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if ((options.mode == M_RESORT) && (argc == 1)) return (options);
+  if (argc == 2) return (options);
+
+  if ((options.mode == M_REFLIST) && (options.photcode == 0)) {
+    fprintf (stderr, "photcode must be specified for -ref\n");
+    exit (2);
+  }
+
+  fprintf (stderr, "USAGE: addstar (filename)\n");
+  fprintf (stderr, "USAGE: addstar -cat (catalog)\n");
+  fprintf (stderr, "USAGE: addstar -ref (filename)\n");
+  fprintf (stderr, "USAGE: addstar -fakeimage (ra) (dec) (theta) (name)\n");
+  fprintf (stderr, "USAGE: addstar -resort (SkyRegion)\n");
+  exit (2);
+}
+
+static void help () {
+
+  fprintf (stderr, "USAGE\n");
+  fprintf (stderr, "  addstar (filename)\n");
+  fprintf (stderr, "     add specified image (cmp format) to database\n\n");
+  fprintf (stderr, "  addstar -ref (filename)");
+  fprintf (stderr, "     add ASCII data (ra dec mag dmag) to database\n\n");
+  fprintf (stderr, "  addstar -cat (catalog)");
+  fprintf (stderr, "     add data from catalog (USNO/2MASS/GSC) to database\n\n");
+  fprintf (stderr, "  addstar -resort (SkyRegion)");
+  fprintf (stderr, "     perform measure sorting for the specified catalog\n\n");
+
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -region ra ra dec dec 	  : only add data in specified region (-ref mode only)\n");
+  fprintf (stderr, "  -p (photcode)         	  : specify photcode (-ref / -cat / or override header)\n");
+  fprintf (stderr, "  -photcode (photcode)    	  : specify photcode (-ref / -cat / or override header)\n");
+  fprintf (stderr, "  -time (YYYY/MM/DD,HH:MM:SS) : specify date/time (override header)\n");
+  fprintf (stderr, "  -mosaic (filename)    	  : identify associated mosaic frame for chip image\n");
+  fprintf (stderr, "  -textmode                	  : input file is RAW TEXT table, not FITS table\n");
+  fprintf (stderr, "  -existing-regions           : only add measurements to existing catalog files\n");
+  fprintf (stderr, "  -only-match           	  : only add measurements to existing objects\n");
+  fprintf (stderr, "  -missed               	  : skipped 'missed' entries\n");
+  fprintf (stderr, "  -replace              	  : replace time/photcode measurements (no duplication)\n");
+  fprintf (stderr, "  -closest             	  : use closest-star algorith\n");
+  fprintf (stderr, "  -nosort             	  : don't re-sort the measure entries (improves speed)\n");
+  fprintf (stderr, "  -update             	  : only update the new rows (foreces -nosort)\n");
+  fprintf (stderr, "  -image                	  : only insert image data\n");
+  fprintf (stderr, "  -cal                  	  : perform zero-point calibration\n");
+  fprintf (stderr, "  -skyprobe             	  : specify skyprobe mode\n");
+  fprintf (stderr, "  -accept               	  : accept bad astrometry from header\n");
+  fprintf (stderr, "  -accept-astrom          	  : accept bad astrometry from header\n");
+  fprintf (stderr, "  -accept-motion           	  : accept proper-motion data from reference\n");
+  fprintf (stderr, "  -force                	  : force read of database with inconsistent info\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -dump (mode)          	  : output test data\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
+
+/** addstar modes:
+ 
+    addstar (image.smp)  - add cmp/smp image data to db
+    addstar -ref (file.dat) (photcode) 
+    addstar -cat (USNO/2MASS/GSC) -region (ra dec - ra dec)
+
+    -replace : ref/cat - replace existing match (photcode/time)
+    -match   : ref/cat - only add measures to existing averages
+
+    ref types: 
+    ASCII - RA,DEC,M,dM in a table
+
+    addstar 
+
+**/
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/args_client.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/args_client.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/args_client.c	(revision 9206)
@@ -0,0 +1,264 @@
+# include "addstar.h"
+static void help (void);
+
+AddstarClientOptions args_client (int argc, char **argv, AddstarClientOptions options) {
+  
+  int N;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  /*** check for command line options ***/
+
+  /* basic mode: image, list, refcat */
+  options.mode = M_IMAGE;
+  if ((N = get_argument (argc, argv, "-ref"))) {
+    options.mode = M_REFLIST;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-cat"))) {
+    options.mode = M_REFCAT;
+    remove_argument (N, &argc, argv);
+  }
+
+  /*** provide additional data ***/ 
+  /* restrict to a portion of the sky? (REFCAT only) */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax= 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* override any header PHOTCODE values */
+  options.photcode = 0;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    remove_argument (N, &argc, argv);
+    options.photcode = GetPhotcodeCodebyName (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* provide a time for dataset */
+  options.timeref = 0; 
+  if ((N = get_argument (argc, argv, "-time"))) {
+    time_t tmp;
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tmp)) { 
+      fprintf (stderr, "syntax error in time\n");
+      exit (1);
+    }
+    options.timeref = tmp;
+    remove_argument (N, &argc, argv);
+  }
+  /* provide a mosaic for distortion */
+  MOSAIC = NULL;
+  options.mosaic = FALSE;
+  if ((N = get_argument (argc, argv, "-mosaic"))) {
+    Header header;
+    ALLOCATE (MOSAIC, Coords, 1);
+
+    remove_argument (N, &argc, argv);
+    if (!gfits_read_header (argv[N], &header)) {
+      fprintf (stderr, "ERROR: can't read header for mosaic %s\n", argv[N]);
+      exit (1);
+    }
+    if (!GetCoords (MOSAIC, &header)) {
+      fprintf (stderr, "ERROR: no astrometric solution in header\n");
+      exit (1);
+    }
+    if (strcmp(&MOSAIC[0].ctype[4], "-DIS")) {
+      fprintf (stderr, "ERROR: not a mosaic distortion header\n");
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    gfits_free_header (&header);
+    options.mosaic = TRUE;
+  }
+  
+  /*** modify behavior ***/
+  /* only add to existing objects */
+  options.existing_regions = FALSE;
+  if ((N = get_argument (argc, argv, "-existing-regions"))) {
+    options.existing_regions = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* only add to existing objects */
+  options.only_match = FALSE;
+  if ((N = get_argument (argc, argv, "-only-match"))) {
+    options.only_match = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* don't add missed pts to Missed table (image only) */
+  options.skip_missed = FALSE;
+  if ((N = get_argument (argc, argv, "-missed"))) {
+    options.skip_missed = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* replace measurement, don't duplicate (ref/cat only) */
+  options.replace = FALSE;
+  if ((N = get_argument (argc, argv, "-replace"))) {
+    options.replace = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* use 'closest star' matching, rather than traditional method */
+  options.closest = FALSE;
+  if ((N = get_argument (argc, argv, "-closest"))) {
+    options.closest = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* don't re-sort the measure sequence */
+  options.nosort = FALSE;
+  if ((N = get_argument (argc, argv, "-nosort"))) {
+    options.nosort = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* only add new rows (-update) or re-write complete measure table (forces -nosort) */
+  options.update = FALSE;
+  if ((N = get_argument (argc, argv, "-update"))) {
+    options.update = TRUE;
+    options.nosort = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* only add image potion to image table */
+  options.only_images = FALSE;
+  if ((N = get_argument (argc, argv, "-image"))) {
+    options.only_images = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* apply average zpt offset calibration (image only) */
+  options.calibrate = FALSE;
+  if ((N = get_argument (argc, argv, "-cal"))) {
+    options.calibrate = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /*** optional situations ***/
+  /* choose high quality airmass vs low quality airmass (per-star vs per-image) */
+  options.quality_airmass = FALSE;
+  if ((N = get_argument (argc, argv, "-quality-airmass"))) {
+    remove_argument (N, &argc, argv);
+    options.quality_airmass = TRUE;
+  }
+  /* choose high quality airmass vs low quality airmass (per-star vs per-image) */
+  SUBPIX = FALSE;
+  if ((N = get_argument (argc, argv, "-subpix"))) {
+    remove_argument (N, &argc, argv);
+    SUBPIX = TRUE;
+  }
+  /* skyprobe means: subpix correction and quality airmass */ 
+  if ((N = get_argument (argc, argv, "-skyprobe"))) {
+    remove_argument (N, &argc, argv);
+    options.quality_airmass = TRUE;
+    SUBPIX = TRUE;
+  }
+  if (SUBPIX) load_subpix ();
+
+  /* define 2MASS quality flags to keep */
+  SELECT_2MASS_QUALITY = NULL;
+  if ((N = get_argument (argc, argv, "-2massquality"))) {
+    remove_argument (N, &argc, argv);
+    SELECT_2MASS_QUALITY = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* accept bad header astrometry */
+  ACCEPT_ASTROM = FALSE;
+  if ((N = get_argument (argc, argv, "-accept"))) {
+    ACCEPT_ASTROM = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* force read of image database with mismatched NSTARS & size */ 
+  FORCE_READ = FALSE;
+  if ((N = get_argument (argc, argv, "-force"))) {
+    FORCE_READ = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* over-ride autointerpretation of input data format */ 
+  TEXTMODE = FALSE;
+  if ((N = get_argument (argc, argv, "-textmode"))) {
+    TEXTMODE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  DUMP = NULL;
+  if ((N = get_argument (argc, argv, "-dump"))) {
+    remove_argument (N, &argc, argv);
+    DUMP = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: addstarc (filename)\n");
+    exit (2);
+  }
+  return (options);
+}
+
+static void help () {
+
+  fprintf (stderr, "USAGE\n");
+  fprintf (stderr, "  addstar (filename)\n");
+  fprintf (stderr, "     add specified image (cmp format) to database\n\n");
+  fprintf (stderr, "  addstar -ref (filename)");
+  fprintf (stderr, "     add ASCII data (ra dec mag dmag) to database\n\n");
+  fprintf (stderr, "  addstar -cat (catalog)");
+  fprintf (stderr, "     add data from catalog (USNO/2MASS/GSC) to database\n\n");
+
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -region ra ra dec dec 	  : only add data in specified region (-ref mode only)\n");
+  fprintf (stderr, "  -p (photcode)         	  : specify photcode (override header)\n");
+  fprintf (stderr, "  -time (YYYY/MM/DD,HH:MM:SS) : specify date/time (override header)\n");
+  fprintf (stderr, "  -mosaic (filename)    	  : identify associated mosaic frame for chip image\n");
+  fprintf (stderr, "  -fits                 	  : input file is FITS table, not TEXT table\n");
+  fprintf (stderr, "  -existing-regions           : only add measurements to existing catalog files\n");
+  fprintf (stderr, "  -only-match           	  : only add measurements to existing objects\n");
+  fprintf (stderr, "  -missed               	  : skipped 'missed' entries\n");
+  fprintf (stderr, "  -replace              	  : replace time/photcode measurements (no duplication)\n");
+  fprintf (stderr, "  -closest             	  : use closest-star algorith\n");
+  fprintf (stderr, "  -nosort             	  : don't re-sort the measure entries (improves speed)\n");
+  fprintf (stderr, "  -update             	  : only update the new rows (foreces -nosort)\n");
+  fprintf (stderr, "  -image                	  : only insert image data\n");
+  fprintf (stderr, "  -cal                  	  : perform zero-point calibration\n");
+  fprintf (stderr, "  -skyprobe             	  : specify skyprobe mode\n");
+  fprintf (stderr, "  -accept               	  : accept bad astrometry from header\n");
+  fprintf (stderr, "  -force                	  : force read of database with inconsistent info\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -dump (mode)          	  : output test data\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
+
+/** addstar modes:
+ 
+    addstar (image.smp)  - add cmp/smp image data to db
+    addstar -ref (file.dat) (photcode) 
+    addstar -cat (USNO/2MASS/GSC) -region (ra dec - ra dec)
+
+    -replace : ref/cat - replace existing match (photcode/time)
+    -match   : ref/cat - only add measures to existing averages
+
+    ref types: 
+    ASCII - RA,DEC,M,dM in a table
+
+    addstar 
+
+**/
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/args_load2mass.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/args_load2mass.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/args_load2mass.c	(revision 9206)
@@ -0,0 +1,110 @@
+# include "addstar.h"
+static void help (void);
+
+AddstarClientOptions args_load2mass (int argc, char **argv, AddstarClientOptions options) {
+  
+  int N;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  /*** check for command line options ***/
+
+  /* basic mode: image, list, refcat */
+  options.mode = M_REFCAT;
+
+  /*** provide additional data ***/ 
+  /* restrict to a portion of the sky? (UNUSED) */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax= 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* override any header PHOTCODE values */
+  options.photcode = 0;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    remove_argument (N, &argc, argv);
+    options.photcode = GetPhotcodeCodebyName (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  options.timeref = 0; 
+  options.mosaic = FALSE;
+  options.existing_regions = FALSE;
+  options.skip_missed = FALSE;
+  options.closest = FALSE;
+
+  /* only add to existing objects */
+  options.only_match = FALSE;
+  if ((N = get_argument (argc, argv, "-only-match"))) {
+    options.only_match = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* replace measurement, don't duplicate (ref/cat only) */
+  options.replace = FALSE;
+  if ((N = get_argument (argc, argv, "-replace"))) {
+    options.replace = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* select quality flags */
+  SELECT_2MASS_QUALITY = NULL;
+  if ((N = get_argument (argc, argv, "-2massquality"))) {
+    remove_argument (N, &argc, argv);
+    SELECT_2MASS_QUALITY = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* other defaults */
+  options.nosort = FALSE;
+  options.update = FALSE;
+  options.only_images = FALSE;
+  options.calibrate = FALSE;
+  options.quality_airmass = FALSE;
+  ACCEPT_ASTROM = FALSE;
+  FORCE_READ = FALSE;
+  TEXTMODE = FALSE;
+  SUBPIX = FALSE;
+  DUMP = NULL;
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: load2mass\n");
+    exit (2);
+  }
+  return (options);
+}
+
+static void help () {
+
+  fprintf (stderr, "USAGE\n");
+  fprintf (stderr, "  load2mass");
+  fprintf (stderr, "     add data from 2MASS catalog to fullsky\n\n");
+
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -p (photcode)         	  : specify photcode (override header)\n");
+  fprintf (stderr, "  -only-match           	  : only add measurements to existing objects\n");
+  fprintf (stderr, "  -replace              	  : replace time/photcode measurements (no duplication)\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/args_sedstar.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/args_sedstar.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/args_sedstar.c	(revision 9206)
@@ -0,0 +1,89 @@
+# include "addstar.h"
+static void help (void);
+
+AddstarClientOptions args_sedstar (int argc, char **argv, AddstarClientOptions options) {
+  
+  int N;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  /*** check for command line options ***/
+
+  /* basic mode: image, list, refcat */
+  options.mode = M_REFCAT;
+
+  /*** provide additional data ***/ 
+  /* restrict to a portion of the sky? (UNUSED) */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax= 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* extra error messages */
+  PLOT = FALSE;
+  if ((N = get_argument (argc, argv, "-plot"))) {
+    PLOT = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* other defaults */
+  options.timeref = 0; 
+  options.mosaic = FALSE;
+  options.existing_regions = FALSE;
+  options.skip_missed = FALSE;
+  options.closest = FALSE;
+  options.only_match = FALSE;
+  options.replace = FALSE;
+  options.nosort = FALSE;
+  options.update = FALSE;
+  options.only_images = FALSE;
+  options.calibrate = FALSE;
+  options.quality_airmass = FALSE;
+  ACCEPT_ASTROM = FALSE;
+  FORCE_READ = FALSE;
+  TEXTMODE = FALSE;
+  SUBPIX = FALSE;
+  DUMP = NULL;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: sedstar (sedtable) (outcatalog) [-region Rmin Rmax Dmin Dmax]\n");
+    exit (2);
+  }
+  return (options);
+}
+
+static void help () {
+
+  fprintf (stderr, "USAGE\n");
+  fprintf (stderr, "  sedstar (SEDtable)");
+  fprintf (stderr, "     fit objects to stellar SEDs\n\n");
+
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -region Rmin Rmax Dmin Dmax : sky region for analysis\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/args_server.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/args_server.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/args_server.c	(revision 9206)
@@ -0,0 +1,68 @@
+# include "addstar.h"
+static void help (void);
+
+void args_server (int argc, char **argv) {
+  
+  int N;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  /* restrict to a portion of the sky? (REFCAT only) */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax = 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  
+  /* define 2MASS quality flags to keep */
+  SELECT_2MASS_QUALITY = NULL;
+  if ((N = get_argument (argc, argv, "-2massquality"))) {
+    remove_argument (N, &argc, argv);
+    SELECT_2MASS_QUALITY = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* force read of image database with mismatched NSTARS & size */ 
+  FORCE_READ = FALSE;
+  if ((N = get_argument (argc, argv, "-force"))) {
+    FORCE_READ = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: addstard\n");
+    exit (2);
+  }
+}
+
+static void help () {
+
+  fprintf (stderr, "USAGE\n");
+  fprintf (stderr, "  addstard\n");
+  fprintf (stderr, "  -force                	  : force read of database with inconsistent info\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/build_links.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/build_links.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/build_links.c	(revision 9206)
@@ -0,0 +1,200 @@
+# include "addstar.h"
+
+/* build the initial links assuming the table is sorted, 
+   not partial, and has a correct set of average[].offset,Nm values */
+int *init_measure_links (Average *average, int Naverage, Measure *measure, int Nmeasure) {
+
+  int i, j, N;
+  int *next;
+
+  N = 0;
+
+  ALLOCATE (next, int, Nmeasure);
+  for (i = 0; i < Naverage; i++, N++) {
+    for (j = 0; j < average[i].Nm - 1; j++, N++) {
+      next[N] = N + 1;
+      if (N >= Nmeasure) {
+	fprintf (stderr, "WARNING: N out of bounds (1)\n");
+      }
+    }
+    next[N] = -1;
+    if (N >= Nmeasure) {
+      fprintf (stderr, "WARNING: N out of bounds (2)\n");
+    }
+
+    if (N >= Nmeasure) {
+      fprintf (stderr, "overflow in init_measure_links\n");
+      abort ();
+    }
+  }
+  return (next);
+}
+
+/* build the initial links assuming the table is sorted */
+int *init_missing_links (Average *average, int Naverage, Missing *missing, int Nmissing) {
+
+  int i, j, N;
+  int *next;
+
+  N = 0;
+
+  ALLOCATE (next, int, Nmissing);
+  for (i = 0; i < Naverage; i++) {
+    for (j = 0; j < average[i].Nn - 1; j++, N++) {
+      next[N] = N + 1;
+    }
+    if (average[i].Nn > 0) {
+      next[N] = -1;
+      if (N >= Nmissing) {
+	fprintf (stderr, "overflow in init_missing_links");
+	abort ();
+      }
+      N++;
+    }
+
+  }
+  return (next);
+}
+
+/* average[].offset, average[].Nm are valid within an addstar run */
+int add_meas_link (Average *average, int *next, int Nmeasure, int NMEASURE) {
+
+  int k, m;
+
+  /* if we have trouble, check validity of next[m] : m < Nmeasure */
+  m = average[0].offset;  
+
+  for (k = 0; k < average[0].Nm - 1; k++)  {
+    m = next[m];
+    if (m >= NMEASURE) {
+      fprintf (stderr, "WARNING: m out of bounds (3)\n");
+    }
+  }
+
+  /* set up references */
+  next[Nmeasure] = -1;
+  if (Nmeasure >= NMEASURE) {
+    fprintf (stderr, "WARNING: Nmeasure out of bounds (1)\n");
+  }
+
+  if (m == -1) {
+    average[0].offset = Nmeasure;
+  } else {
+    next[m] = Nmeasure;
+    if (m >= NMEASURE) {
+      fprintf (stderr, "WARNING: m out of bounds (4)\n");
+    }
+  }
+
+  return (TRUE);
+}
+
+int add_miss_link (Average *average, int *next, int Nmissing) {
+
+  int k, m;
+
+  /* there may be 0 Nmiss; this is not true for Nmeas */
+  if (average[0].Nn < 1) {
+    average[0].missing = Nmissing;
+    next[Nmissing] = -1;
+    return (TRUE);
+  }
+
+  m = average[0].missing;  
+  for (k = 0; k < average[0].Nn - 1; k++) m = next[m];
+  /* set up references */
+  next[Nmissing] = -1;
+  next[m] = Nmissing;
+  return (TRUE);
+}
+
+/* construct measure links which are valid FOR THIS LOAD
+ * - if we have a full load, we will get links which can
+ *   be used by other programs (eg, relphot, etc)
+ * - if we have a partial load, the links are only valid
+ *   for that partial load
+ */ 
+
+int *build_measure_links (Average *average, int Naverage, Measure *measure, int Nmeasure) {
+
+  int i, m, k, Nm, averef;
+  int *next;
+
+  ALLOCATE (next, int, Nmeasure);
+
+  /* reset the Nm, offset values for average */
+  for (i = 0; i < Naverage; i++) {
+    average[i].offset = -1;
+    average[i].Nm     =  0;
+  }
+
+  for (Nm = 0; Nm < Nmeasure; Nm++) {
+    averef = measure[Nm].averef;
+    m = average[averef].offset;  
+    next[Nm] = -1;
+
+    if (m == -1) { /* no links yet for source */
+      average[averef].offset = Nm;
+      average[averef].Nm     = 1;
+      continue;
+    }
+
+    for (k = 0; next[m] != -1; k++) {
+      m = next[m];
+      if (m >= Nmeasure) {
+	fprintf (stderr, "WARNING: m out of bounds (1)\n");
+      }
+    }
+
+    average[averef].Nm = k + 2;
+    next[m] = Nm;
+    if (m >= Nmeasure) {
+      fprintf (stderr, "WARNING: m out of bounds (2)\n");
+    }
+  }
+  return (next);
+}
+
+/* Missing does not carry enough information to reconstruct the links
+   we must always save the missing table, if it exists */
+
+Measure *sort_measure (Average *average, int Naverage, Measure *measure, int Nmeasure, int *next) {
+
+  int i, k, n, N;
+  Measure *tmpmeasure;
+
+  /* fix order of Measure (memory intensive, but fast) */
+  N = 0; 
+  ALLOCATE (tmpmeasure, Measure, Nmeasure);
+  for (i = 0; i < Naverage; i++) {
+    n = average[i].offset;
+    average[i].offset = N;
+    for (k = 0; k < average[i].Nm; k++, N++) {
+      tmpmeasure[N] = measure[n]; 
+      tmpmeasure[N].averef = i;
+      n = next[n];
+    }
+  }
+  free (measure);
+  return (tmpmeasure);
+}
+
+Missing *sort_missing (Average *average, int Naverage, Missing *missing, int Nmissing, int *next) {
+
+  int i, k, n, N;
+  Missing *tmpmissing;
+
+  /* fix order of Missing (memory intensive, but fast) */
+  N = 0; 
+  ALLOCATE (tmpmissing, Missing, Nmissing);
+  for (i = 0; i < Naverage; i++) {
+    n = average[i].missing;
+    average[i].missing = N;
+    for (k = 0; k < average[i].Nn; k++, N++) {
+      tmpmissing[N] = missing[n]; 
+      n = next[n];
+    }
+  }
+  free (missing);
+  return (tmpmissing);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/calibrate.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/calibrate.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/calibrate.c	(revision 9206)
@@ -0,0 +1,198 @@
+# include "addstar.h"
+
+static int InternalCal;
+static int Ncal, NCAL, *Nstar;
+static float *Mobs, *dMobs, *Mref, *dMref, *Minst;
+
+void InitCalibration (int mode) {
+
+  InternalCal = mode;
+
+  fprintf (stderr, "calibrating the image...\n");
+  Ncal = 0;
+  NCAL = 1000;
+  ALLOCATE (Mobs,  float,  NCAL);
+  ALLOCATE (dMobs, float, NCAL);
+  ALLOCATE (Mref,  float,  NCAL);
+  ALLOCATE (dMref, float,  NCAL);
+  ALLOCATE (Minst, float,  NCAL);
+  ALLOCATE (Nstar, int, NCAL);
+}
+  
+void SaveCalibration (float Mo, float dMo, float Mr, float dMr, float Mi, int N) {
+
+  Mobs[Ncal]  = Mo;
+  dMobs[Ncal] = dMo;
+  Mref[Ncal]  = Mr;
+  dMref[Ncal] = dMr;
+  Minst[Ncal] = Mi;
+  Nstar[Ncal] = N;
+  Ncal ++;
+
+  if (Ncal == NCAL) {
+    NCAL += 1000;
+    REALLOCATE (Mobs,  float, NCAL);
+    REALLOCATE (dMobs, float, NCAL);
+    REALLOCATE (Mref,  float, NCAL);
+    REALLOCATE (dMref, float, NCAL);
+    REALLOCATE (Minst, float, NCAL);
+    REALLOCATE (Nstar, int,   NCAL);
+  }
+}
+
+/* use the linked list to navigate the measures; safe for unsorted measures */
+void AddToCalibration (Average *average, Measure *measure, Measure *new, int *next, int Nstar) {
+
+  int i, j, m, found0, found1, found2;
+  float CalM0, CalM1, CalM2, dCalM;
+  float Mcal, color, factor;
+  short CalC0, CalC1, CalC2;
+
+  PhotCode *mycode;  // photcode of this measurement
+  PhotCode *incode;  // mycode.equiv (internal reference)
+  PhotCode *excode;  // incode.equiv (external reference)
+
+  found0 = found1 = found2 = FALSE;
+  CalM0 = CalM1 = CalM2 = dCalM = NO_MAG;
+
+  // we have two options here: 
+  //  - calibrate to internal system (Mcal)
+  //  - calibrate to external system (Mref)
+
+  mycode = GetPhotcodebyCode (new[0].source);
+  incode = GetPhotcodebyCode (mycode[0].equiv);
+  excode = GetPhotcodebyCode (incode[0].equiv);
+
+  if (InternalCal) {
+    CalC0 = incode[0].code;
+  } else {
+    CalC0 = excode[0].code;
+  }
+  CalC1 = mycode[0].c1;
+  CalC2 = mycode[0].c2;
+
+  m = average[0].offset;
+  for (i = 0; i < average[0].Nm; i++) {
+    if (measure[m].source == CalC0) { 
+      found0 = TRUE; 
+      CalM0  = measure[m].M_PS; 
+      dCalM  = measure[m].dM_PS; 
+    }
+    if (measure[m].source == CalC1) { 
+      found1 = TRUE; 
+      CalM1  = measure[m].M_PS; 
+    }
+    if (measure[m].source == CalC2) { 
+      found2 = TRUE; 
+      CalM2  = measure[m].M_PS; 
+    }
+    if (found0 && found1 && found2) {
+      Mcal   = new[0].M_PS + 0.001*mycode[0].C + mycode[0].K*(new[0].airmass_PS - 1.0) - ZeroPt;
+      color  = CalM1 - CalM2 - 0.001*mycode[0].dX;
+      factor = color;
+      for (j = 0; j < mycode[0].Nc; j++) {
+	Mcal += mycode[0].X[j]*factor;
+	factor *= color;
+      }
+      if (!InternalCal) {
+	Mcal += 0.001*incode[0].C;
+      }
+      // if we want to apply a Mcal -> Mref color correction, we need the additional color term
+      SaveCalibration (Mcal, new[0].dM_PS, CalM0, dCalM, new[0].M_PS - ZeroPt - new[0].dt_PS, Nstar);
+      return;
+    }
+    m = next[m];
+  }
+  return;
+}
+
+void FindCalibration (Image *image) {
+
+  int i, MaxN, *Nlist, Nkeep;
+  float N, M1, M2, *Dmag, *dDmag;
+  float dMo, dMr, Mw, Dmed, W1, W2, NSigma;
+
+  /* reject multiple matched-stars */
+  /* find maximum value of Nstar[] */
+  MaxN = -1;
+  for (i = 0; i < Ncal; i++) {
+    MaxN = MAX (Nstar[i], MaxN);
+  }
+  if (MaxN == -1) {
+    fprintf (stderr, "no clean stars\n");
+    image[0].Mcal_PS = 10.000;
+    image[0].dMcal_PS = 10.000;
+    return;
+  }
+  /* create a hash array from Nstar[] entries */
+  ALLOCATE (Nlist, int, MaxN + 1);
+  bzero (Nlist, MAX (0, MaxN*sizeof(int)));
+  for (i = 0; i < Ncal; i++) {
+    Nlist[Nstar[i]] ++;
+  }
+  
+  /* accumulate delta mags */
+  ALLOCATE (Dmag, float, Ncal);
+  ALLOCATE (dDmag, float, Ncal);
+  Nkeep = 0;
+  for (i = 0; i < Ncal; i++) {
+    /* if this entry has too many (or two few?) matches, skip it */
+    if (Nlist[Nstar[i]] != 1) continue;
+
+    /* clip by instrumental magnitude */
+    if (Minst[i] > CAL_INSTMAG_MAX) continue;
+    if (Minst[i] < CAL_INSTMAG_MIN) continue;
+    
+    /* XXX EAM: note the artificial 0.005 dmag here */
+    dMr = MAX (0.005, dMref[i]);
+    dMo = MAX (0.005, dMobs[i]);
+
+    Dmag[Nkeep] = (Mobs[i] - Mref[i]);
+    dDmag[Nkeep] = (dMr*dMr + dMo*dMo);
+    Nkeep ++;
+  }
+
+  if (Nkeep < 5) {
+    fprintf (stderr, "too few stars\n");
+    image[0].Mcal_PS = 10.000;
+    image[0].dMcal_PS = 10.000;
+    return;
+  }
+  fsort2 (Dmag, dDmag, Nkeep);
+
+  /* take sort list of Dmag, find median */
+  Dmed = Dmag[(int)(0.5*Nkeep)];
+
+  /* exclude points with abs(Dmag - Dmed) / dDmag > 2.5 */
+
+  /* accumulate delta mags (25% - 75% of clipped range) */
+  W1 = 0.0;
+  W2 = 0.0;
+  M1 = 0.0;
+  M2 = 0.0;
+  N  = 0.0;
+  for (i = 0; i < Nkeep; i++) {
+    NSigma = fabs (Dmag[i] - Dmed) / sqrt (dDmag[i]);
+    if (NSigma > 2.5) continue;
+    W1 += Dmag[i] / dDmag[i];
+    W2 += 1 / dDmag[i];
+    M1 += Dmag[i];
+    M2 += SQ (Dmag[i]);
+    N  += 1.0; 
+  }
+
+  if (N > 1) {
+    M1 = M1 / N;
+    M2 = sqrt (fabs(M2/N - M1*M1));
+    Mw = W1 / W2;
+    fprintf (stderr, "N: %.0f, mean: %f, wt mean: %f, stdev: %f, precision: %f\n", N, M1, Mw, M2, M2 / sqrt (N));
+    image[0].Mcal_PS = M1;
+    image[0].dMcal_PS = M2 / sqrt (N);
+    image[0].Mxxxx = N;
+  } else {
+    fprintf (stderr, "too few stars\n");
+    image[0].Mcal_PS = 10.000;
+    image[0].dMcal_PS = 10.000;
+    image[0].Mxxxx = 0;
+  }
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/dump.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/dump.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/dump.c	(revision 9206)
@@ -0,0 +1,21 @@
+# include "addstar.h"
+
+int dump_rawstars (Stars *stars, int Nstars) {
+
+  int i;
+  FILE *f;
+
+  f = fopen ("stars.dat", "w");
+
+  for (i = 0; i < Nstars; i++) {
+    fprintf (f, "%4d  %10.6f %10.6f  %8.2f %8.2f  %7.2f %7.2f\n", 
+	     i, 
+	     stars[i].R, stars[i].D,
+	     stars[i].X, stars[i].Y,
+	     stars[i].M, stars[i].dM);
+  }
+
+  fclose (f);
+  exit (1);
+}
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/edge_check.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/edge_check.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/edge_check.c	(revision 9206)
@@ -0,0 +1,36 @@
+# include "addstar.h"
+
+int edge_check (double *x1, double *y1, double *x2, double *y2) {
+
+  double theta1, theta2;
+  double Theta1, Theta2;
+
+  theta1 = opening_angle (x1[0], y1[0], x2[0], y2[0], x1[1], y1[1]); 
+  theta2 = opening_angle (x1[0], y1[0], x2[0], y2[0], x2[1], y2[1]); 
+
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  Theta1 = theta1;
+  Theta2 = theta2;
+  theta1 = opening_angle (x2[0], y2[0], x1[1], y1[1], x2[1], y2[1]); 
+  theta2 = opening_angle (x2[0], y2[0], x1[1], y1[1], x1[0], y1[0]); 
+  
+ 
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/fakeimage.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/fakeimage.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/fakeimage.c	(revision 9206)
@@ -0,0 +1,196 @@
+# include "addstar.h"
+
+Image *fakeimage (char *rootname, int *Nimage, int photcode) {
+
+  int i, j, Nx, Ny, Nchips;
+  double pltscale, pixscale;
+  double Rmin, Rmax, Dmin, Dmax;
+  // double Xmin, Xmax, Ymin, Ymax;
+  double dX, dY, r, d;
+  char chipname[80], chipdata[256], name[80];
+  char *config;
+  Image *image;
+
+  /* this is a somewhat bogus method to set a time for the exposure */
+  struct timeval now;
+  long int seedval;
+
+  gettimeofday (&now, NULL);
+  seedval = now.tv_sec + now.tv_usec;
+  srand48(seedval);
+
+  e_time MosaicTime = 0xffffffff * drand48();
+  fprintf (stderr, "time: %x\n", MosaicTime);
+
+  /* load in the camera layout file */
+  config = LoadConfigFile (CameraLayout);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find camera layout file %s\n", CameraLayout);
+    exit (1);
+  }
+  if (VERBOSE) fprintf (stderr, "loaded camera layout file: %s\n", CameraLayout);
+
+  /* create a mosaic distortion structure */
+  ALLOCATE (MOSAIC, Coords, 1);
+  strcpy (MOSAIC[0].ctype, "RA---DIS");
+  MOSAIC[0].crval1 = FAKE_RA;
+  MOSAIC[0].crval2 = FAKE_DEC;
+  
+  MOSAIC[0].crpix1 = MOSAIC[0].crpix2 = 0.0;
+  
+  /* mosaic 'pixels' are millimeters */
+  ScanConfig (config, "PLATE_SCALE",   "%lf", 0, &pltscale);
+  MOSAIC[0].cdelt1 = MOSAIC[0].cdelt2 = pltscale / 3600.0;
+
+  MOSAIC[0].pc1_1 =  cos(FAKE_THETA*RAD_DEG);
+  MOSAIC[0].pc1_2 = -sin(FAKE_THETA*RAD_DEG);
+  MOSAIC[0].pc2_1 =  sin(FAKE_THETA*RAD_DEG);
+  MOSAIC[0].pc2_2 =  cos(FAKE_THETA*RAD_DEG);
+
+  MOSAIC[0].Npolyterms = 3;
+  for (i = 0; i < 7; i++) {
+    MOSAIC[0].polyterms[i][0] = 0;
+    MOSAIC[0].polyterms[i][1] = 0;
+  }
+  ScanConfig (config, "DPLATE_X",   "%lf", 0, &pltscale);
+  MOSAIC[0].polyterms[3][0] = pltscale;  // L : X^3 Y^0
+  MOSAIC[0].polyterms[5][0] = pltscale;  // L : X^1 Y^2
+  ScanConfig (config, "DPLATE_Y",   "%lf", 0, &pltscale);
+  MOSAIC[0].polyterms[4][1] = pltscale;  // M : X^0 Y^0
+  MOSAIC[0].polyterms[6][1] = pltscale;  // M : X^2 Y^0
+
+  /* some basic data about the chisp */
+  ScanConfig (config, "NCHIPS", "%d", 0, &Nchips);
+  ScanConfig (config, "NAXIS1", "%d", 0, &Nx);
+  ScanConfig (config, "NAXIS2", "%d", 0, &Ny);
+  ScanConfig (config, "PIXEL_SCALE", "%lf", 0, &pixscale);
+
+  ALLOCATE (image, Image, Nchips + 1);
+  
+  Rmin = Rmax = Dmin = Dmax = 0;
+
+  /* define the chip images (1 - Nchips) */
+  for (i = 0; i < Nchips; i++) {
+    /* this is the addstar name for the chip in the camera */
+    sprintf (chipname, "CHIP.%03d", i);
+    ScanConfig (config, chipname, "%s", 0, chipdata);
+
+    sscanf (chipdata, "%s %lf %lf", chipname, &dX, &dY);
+    // if (VERBOSE) fprintf (stderr, "chip %s (%f,%f)\n", chipname, dX, dY);
+
+    /* this is the camera-specific name of a chip */
+    sprintf (name, "%s.%s", rootname, chipname);
+    strcpy (image[i+1].name, name);
+
+    strcpy (image[i+1].coords.ctype, "RA---WRP");
+    
+    image[i+1].coords.crval1 = dX*pixscale;
+    image[i+1].coords.crval2 = dY*pixscale;
+    
+    image[i+1].coords.crpix1 = image[i+1].coords.crpix2 = 0.0;
+    image[i+1].coords.cdelt1 = image[i+1].coords.cdelt2 = pixscale;
+
+    image[i+1].coords.pc1_1 = 1.0;
+    image[i+1].coords.pc1_2 = 0.0;
+    image[i+1].coords.pc2_1 = 0.0;
+    image[i+1].coords.pc2_2 = 1.0;
+
+    image[i+1].coords.Npolyterms = 0;
+    for (j = 0; j < 7; j++) {
+      image[i+1].coords.polyterms[j][0] = 0;
+      image[i+1].coords.polyterms[j][1] = 0;
+    }
+
+    image[i+1].sidtime  = 0.0;
+    image[i+1].latitude = 0.0;
+
+    image[i+1].cerror = 0.0;
+    
+    image[i+1].NX = Nx;
+    image[i+1].NY = Ny;
+
+    image[i+1].source = photcode;
+
+    image[i+1].exptime = 0.0;
+  
+    image[i+1].apmifit_PS = 0.0;
+    image[i+1].dapmifit_PS = 0.0;
+
+    image[i+1].detection_limit = 0.0;
+    image[i+1].saturation_limit = 0.0;
+    image[i+1].fwhm_x = 0.0;
+    image[i+1].fwhm_y = 0.0;
+    image[i+1].tzero = MosaicTime;
+    image[i+1].trate = 0;
+    image[i+1].secz_PS = 1.0;
+    image[i+1].ccdnum = 0xff;
+
+    image[i+1].Mcal_PS = 0.0;
+    image[i+1].Xm   = NO_MAG;
+    image[i+1].code = 0;
+    bzero (image[i+1].dummy, sizeof(image[i+1].dummy));
+
+    image[i+1].nstar = 0;
+    image[i+1].Myyyy = 0;
+
+    /* check if chip hits outer bounds of mosaic */
+    XY_to_RD (&r, &d, 0, 0, &image[i+1].coords);
+    Rmin = MIN (Rmin, r);
+    Rmax = MAX (Rmax, r);
+    Dmin = MIN (Dmin, d);
+    Dmax = MAX (Dmax, d);
+    XY_to_RD (&r, &d, Nx, 0, &image[i+1].coords);
+    Rmin = MIN (Rmin, r);
+    Rmax = MAX (Rmax, r);
+    Dmin = MIN (Dmin, d);
+    Dmax = MAX (Dmax, d);
+    XY_to_RD (&r, &d, 0, Ny, &image[i+1].coords);
+    Rmin = MIN (Rmin, r);
+    Rmax = MAX (Rmax, r);
+    Dmin = MIN (Dmin, d);
+    Dmax = MAX (Dmax, d);
+    XY_to_RD (&r, &d, Nx, Ny, &image[i+1].coords);
+    Rmin = MIN (Rmin, r);
+    Rmax = MAX (Rmax, r);
+    Dmin = MIN (Dmin, d);
+    Dmax = MAX (Dmax, d);
+  }
+
+  /* define the mosaic image */
+  strcpy (image[0].name, rootname);
+
+  image[0].coords = MOSAIC[0];
+  strcpy (image[0].coords.ctype, MOSAIC[0].ctype);
+
+  image[0].sidtime  = 0.0;
+  image[0].latitude = 0.0;
+  image[0].cerror = 0.0;
+    
+  // RD_to_XY (&Xmax, &Ymax, Rmax, Dmax, MOSAIC);
+  // RD_to_XY (&Xmin, &Ymin, Rmin, Dmin, MOSAIC);
+  image[0].NX = Rmax - Rmin;
+  image[0].NY = Dmax - Dmin;
+
+  image[0].source = photcode;
+
+  image[0].exptime = 0.0;
+  image[0].apmifit_PS = 0.0;
+  image[0].dapmifit_PS = 0.0;
+  image[0].detection_limit = 0.0;
+  image[0].saturation_limit = 0.0;
+  image[0].fwhm_x = 0.0;
+  image[0].fwhm_y = 0.0;
+  image[0].tzero = MosaicTime;
+  image[0].trate = 0;
+  image[0].secz_PS = 1.0;
+  image[0].ccdnum = 0xff;
+  image[0].Mcal_PS = 0.0;
+  image[0].Xm   = NO_MAG;
+  image[0].code = 0;
+  bzero (image[0].dummy, sizeof(image[0].dummy));
+  image[0].nstar = 0;
+  image[0].Myyyy = 0;
+
+  *Nimage = Nchips + 1;
+  return (image);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/find_matches.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/find_matches.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/find_matches.c	(revision 9206)
@@ -0,0 +1,405 @@
+# include "addstar.h"
+
+int find_matches (SkyRegion *region, Stars *stars, int NstarsIn, Catalog *catalog, Image *image, Image *overlap, int Noverlap, Coords *mosaic, AddstarClientOptions options) {
+
+  int i, j, n, N, J, status, Nstars;
+  double X, Y, RADIUS, RADIUS2, secz;
+  float *X1, *Y1, *X2, *Y2;
+  float dX, dY, dR;
+  int *N1, *N2,  *next_meas, *next_miss;
+  int Nave, NAVE, Nmeas, NMEAS, Nmiss, NMISS, Nmatch;
+  int Nsecfilt, Nsec;
+  float Mcat, *Mval, MTIME;
+  PhotCode *code;
+  Coords tcoords;
+
+  /* XXX EAM : options.photcode overridden by image.source.... */
+  code = GetPhotcodebyCode (image[0].source);
+
+  /* photcode data - must by of type DEP, (PRI, SEC) - probably should restrict to DEP */
+  // XXX : rely on catalog[0].Nsecfilt or GetPhotcodeNsecfilt??
+  Nsecfilt = GetPhotcodeNsecfilt ();
+  Nsec = (code[0].type == PHOT_DEP) ? GetPhotcodeNsec (code[0].equiv) : GetPhotcodeNsec (code[0].code);
+  /* this function requires incoming stars to have the same photcode */
+
+  /** allocate local arrays (stars) **/
+  ALLOCATE (X1, float, NstarsIn);
+  ALLOCATE (Y1, float, NstarsIn);
+  ALLOCATE (N1, int,   NstarsIn);
+
+  /** allocate local arrays (catalog) **/
+  NAVE = Nave = catalog[0].Naverage;
+  ALLOCATE (X2, float, NAVE);
+  ALLOCATE (Y2, float, NAVE);
+  ALLOCATE (N2, int,   NAVE);
+  ALLOCATE (catalog[0].found, int, NAVE);
+  /* for secfilt j and star i, secfilt[i*Nsecfilt+j] */
+
+  /* internal counters */
+  Nmatch = 0;
+  NMEAS = Nmeas = catalog[0].Nmeasure;
+  NMISS = Nmiss = catalog[0].Nmissing;
+  
+  /* project onto rectilinear grid with 1 arcsec pixels. the choice of ZEA projection has the
+     advantage that every point in R,D has a mapping to a unique X,Y.  However, note that not all
+     possible X,Y points map back to R,D and the local plate scale changes substantially far from
+     the projection pole.  a better mapping might be ARC, not yet implemented (see
+     coordops.update.c).  We keep the original crpix1,2 and crref1,2.  For mosaic astrometry, the
+     grid should be w.r.t. the tangent-plane, not chip coords */
+
+  if (!strcmp (&image[0].coords.ctype[4], "-WRP")) {
+    tcoords = mosaic[0];
+    tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+    tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+    tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+    tcoords.Npolyterms = 1;
+    strcpy (tcoords.ctype, "RA---ZEA");
+  } else {
+    tcoords = image[0].coords;
+    tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+    tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+    tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+    tcoords.Npolyterms = 1;
+    strcpy (tcoords.ctype, "RA---ZEA");
+  }
+
+  /* build spatial index (RA sort) */
+  Nstars = 0;
+  for (i = 0; i < NstarsIn; i++) {
+    status = fRD_to_XY (&X1[Nstars], &Y1[Nstars], stars[i].R, stars[i].D, &tcoords);
+    if (!status) continue;
+    N1[Nstars] = i;
+    Nstars ++;
+  }
+  if (Nstars < 1) {
+    if (VERBOSE) fprintf (stderr, "skipping %s, no overlapping stars\n", catalog[0].filename);
+    free (catalog[0].found);
+    free (X1);
+    free (Y1);
+    free (N1);
+    free (X2);
+    free (Y2);
+    free (N2);
+    return;
+  }
+  if (Nstars > 1) sort_lists (X1, Y1, N1, Nstars);
+  
+  /* build spatial index (RA sort) */
+  for (i = 0; i < Nave; i++) {
+    fRD_to_XY (&X2[i], &Y2[i], catalog[0].average[i].R, catalog[0].average[i].D, &tcoords);
+    N2[i] = i;
+    catalog[0].found[N2[i]] = -1;
+  }
+  if (Nave > 1) sort_lists (X2, Y2, N2, Nave);
+
+  /* set up pointers for linked list of measure, missing */
+  if (catalog[0].sorted) {
+    next_meas = init_measure_links (catalog[0].average, Nave, catalog[0].measure, Nmeas);
+  } else {
+    next_meas = build_measure_links (catalog[0].average, Nave, catalog[0].measure, Nmeas);
+  }    
+  next_miss = init_missing_links (catalog[0].average, Nave, catalog[0].missing, Nmiss);
+  /* missing MUST be written 'sorted', or not at all */
+
+  /* choose a radius for matches */
+  if (options.radius == 0) {
+    RADIUS = options.Nsigma * 0.02 * image[0].cerror;  /* 0.02 corrects cerror to arcsec from storage units */
+  } else {
+    RADIUS = options.radius; /* provided by config */
+  }
+  RADIUS2 = RADIUS*RADIUS;
+
+  /* correct instrumental mags for exposure time */
+  MTIME = (image[0].exptime > 0) ? 2.500*log10(image[0].exptime) : 0.0;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nstars) && (j < Nave); ) {
+    
+    /* negative dX: j is too large */
+    dX = X1[i] - X2[j];
+    if (dX <= -2*RADIUS) {
+      i++;
+      continue;
+    }
+    /* positive dX, i is too large */
+    if (dX >= 2*RADIUS) {
+      j++;
+      continue;
+    }
+
+    /* within match range; look for matches */
+    for (J = j; (dX > -2*RADIUS) && (J < Nave); J++) {
+      dX = X1[i] - X2[J];
+      dY = Y1[i] - Y2[J];
+      dR = dX*dX + dY*dY;
+      if (dR > RADIUS2) continue;
+
+      /* make sure there is space for next entry */
+      if (Nmeas >= NMEAS) {
+	NMEAS = Nmeas + 1000;
+	REALLOCATE (next_meas, int, NMEAS);
+	REALLOCATE (catalog[0].measure, Measure, NMEAS);
+      }
+
+      Nmatch ++;
+      n = N2[J];
+      N = N1[i];
+
+      /* add to end of measurement list */
+      add_meas_link (&catalog[0].average[n], next_meas, Nmeas, NMEAS);
+
+      /* calculate accurate per-star airmass */
+      secz = airmass (image[0].secz_PS, stars[N].R, stars[N].D, image[0].sidtime, image[0].latitude);
+      
+      /** add measurements for this star **/
+      /** dR,dD now represent arcsec **/
+      catalog[0].measure[Nmeas].dR_PS       = 3600.0*(catalog[0].average[n].R - stars[N].R);
+      if (catalog[0].measure[Nmeas].dR_PS > +180.0*3600.0) {
+	  // average on high end of boundary, move star up
+	  stars[N].R += 360.0;
+	  catalog[0].measure[Nmeas].dR_PS = 3600.0*(catalog[0].average[n].R - stars[N].R);
+      }
+      if (catalog[0].measure[Nmeas].dR_PS < -180.0*3600.0) {
+	  // average on low end of boundary, move star down
+	  stars[N].R -= 360.0;
+	  catalog[0].measure[Nmeas].dR_PS = 3600.0*(catalog[0].average[n].R - stars[N].R);
+      }
+      if (fabs(catalog[0].measure[Nmeas].dR_PS) > 10*RADIUS) {
+	  fprintf (stderr, "error: %10.6f,%10.6f vs %10.6f,%10.6f (%f,%f vs %f,%f)\n", 
+		   catalog[0].average[n].R, catalog[0].average[n].D, 
+		   stars[N].R, stars[N].D,
+		   X1[i], X2[J], 
+		   Y1[i], Y2[J]);
+      }
+      catalog[0].measure[Nmeas].dD_PS       = 3600.0*(catalog[0].average[n].D - stars[N].D);
+      catalog[0].measure[Nmeas].M_PS        = MIN (stars[N].M + MTIME, NO_MAG);
+      catalog[0].measure[Nmeas].dM_PS       = MIN (stars[N].dM, NO_ERR);  /* error in input files stored in thousandths of mag */
+      catalog[0].measure[Nmeas].Mcal_PS     = image[0].Mcal_PS;
+      catalog[0].measure[Nmeas].t           = image[0].tzero + 1e-4*stars[N].Y*image[0].trate;  /* trate is in 0.1 msec / row */
+      catalog[0].measure[Nmeas].averef      = n;              /* this must be an absolute sequence number, if partial average is loaded */
+      catalog[0].measure[Nmeas].source      = stars[N].code;  /* photcode */
+      catalog[0].measure[Nmeas].dophot      = stars[N].dophot;  
+      catalog[0].measure[Nmeas].flags       = 0;
+      catalog[0].measure[Nmeas].dt_PS       = MTIME;
+      catalog[0].measure[Nmeas].airmass_PS  = secz;
+
+      catalog[0].measure[Nmeas].Mgal_PS     = MIN (stars[N].Mgal + MTIME, NO_MAG);
+      catalog[0].measure[Nmeas].FWx         = MIN (100*stars[N].fx, NO_MAG);
+      catalog[0].measure[Nmeas].FWy         = MIN (100*stars[N].fy, NO_MAG);
+      catalog[0].measure[Nmeas].theta       = MIN ((255/360)*stars[N].df, NO_ERR);
+	
+      /* it is not valid to pass PRI/SEC/REF photcodes to this routine */
+      /* check for entries in the secfilt lists */
+      Mcat = PhotCat (&catalog[0].measure[Nmeas]);
+      Mval = (Nsec == -1) ? &catalog[0].average[n].M : &catalog[0].secfilt[n*Nsecfilt+Nsec].M_PS;
+      if (*Mval == NO_MAG) *Mval = Mcat;
+      /* in UPDATE mode, this value is not saved; use relphot to recalculate */
+
+      /* adds the measurement to the calibration if appropriate color terms are found */
+      if (options.calibrate) {
+	AddToCalibration (&catalog[0].average[n], catalog[0].measure, &catalog[0].measure[Nmeas], next_meas, N);
+      }
+
+      /*** flag multiple stars */
+      /* this image star matches more than one catalog star */
+      if (stars[N].found > -1) {
+	catalog[0].measure[stars[N].found].flags |= BLEND_IMAGE;
+	catalog[0].measure[Nmeas].flags |= BLEND_IMAGE;
+      } 
+      if (stars[N].found == -2) { /* this image star matches a catalog star on a neighboring catalog */
+	catalog[0].measure[Nmeas].flags |= BLEND_IMAGE_NEIGHBOR;
+      } 
+      if (stars[N].found == -1) { /* this image star matches only this catalog star */
+	stars[N].found = Nmeas;  /* save first match, in case coincidences are found */
+      }
+      /* this catalog star matches more than one image star */
+      if (catalog[0].found[n] > -1) {
+	catalog[0].measure[catalog[0].found[n]].flags |= BLEND_CATALOG;
+	catalog[0].measure[Nmeas].flags |= BLEND_CATALOG;
+      } else {
+	catalog[0].found[n] = Nmeas;
+      }
+      /* Nm is updated, but not written out in -update mode (for existing entries)
+	 Nm is recalculated in build_meas_links if loaded table is not sorted */
+      catalog[0].average[n].Nm ++;
+      Nmeas ++;
+
+      if (!options.update) {
+	/* in UPDATE mode, newly calculated coordinates are not saved */
+	update_coords (&catalog[0].average[n], &catalog[0].measure[0], next_meas);
+      }
+    }
+    i++;
+  }
+
+  /* add reference for undetected catalog stars */
+  if (!strcmp (&image[0].coords.ctype[4], "-WRP")) RegisterMosaic (mosaic);
+  for (j = 0; (j < Nave) && !options.skip_missed; j++) {
+    n = N2[j];
+    if (catalog[0].found[n] < 0) { 
+      /* make sure there is space for next entry */
+      if (Nmiss >= NMISS) {
+	NMISS = Nmiss + 1000;
+	REALLOCATE (next_miss, int, NMISS);
+	REALLOCATE (catalog[0].missing, Missing, NMISS);
+      }
+
+      /* should the catalog star be on this image? project into image coords */
+      if (!in_image (catalog[0].average[n].R, catalog[0].average[n].D, image)) continue;
+      add_miss_link (&catalog[0].average[n], next_miss, Nmiss);
+
+      /* calculate time of exposure for this coordinate in the image */
+      RD_to_XY (&X, &Y, catalog[0].average[n].R, catalog[0].average[n].D, &image[0].coords);	  
+      catalog[0].missing[Nmiss].t  = image[0].tzero + 1e-4*Y*image[0].trate;  /* trate is in 0.1 msec / row */
+      catalog[0].average[n].Nn ++;
+      Nmiss ++;
+    }
+  }
+
+  /* incorporate unmatched image stars, if this star is in field of this catalog */
+  /* these new entries are all written out in UPDATE mode */ 
+  for (i = 0; (i < Nstars) && !options.only_match; i++) {
+    /* make sure there is space for next entry */
+    if (Nmeas >= NMEAS) {
+      NMEAS = Nmeas + 1000;
+      REALLOCATE (next_meas, int, NMEAS);
+      REALLOCATE (catalog[0].measure, Measure, NMEAS);
+    }
+    if (Nave >= NAVE) {
+      NAVE = Nave + 1000;
+      REALLOCATE (catalog[0].average, Average, NAVE);
+      REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*catalog[0].Nsecfilt);
+    }
+
+    N = N1[i];
+    if (stars[N].found >= 0) continue;
+    if (!IN_CATALOG (stars[N].R, stars[N].D)) continue;
+
+    secz = airmass (image[0].secz_PS, stars[N].R, stars[N].D, image[0].sidtime, image[0].latitude);
+
+    catalog[0].average[Nave].R         = stars[N].R;
+    catalog[0].average[Nave].D         = stars[N].D;
+    catalog[0].average[Nave].M         = NO_MAG;
+    catalog[0].average[Nave].dM        = NO_MAG;
+    catalog[0].average[Nave].Nm        = 1;
+    catalog[0].average[Nave].Nn        = 0;
+    catalog[0].average[Nave].Xp        = NO_MAG;
+    catalog[0].average[Nave].Xm        = NO_MAG;
+    catalog[0].average[Nave].Xg        = NO_MAG;
+    catalog[0].average[Nave].offset    = Nmeas;
+    catalog[0].average[Nave].missing   = -1;
+    catalog[0].average[Nave].code      = 0;
+
+    catalog[0].average[Nave].dR        = 0;
+    catalog[0].average[Nave].dD        = 0;
+    catalog[0].average[Nave].uR        = 0;
+    catalog[0].average[Nave].uD        = 0;
+    catalog[0].average[Nave].duR       = 0;
+    catalog[0].average[Nave].duD       = 0;
+    catalog[0].average[Nave].P         = 0;
+    catalog[0].average[Nave].dP        = 0;
+
+    for (j = 0; j < Nsecfilt; j++) {
+      catalog[0].secfilt[Nave*Nsecfilt+j].M_PS  = NO_MAG;
+      catalog[0].secfilt[Nave*Nsecfilt+j].dM_PS = NO_MAG;
+      catalog[0].secfilt[Nave*Nsecfilt+j].Xm    = NO_MAG;
+    }
+
+    catalog[0].measure[Nmeas].dR_PS       = 0.0;
+    catalog[0].measure[Nmeas].dD_PS       = 0.0;
+    catalog[0].measure[Nmeas].M_PS        = MIN (stars[N].M + MTIME, NO_MAG);
+    catalog[0].measure[Nmeas].dM_PS       = MIN (stars[N].dM, NO_ERR);
+    catalog[0].measure[Nmeas].Mcal_PS  	  = image[0].Mcal_PS;
+    catalog[0].measure[Nmeas].t        	  = image[0].tzero + 1e-4*stars[N].Y*image[0].trate; /* trate is in 0.1 msec / row */
+    catalog[0].measure[Nmeas].averef   	  = Nave;           /* XXX EAM : must be absolute Nave if partial read */
+    catalog[0].measure[Nmeas].source   	  = stars[N].code;  /* photcode */
+    catalog[0].measure[Nmeas].dophot   	  = stars[N].dophot;  
+    catalog[0].measure[Nmeas].flags    	  = 0;
+    catalog[0].measure[Nmeas].dt_PS    	  = MTIME;
+    catalog[0].measure[Nmeas].airmass_PS  = secz;
+
+    catalog[0].measure[Nmeas].Mgal_PS  	  = MIN (stars[N].Mgal + MTIME, NO_MAG);
+    catalog[0].measure[Nmeas].FWx      	  = MIN (100*stars[N].fx, NO_MAG);
+    catalog[0].measure[Nmeas].FWy      	  = MIN (100*stars[N].fy, NO_MAG);
+    catalog[0].measure[Nmeas].theta    	  = MIN ((255/360)*stars[N].df, NO_ERR);
+
+    Mcat = PhotCat (&catalog[0].measure[Nmeas]);
+    Mval = (Nsec == -1) ? &catalog[0].average[Nave].M : &catalog[0].secfilt[Nave*Nsecfilt+Nsec].M_PS;
+    if (*Mval == NO_MAG) *Mval = Mcat;
+
+    /** now add references from all previous non-detection observations of this spot on the sky */
+    for (j = 0; (j < Noverlap) && !options.skip_missed; j++) {
+      /* make sure there is space for next entry */
+      if (Nmiss >= NMISS) {
+	NMISS = Nmiss + 1000;
+	REALLOCATE (next_miss, int, NMISS);
+	REALLOCATE (catalog[0].missing, Missing, NMISS);
+      }
+      if (!FindMosaicForImage (overlap, Noverlap, j)) continue;
+      if (!in_image (catalog[0].average[Nave].R, catalog[0].average[Nave].D, &overlap[j])) continue;
+      add_miss_link (&catalog[0].average[Nave], next_miss, Nmiss);
+
+      /* get time of exposure of this portion of the image */
+      RD_to_XY (&X, &Y, catalog[0].average[Nave].R, catalog[0].average[Nave].D, &overlap[j].coords);	  
+      catalog[0].missing[Nmiss].t  = overlap[j].tzero + 1e-4*Y*overlap[j].trate;  /* rough guess at time */
+      catalog[0].average[Nave].Nn ++;
+      Nmiss ++;
+    }
+
+    /* next[Nmeas] should always be -1 in this context (it is always the only
+       measurement for the star) */
+    stars[N].found = Nmeas;
+    next_meas[Nmeas] = -1;
+    Nmeas ++;
+    Nave ++;
+  }
+      
+  REALLOCATE (catalog[0].average, Average, Nave);
+  REALLOCATE (catalog[0].measure, Measure, Nmeas);
+  REALLOCATE (catalog[0].missing, Missing, Nmiss);
+ 
+  if (options.nosort) {
+    catalog[0].sorted = FALSE;
+  } else {
+    catalog[0].sorted = TRUE;
+    catalog[0].measure = sort_measure (catalog[0].average, Nave, catalog[0].measure, Nmeas, next_meas);
+  }
+  catalog[0].missing = sort_missing (catalog[0].average, Nave, catalog[0].missing, Nmiss, next_miss);
+  /* missing is REQUIRED to be sorted */
+
+  /* note stars which have been found in this catalog */
+  for (i = 0; i < NstarsIn; i++) {
+    if (stars[i].found > -1) {
+      stars[i].found = -2;
+    } else {
+      stars[i].found = -3;
+    }
+  }
+
+  /* check if the catalog has changed?  if no change, no need to write */
+  catalog[0].Naverage = Nave;
+  catalog[0].Nmeasure = Nmeas;
+  catalog[0].Nmissing = Nmiss;
+  if (VERBOSE) fprintf (stderr, "Nstars, Nave, Nmeas, Nmiss: %d %d %d %d, (%d matches)\n", Nstars, Nave, Nmeas, Nmiss, Nmatch);
+
+  free (catalog[0].found);
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (X2);
+  free (Y2);
+  free (N2);
+  return (Nmatch);
+}
+
+/* 
+   notes:
+   
+   for finding if a catalog star is in an image or an image star is in the catalog:
+   
+   catalogs have boundaries defined by RA and DEC, but they may curve in projection
+   images have boundaries which are lines in pixels coords, but curve in RA and DEC
+   
+   catalog[0].found[Ncat] but stars[Nstar].found
+   
+*/
Index: /tags/addstar-1-7/Ohana/src/addstar/src/find_matches_closest.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/find_matches_closest.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/find_matches_closest.c	(revision 9206)
@@ -0,0 +1,410 @@
+# include "addstar.h"
+
+int find_matches_closest (SkyRegion *region, Stars *stars, int NstarsIn, Catalog *catalog, Image *image, Image *overlap, int Noverlap, Coords *mosaic, AddstarClientOptions options) {
+
+  int i, j, n, N, J, Jmin, status, Nstars;
+  double X, Y, RADIUS, RADIUS2, Rmin, secz;
+  float *X1, *Y1, *X2, *Y2;
+  float dX, dY, dR;
+  int *N1, *N2,  *next_meas, *next_miss;
+  int Nave, NAVE, Nmeas, NMEAS, Nmiss, NMISS, Nmatch;
+  Coords tcoords;
+  int Nsecfilt, Nsec;
+  float Mcat, *Mval, MTIME;
+  PhotCode *code;
+
+  /* XXX EAM : options.photcode overridden by image.source.... */
+  code = GetPhotcodebyCode (image[0].source);
+
+  /* photcode data - must by of type DEP, (PRI, SEC) - probably should restrict to DEP */
+  Nsecfilt = GetPhotcodeNsecfilt ();
+  Nsec = (code[0].type == PHOT_DEP) ? GetPhotcodeNsec (code[0].equiv) : GetPhotcodeNsec (code[0].code);
+  /* this function requires incoming stars to have the same photcode */
+
+  /** allocate local arrays (stars) **/
+  ALLOCATE (X1, float, NstarsIn);
+  ALLOCATE (Y1, float, NstarsIn);
+  ALLOCATE (N1, int,   NstarsIn);
+
+  /** allocate local arrays (catalog) **/
+  NAVE = Nave = catalog[0].Naverage;
+  ALLOCATE (X2, float, NAVE);
+  ALLOCATE (Y2, float, NAVE);
+  ALLOCATE (N2, int,   NAVE);
+  ALLOCATE (catalog[0].found, int, NAVE);
+  /* for secfilt j and star i, secfilt[i*Nsecfilt+j] */
+
+  /* internal counters */
+  Nmatch = 0;
+  NMEAS = Nmeas = catalog[0].Nmeasure;
+  NMISS = Nmiss = catalog[0].Nmissing;
+
+  /* project onto rectilinear grid with 1 arcsec pixels. the choice of ZEA projection has the
+     advantage that every point in R,D has a mapping to a unique X,Y.  However, note that not all
+     possible X,Y points map back to R,D and the local plate scale changes substantially far from
+     the projection pole.  a better mapping might be ARC, not yet implemented (see
+     coordops.update.c).  We keep the original crpix1,2 and crref1,2.  For mosaic astrometry, the
+     grid should be w.r.t. the tangent-plane, not chip coords */
+
+  if (!strcmp (&image[0].coords.ctype[4], "-WRP")) {
+    tcoords = mosaic[0];
+    tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+    tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+    tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+    tcoords.Npolyterms = 1;
+    strcpy (tcoords.ctype, "RA---ZEA");
+  } else {
+    tcoords = image[0].coords;
+    tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+    tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+    tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+    tcoords.Npolyterms = 1;
+    strcpy (tcoords.ctype, "RA---ZEA");
+  }
+
+  /* build spatial index (RA sort) referencing input array sequence */
+  Nstars = 0;
+  for (i = 0; i < NstarsIn; i++) {
+    status = fRD_to_XY (&X1[Nstars], &Y1[Nstars], stars[i].R, stars[i].D, &tcoords);
+    if (!status) continue;
+    N1[Nstars] = i;
+    Nstars ++;
+  }
+  if (Nstars < 1) {
+    if (VERBOSE) fprintf (stderr, "skipping %s, no overlapping stars\n", catalog[0].filename);
+    free (catalog[0].found);
+    free (X1);
+    free (Y1);
+    free (N1);
+    free (X2);
+    free (Y2);
+    free (N2);
+    return;
+  }
+  if (Nstars > 1) sort_lists (X1, Y1, N1, Nstars);
+
+  /* build spatial index (RA sort) */
+  for (i = 0; i < Nave; i++) {
+    fRD_to_XY (&X2[i], &Y2[i], catalog[0].average[i].R, catalog[0].average[i].D, &tcoords);
+    N2[i] = i;
+    catalog[0].found[N2[i]] = -1;
+  }
+  if (Nave > 1) sort_lists (X2, Y2, N2, Nave);
+
+  /* set up pointers for linked list of measure, missing */
+  if (catalog[0].sorted) {
+    next_meas = init_measure_links (catalog[0].average, Nave, catalog[0].measure, Nmeas);
+  } else {
+    next_meas = build_measure_links (catalog[0].average, Nave, catalog[0].measure, Nmeas);
+  }    
+  next_miss = init_missing_links (catalog[0].average, Nave, catalog[0].missing, Nmiss);
+  /* missing MUST be written 'sorted', or not at all */
+
+  /* choose a radius for matches */
+  if (options.radius == 0) {
+    RADIUS = options.Nsigma * 0.02 * image[0].cerror;  /* 0.02 corrects cerror to arcsec from storage units */
+  } else {
+    RADIUS = options.radius; /* provided by config */
+  }
+  RADIUS2 = RADIUS*RADIUS;
+
+  /* correct instrumental mags for exposure time */
+  MTIME = (image[0].exptime > 0) ? 2.500*log10(image[0].exptime) : 0.0;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nstars) && (j < Nave); ) {
+    if (!finite(X1[i]) || !finite(Y1[i])) { 
+      i++; 
+      continue;
+    }
+    if (!finite(X2[j]) || !finite(Y2[j])) { 
+      j++; 
+      continue;
+    }
+    
+    /* negative dX: j is too large */
+    dX = X1[i] - X2[j];
+    if (dX <= -2*RADIUS) {
+      i++;
+      continue;
+    }
+    /* positive dX, i is too large */
+    if (dX >= 2*RADIUS) {
+      j++;
+      continue;
+    }
+
+    Jmin = -1;
+    Rmin = RADIUS2;
+    for (J = j; (dX > -2*RADIUS) && (J < Nave); J++) {
+      /* find closest match for this detection */
+      dX = X1[i] - X2[J];
+      dY = Y1[i] - Y2[J];
+      dR = dX*dX + dY*dY;
+      if (dR > RADIUS2) continue;
+      if (dR < Rmin) {
+	Rmin = dR;
+	Jmin  = J;
+      }
+    }
+
+    /* no match, try next detection */ 
+    if (Jmin == -1) {
+      i++;
+      continue;
+    }
+
+    /*** a match is found, add to average, measure ***/
+
+    /* make sure there is space for next entry */
+    if (Nmeas >= NMEAS) {
+      NMEAS = Nmeas + 1000;
+      REALLOCATE (next_meas, int, NMEAS);
+      REALLOCATE (catalog[0].measure, Measure, NMEAS);
+    }
+
+    Nmatch ++;
+    n = N2[Jmin];
+    N = N1[i];
+
+    /* add to end of measurement list */
+    add_meas_link (&catalog[0].average[n], next_meas, Nmeas, NMEAS);
+    ohana_memcheck (0);
+	
+    /* calculate accurate per-star airmass, if required */
+    secz = airmass (image[0].secz_PS, stars[N].R, stars[N].D, image[0].sidtime, image[0].latitude);
+      
+    /** add measurements for this star **/
+    /** dR,dD now represent arcsec **/
+    catalog[0].measure[Nmeas].dR_PS       = 3600.0*(catalog[0].average[n].R - stars[N].R);
+    if (catalog[0].measure[Nmeas].dR_PS > +180.0*3600.0) {
+      // average on high end of boundary, move star up
+      stars[N].R += 360.0;
+      catalog[0].measure[Nmeas].dR_PS = 3600.0*(catalog[0].average[n].R - stars[N].R);
+    }
+    if (catalog[0].measure[Nmeas].dR_PS < -180.0*3600.0) {
+      // average on low end of boundary, move star down
+      stars[N].R -= 360.0;
+      catalog[0].measure[Nmeas].dR_PS = 3600.0*(catalog[0].average[n].R - stars[N].R);
+    }
+    if (fabs(catalog[0].measure[Nmeas].dR_PS) > 10*RADIUS) {
+      fprintf (stderr, "error: %10.6f,%10.6f vs %10.6f,%10.6f (%f,%f vs %f,%f)\n", 
+	       catalog[0].average[n].R, catalog[0].average[n].D, 
+	       stars[N].R, stars[N].D,
+	       X1[i], X2[Jmin], 
+	       Y1[i], Y2[Jmin]);
+    }
+    catalog[0].measure[Nmeas].dD_PS       = 3600.0*(catalog[0].average[n].D - stars[N].D);
+    catalog[0].measure[Nmeas].M_PS        = MIN (stars[N].M + MTIME, NO_MAG);
+    catalog[0].measure[Nmeas].dM_PS       = MIN (stars[N].dM, NO_ERR);  /* error in input files stored in thousandths of mag */
+    catalog[0].measure[Nmeas].Mcal_PS     = image[0].Mcal_PS;
+    catalog[0].measure[Nmeas].t           = image[0].tzero + 1e-4*stars[N].Y*image[0].trate;  /* trate is in 0.1 msec / row */
+    catalog[0].measure[Nmeas].averef      = n;
+    catalog[0].measure[Nmeas].source      = stars[N].code;  /* photcode */
+    catalog[0].measure[Nmeas].dophot      = stars[N].dophot;  
+    catalog[0].measure[Nmeas].flags       = 0;
+    catalog[0].measure[Nmeas].dt_PS       = MTIME;
+    catalog[0].measure[Nmeas].airmass_PS  = secz;
+
+    catalog[0].measure[Nmeas].Mgal_PS     = MIN (stars[N].Mgal + MTIME, NO_MAG);
+    catalog[0].measure[Nmeas].FWx         = MIN (100*stars[N].fx, NO_MAG);
+    catalog[0].measure[Nmeas].FWy         = MIN (100*stars[N].fy, NO_MAG);
+    catalog[0].measure[Nmeas].theta       = MIN ((255/360)*stars[N].df, NO_ERR);
+	
+    /* it is not valid to pass PRI/SEC/REF photcodes to this routine */
+    /* check for entries in the secfilt lists */
+    Mcat = PhotCat (&catalog[0].measure[Nmeas]);
+    Mval = (Nsec == -1) ? &catalog[0].average[n].M : &catalog[0].secfilt[n*Nsecfilt+Nsec].M_PS;
+    if (*Mval == NO_MAG) *Mval = Mcat;
+    /* in UPDATE mode, this value is not saved; use relphot to recalculate */
+
+    /* adds the measurement to the calibration if appropriate color terms are found */
+    if (options.calibrate) {
+      AddToCalibration (&catalog[0].average[n], catalog[0].measure, &catalog[0].measure[Nmeas], next_meas, N);
+    }
+
+    /* if we choose to flag close encounters, see find_matches.c */
+    /* if we choose to calculate RA,DEC averages, see update_coords.c */
+
+    /* Nm is updated, but not written out in -update mode (for existing entries)
+       Nm is recalculated in build_meas_links if loaded table is not sorted */
+    stars[N].found = Nmeas;
+    catalog[0].found[n] = Nmeas;
+    catalog[0].average[n].Nm ++;
+    Nmeas ++;
+    i++;
+    ohana_memcheck (0);
+  }
+  ohana_memcheck (0);
+
+  /** add reference for undetected catalog stars **/
+  if (!strcmp (&image[0].coords.ctype[4], "-WRP")) RegisterMosaic (mosaic);
+  for (j = 0; (j < Nave) && !options.skip_missed; j++) {
+    n = N2[j];
+    if (catalog[0].found[n] < 0) { 
+      /* make sure there is space for next entry */
+      if (Nmiss >= NMISS) {
+	NMISS = Nmiss + 1000;
+	REALLOCATE (next_miss, int, NMISS);
+	REALLOCATE (catalog[0].missing, Missing, NMISS);
+      }
+
+      /* should the catalog star be on this image? project into image coords */
+      if (!in_image (catalog[0].average[n].R, catalog[0].average[n].D, image)) continue;
+      add_miss_link (&catalog[0].average[n], next_miss, Nmiss);
+
+      /* calculate time of exposure for this coordinate in the image */
+      RD_to_XY (&X, &Y, catalog[0].average[n].R, catalog[0].average[n].D, &image[0].coords);	  
+      catalog[0].missing[Nmiss].t  = image[0].tzero + 1e-4*Y*image[0].trate;  /* trate is in 0.1 msec / row */
+      catalog[0].average[n].Nn ++;
+      Nmiss ++;
+    }
+  }
+
+  /** incorporate unmatched image stars, if this star is in field of this catalog **/
+  /* these new entries are all written out in UPDATE mode */ 
+  for (i = 0; (i < Nstars) && !options.only_match; i++) {
+    /* make sure there is space for next entry */
+    if (Nmeas >= NMEAS) {
+      NMEAS = Nmeas + 1000;
+      REALLOCATE (next_meas, int, NMEAS);
+      REALLOCATE (catalog[0].measure, Measure, NMEAS);
+    }
+    if (Nave >= NAVE) {
+      NAVE = Nave + 1000;
+      REALLOCATE (catalog[0].average, Average, NAVE);
+      REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*catalog[0].Nsecfilt);
+    }
+
+    N = N1[i];
+    if (stars[N].found >= 0) continue;
+    if (!IN_CATALOG (stars[N].R, stars[N].D)) continue;
+
+    secz = airmass (image[0].secz_PS, stars[N].R, stars[N].D, image[0].sidtime, image[0].latitude);
+
+    catalog[0].average[Nave].R         = stars[N].R;
+    catalog[0].average[Nave].D         = stars[N].D;
+    catalog[0].average[Nave].M         = NO_MAG;
+    catalog[0].average[Nave].dM        = NO_MAG;
+    catalog[0].average[Nave].Nm        = 1;
+    catalog[0].average[Nave].Nn        = 0;
+    catalog[0].average[Nave].Xp        = NO_MAG;
+    catalog[0].average[Nave].Xm        = NO_MAG;
+    catalog[0].average[Nave].Xg        = NO_MAG;
+    catalog[0].average[Nave].offset    = Nmeas;
+    catalog[0].average[Nave].missing   = -1;
+    catalog[0].average[Nave].code      = 0;
+
+    catalog[0].average[Nave].dR        = 0;
+    catalog[0].average[Nave].dD        = 0;
+    catalog[0].average[Nave].uR        = 0;
+    catalog[0].average[Nave].uD        = 0;
+    catalog[0].average[Nave].duR       = 0;
+    catalog[0].average[Nave].duD       = 0;
+    catalog[0].average[Nave].P         = 0;
+    catalog[0].average[Nave].dP        = 0;
+
+    for (j = 0; j < Nsecfilt; j++) {
+      catalog[0].secfilt[Nave*Nsecfilt+j].M_PS  = NO_MAG;
+      catalog[0].secfilt[Nave*Nsecfilt+j].dM_PS = NO_MAG;
+      catalog[0].secfilt[Nave*Nsecfilt+j].Xm    = NO_MAG;
+    }
+
+    catalog[0].measure[Nmeas].dR_PS       = 0.0;
+    catalog[0].measure[Nmeas].dD_PS       = 0.0;
+    catalog[0].measure[Nmeas].M_PS        = MIN (stars[N].M + MTIME, NO_MAG);
+    catalog[0].measure[Nmeas].dM_PS       = MIN (stars[N].dM, NO_ERR);
+    catalog[0].measure[Nmeas].Mcal_PS  	  = image[0].Mcal_PS;
+    catalog[0].measure[Nmeas].t        	  = image[0].tzero + 1e-4*stars[N].Y*image[0].trate; /* trate is in 0.1 msec / row */
+    catalog[0].measure[Nmeas].averef   	  = Nave;
+    catalog[0].measure[Nmeas].source   	  = stars[N].code;  /* photcode */
+    catalog[0].measure[Nmeas].dophot   	  = stars[N].dophot;  
+    catalog[0].measure[Nmeas].flags    	  = 0;
+    catalog[0].measure[Nmeas].dt_PS    	  = MTIME;
+    catalog[0].measure[Nmeas].airmass_PS  = secz;
+
+    catalog[0].measure[Nmeas].Mgal_PS  	  = MIN (stars[N].Mgal + MTIME, NO_MAG);
+    catalog[0].measure[Nmeas].FWx      	  = MIN (100*stars[N].fx, NO_MAG);
+    catalog[0].measure[Nmeas].FWy      	  = MIN (100*stars[N].fy, NO_MAG);
+    catalog[0].measure[Nmeas].theta    	  = MIN ((255/360)*stars[N].df, NO_ERR);
+
+    Mcat = PhotCat (&catalog[0].measure[Nmeas]);
+    Mval = (Nsec == -1) ? &catalog[0].average[Nave].M : &catalog[0].secfilt[Nave*Nsecfilt+Nsec].M_PS;
+    if (*Mval == NO_MAG) *Mval = Mcat;
+
+    /** now add references from all previous non-detection observations of this spot on the sky */
+    for (j = 0; (j < Noverlap) && !options.skip_missed; j++) {
+      /* make sure there is space for next entry */
+      if (Nmiss >= NMISS) {
+	NMISS = Nmiss + 1000;
+	REALLOCATE (next_miss, int, NMISS);
+	REALLOCATE (catalog[0].missing, Missing, NMISS);
+      }
+      if (!FindMosaicForImage (overlap, Noverlap, j)) continue;
+      if (!in_image (catalog[0].average[Nave].R, catalog[0].average[Nave].D, &overlap[j])) continue;
+      add_miss_link (&catalog[0].average[Nave], next_miss, Nmiss);
+
+      /* get time of exposure of this portion of the image */
+      RD_to_XY (&X, &Y, catalog[0].average[Nave].R, catalog[0].average[Nave].D, &overlap[j].coords);	  
+      catalog[0].missing[Nmiss].t  = overlap[j].tzero + 1e-4*Y*overlap[j].trate;  /* rough guess at time */
+      catalog[0].average[Nave].Nn ++;
+      Nmiss ++;
+    }
+
+    /* next[Nmeas] should always be -1 in this context (it is always the only
+       measurement for the star) */
+    stars[N].found = Nmeas;
+    next_meas[Nmeas] = -1;
+    Nmeas ++;
+    Nave ++;
+  }
+      
+  REALLOCATE (catalog[0].average, Average, Nave);
+  REALLOCATE (catalog[0].measure, Measure, Nmeas);
+  REALLOCATE (catalog[0].missing, Missing, Nmiss);
+ 
+  if (options.nosort) {
+    catalog[0].sorted = FALSE;
+  } else {
+    catalog[0].sorted = TRUE;
+    catalog[0].measure = sort_measure (catalog[0].average, Nave, catalog[0].measure, Nmeas, next_meas);
+  }
+  catalog[0].missing = sort_missing (catalog[0].average, Nave, catalog[0].missing, Nmiss, next_miss);
+  /* missing is REQUIRED to be sorted */
+
+  /* note stars which have been found in this catalog */
+  for (i = 0; i < NstarsIn; i++) {
+    if (stars[i].found > -1) {
+      stars[i].found = -2;
+    } else {
+      stars[i].found = -3;
+    }
+  }
+
+  /* check if the catalog has changed?  if no change, no need to write */
+  catalog[0].Naverage = Nave;
+  catalog[0].Nmeasure = Nmeas;
+  catalog[0].Nmissing = Nmiss;
+  if (VERBOSE) fprintf (stderr, "Nstars, Nave, Nmeas, Nmiss: %d %d %d %d, (%d matches)\n", NstarsIn, Nave, Nmeas, Nmiss, Nmatch);
+
+  free (catalog[0].found);
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (X2);
+  free (Y2);
+  free (N2);
+  return (Nmatch);
+}
+
+/* 
+   notes:
+   
+   for finding if a catalog star is in an image or an image star is in the catalog:
+   
+   catalogs have boundaries defined by RA and DEC, but they may curve in projection
+   images have boundaries which are lines in pixels coords, but curve in RA and DEC
+   
+   catalog[0].found[Ncat] but stars[Nstar].found
+   
+*/
Index: /tags/addstar-1-7/Ohana/src/addstar/src/find_matches_refstars.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/find_matches_refstars.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/find_matches_refstars.c	(revision 9206)
@@ -0,0 +1,340 @@
+# include "addstar.h"
+
+int find_matches_refstars (SkyRegion *region, Stars **stars, int Nstars, Catalog *catalog, AddstarClientOptions options) {
+
+  int i, j, k, n, m, N, J;
+  double RADIUS, RADIUS2;
+  float *X1, *Y1, *X2, *Y2;
+  float dX, dY, dR;
+  int *N1, *N2,  *next, *next_miss, last, last_miss;
+  int Nave, NAVE, Nmeas, NMEAS, Nmiss, NMISS, Nmatch;
+  Measure *tmpmeasure;
+  Missing *tmpmissing;
+  Coords tcoords;
+  int Nsecfilt;
+
+  /* photcode data -- should not have to modify secfilt / average */
+  Nsecfilt = GetPhotcodeNsecfilt ();
+
+  /** allocate local arrays (stars) **/
+  ALLOCATE (X1, float, Nstars);
+  ALLOCATE (Y1, float, Nstars);
+  ALLOCATE (N1, int,   Nstars);
+
+  /** allocate local arrays (catalog) **/
+  Nave = catalog[0].Naverage;
+  NAVE = Nave + 1000;
+  ALLOCATE (X2, float, NAVE);
+  ALLOCATE (Y2, float, NAVE);
+  ALLOCATE (N2, int, NAVE);
+  ALLOCATE (catalog[0].found, int, NAVE);
+  REALLOCATE (catalog[0].average, Average, NAVE);
+  REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*catalog[0].Nsecfilt);
+  /* for secfilt j and star i, secfilt[i*Nsecfilt+j] */
+
+  Nmatch = 0;
+  Nmeas = catalog[0].Nmeasure;
+  NMEAS = Nmeas + 1000;
+  ALLOCATE (next, int, NMEAS);
+  REALLOCATE (catalog[0].measure, Measure, NMEAS);
+  
+  Nmiss = catalog[0].Nmissing;
+  NMISS = Nmiss + 1000;
+  if ((NMISS < 1) || (NMISS > 1e10)) {
+      fprintf (stderr, "weird value for NMISS: %d\n", NMISS);
+  }
+  ALLOCATE (next_miss, int, NMISS);
+  REALLOCATE (catalog[0].missing, Missing, NMISS);
+  
+  /* project onto rectilinear grid with 1 arcsec pixels, sort by X */
+  /* reference for coords is catalog center */
+  tcoords.crval1 = 0.5*(region[0].Rmin + region[0].Rmax);
+  tcoords.crval2 = 0.5*(region[0].Dmin + region[0].Dmax);
+  tcoords.crpix1 = tcoords.crpix2 = 0.0;
+  tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+  tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+  tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+  strcpy (tcoords.ctype, "RA---ZEA");
+  tcoords.Npolyterms = 0;
+  
+  for (i = 0; i < Nstars; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], stars[i][0].R, stars[i][0].D, &tcoords);
+    N1[i] = i;
+  }
+  if (Nstars > 1) sort_lists (X1, Y1, N1, Nstars);
+  
+  for (i = 0; i < Nave; i++) {
+    fRD_to_XY (&X2[i], &Y2[i], catalog[0].average[i].R, catalog[0].average[i].D, &tcoords);
+    N2[i] = i;
+    catalog[0].found[N2[i]] = -1;
+  }
+  if (Nave > 1) sort_lists (X2, Y2, N2, Nave);
+
+  /* set up pointers for linked list of measurements */
+  for (i = 0; i < Nmeas - 1; i++) {
+    next[i] = i+1;
+  }
+  next[i] = -1;
+  last = i;
+
+  for (i = 0; i < Nmiss - 1; i++) {
+    next_miss[i] = i+1;
+  }
+  next_miss[i] = -1;
+  last_miss = i;
+
+  /* choose a radius for matches */
+  if (options.radius == 0) {
+    RADIUS = 2.0; /* hardwired default for refstars */
+  } else {
+    RADIUS = options.radius; /* provided by config */
+  }
+  RADIUS2 = RADIUS*RADIUS;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nstars) && (j < Nave); ) {
+    
+    dX = X1[i] - X2[j];
+    if (dX <= -2*RADIUS) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*RADIUS) {
+      j++;
+      continue;
+    }
+
+    /* negative dX: j is too large, positive dX, i is too large */
+    for (J = j; (dX > -2*RADIUS) && (J < Nave); J++) {
+      dX = X1[i] - X2[J];
+      dY = Y1[i] - Y2[J];
+      dR = dX*dX + dY*dY;
+      if (dR > RADIUS2) continue;
+
+      Nmatch ++;
+      n = N2[J];
+      N = N1[i];
+      m = catalog[0].average[n].offset;  
+
+      /** in replace mode, search for entry and replace values M, dM, R, D */
+      if (options.replace && replace_match (&catalog[0].average[n], &catalog[0].measure[m], stars[N])) continue;
+
+      /** insert star in measurement list */
+      /* find last measurement of this star */
+      for (k = 0; k < catalog[0].average[n].Nm - 1; k++) m = next[m];
+      /* set up references */
+      next[Nmeas] = next[m];
+      next[m] = Nmeas;
+      /* last just was moved */
+      if (next[Nmeas] == -1) last = Nmeas;
+	
+      /** add measurements for this star **/
+      /** *** dR,dD now in arcsec *** **/
+      catalog[0].measure[Nmeas].dR_PS       = 3600.0*(catalog[0].average[n].R - stars[N][0].R);
+      catalog[0].measure[Nmeas].dD_PS       = 3600.0*(catalog[0].average[n].D - stars[N][0].D);
+      catalog[0].measure[Nmeas].M_PS        = MIN (stars[N][0].M,  NO_MAG);
+      catalog[0].measure[Nmeas].dM_PS       = MIN (stars[N][0].dM, NO_ERR);
+      catalog[0].measure[Nmeas].Mcal_PS     = 0;
+      catalog[0].measure[Nmeas].t           = (TIMEREF == 0) ? stars[N][0].t : TIMEREF; /** careful : time_t vs e_time **/
+      catalog[0].measure[Nmeas].averef      = n;
+      catalog[0].measure[Nmeas].source      = stars[N][0].code;
+      catalog[0].measure[Nmeas].dophot      = 0;
+      catalog[0].measure[Nmeas].flags       = 0;
+      catalog[0].measure[Nmeas].dt_PS       = 0xffff;
+
+      catalog[0].measure[Nmeas].Mgal_PS     = NO_MAG;
+      catalog[0].measure[Nmeas].airmass_PS  = 0;
+      catalog[0].measure[Nmeas].FWx         = NO_MAG;
+      catalog[0].measure[Nmeas].FWy         = NO_MAG;
+      catalog[0].measure[Nmeas].theta       = NO_ERR;
+	
+      if (ACCEPT_MOTION) {
+	catalog[0].average[n].uR          = stars[N][0].uR;
+	catalog[0].average[n].uD          = stars[N][0].uD;
+	catalog[0].average[n].duR         = stars[N][0].duR;
+	catalog[0].average[n].duD         = stars[N][0].duD;
+	catalog[0].average[n].P           = stars[N][0].P;
+	catalog[0].average[n].dP          = stars[N][0].dP;
+      }
+
+      /** don't update average / secfilt values for REF photcodes **/
+
+      /*** handle multiple stars */
+      /* this image star matches more than one catalog star */
+      if (stars[N][0].found > -1) {
+	catalog[0].measure[stars[N][0].found].flags |= BLEND_IMAGE;
+	catalog[0].measure[Nmeas].flags |= BLEND_IMAGE;
+      } 
+      if (stars[N][0].found == -2) { /* this image star matches a catalog star on a neighboring catalog */
+	catalog[0].measure[Nmeas].flags |= BLEND_IMAGE_NEIGHBOR;
+      } 
+      if (stars[N][0].found == -1) { /* this image star matches only this catalog star */
+	stars[N][0].found = Nmeas;  /* save first match, in case coincidences are found */
+      }
+      /* this catalog star matches more than one image star */
+      if (catalog[0].found[n] > -1) {
+	catalog[0].measure[catalog[0].found[n]].flags |= BLEND_CATALOG;
+	catalog[0].measure[Nmeas].flags |= BLEND_CATALOG;
+      } else {
+	catalog[0].found[n] = Nmeas;
+      }
+
+      catalog[0].average[n].Nm ++;
+      Nmeas ++;
+      if (Nmeas == NMEAS) {
+	NMEAS = Nmeas + 1000;
+	REALLOCATE (next, int, NMEAS);
+	REALLOCATE (catalog[0].measure, Measure, NMEAS);
+      }
+
+      update_coords (&catalog[0].average[n], &catalog[0].measure[0], next);
+    }
+    i++;
+  }
+
+  /* we don't add missed entries for refcat
+     (already in database, not refcat) */
+
+  /* incorporate unmatched refcat stars */
+  /* skip if we want to require matches
+     combined with -replace, this lets us keep 
+     the reference up-to-date with known stars only */
+
+  for (i = 0; (i < Nstars) && !options.only_match; i++) {
+    N = N1[i];
+    if (stars[N][0].found >= 0) continue;
+
+    catalog[0].average[Nave].R         = stars[N][0].R;
+    catalog[0].average[Nave].D         = stars[N][0].D;
+
+    if (ACCEPT_MOTION) {
+      catalog[0].average[Nave].dR    = stars[N][0].dR;
+      catalog[0].average[Nave].dD    = stars[N][0].dD;
+      catalog[0].average[Nave].uR    = stars[N][0].uR;
+      catalog[0].average[Nave].uD    = stars[N][0].uD;
+      catalog[0].average[Nave].duR   = stars[N][0].duR;
+      catalog[0].average[Nave].duD   = stars[N][0].duD;
+      catalog[0].average[Nave].P     = stars[N][0].P;
+      catalog[0].average[Nave].dP    = stars[N][0].dP;
+    } else {
+      catalog[0].average[Nave].dR    = 0;
+      catalog[0].average[Nave].dD    = 0;
+      catalog[0].average[Nave].uR    = 0;
+      catalog[0].average[Nave].uD    = 0;
+      catalog[0].average[Nave].duR   = 0;
+      catalog[0].average[Nave].duD   = 0;
+      catalog[0].average[Nave].P     = 0;
+      catalog[0].average[Nave].dP    = 0;
+    }
+
+    catalog[0].average[Nave].M         = NO_MAG;
+    catalog[0].average[Nave].dM        = NO_MAG;
+    catalog[0].average[Nave].Nm        = 1;
+    catalog[0].average[Nave].Nn        = 0;
+    catalog[0].average[Nave].Xp        = NO_MAG;
+    catalog[0].average[Nave].Xm        = NO_MAG;
+    catalog[0].average[Nave].Xg        = NO_MAG;
+    catalog[0].average[Nave].offset    = Nmeas;
+    catalog[0].average[Nave].missing   = -1;
+    catalog[0].average[Nave].code      = 0;
+
+    for (j = 0; j < Nsecfilt; j++) {
+      catalog[0].secfilt[Nave*Nsecfilt+j].M_PS  = NO_MAG;
+      catalog[0].secfilt[Nave*Nsecfilt+j].dM_PS = NO_MAG;
+      catalog[0].secfilt[Nave*Nsecfilt+j].Xm    = NO_MAG;
+    }
+
+    catalog[0].measure[Nmeas].dR_PS       = 0.0;
+    catalog[0].measure[Nmeas].dD_PS       = 0.0;
+    catalog[0].measure[Nmeas].M_PS        = MIN (stars[N][0].M,  NO_MAG);
+    catalog[0].measure[Nmeas].dM_PS       = MIN (stars[N][0].dM, NO_ERR);
+    catalog[0].measure[Nmeas].Mcal_PS     = 0;
+    catalog[0].measure[Nmeas].t        	  = (stars[N][0].t == 0) ? TIMEREF : stars[N][0].t; /** careful : time_t vs e_time **/
+    catalog[0].measure[Nmeas].averef   	  = Nave;
+    catalog[0].measure[Nmeas].source   	  = stars[N][0].code;
+    catalog[0].measure[Nmeas].dophot   	  = 0;
+    catalog[0].measure[Nmeas].flags    	  = 0;
+    catalog[0].measure[Nmeas].dt_PS       = 0xffff;
+
+    catalog[0].measure[Nmeas].Mgal_PS     = NO_MAG;
+    catalog[0].measure[Nmeas].airmass_PS  = 0;
+    catalog[0].measure[Nmeas].FWx      	  = NO_MAG;
+    catalog[0].measure[Nmeas].FWy      	  = NO_ERR;
+    catalog[0].measure[Nmeas].theta    	  = NO_ERR;
+
+    stars[N][0].found = Nmeas;
+    next[last] = Nmeas;
+    next[Nmeas] = -1;
+    last = Nmeas;
+    Nmeas ++;
+    if (Nmeas == NMEAS) {
+      NMEAS = Nmeas + 1000;
+      REALLOCATE (next, int, NMEAS);
+      REALLOCATE (catalog[0].measure, Measure, NMEAS);
+    }
+    Nave ++;
+    if (Nave == NAVE) {
+      NAVE = Nave + 1000;
+      REALLOCATE (catalog[0].average, Average, NAVE);
+      REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*catalog[0].Nsecfilt);
+    }
+  }
+      
+  free (catalog[0].found);
+  REALLOCATE (catalog[0].average, Average, Nave);
+
+  /* fix order of Measure (memory intensive, but fast) */
+  N = 0; 
+  ALLOCATE (tmpmeasure, Measure, Nmeas);
+  for (i = 0; i < Nave; i++) {
+    n = catalog[0].average[i].offset;
+    catalog[0].average[i].offset = N;
+    for (k = 0; k < catalog[0].average[i].Nm; k++, N++) {
+      tmpmeasure[N] = catalog[0].measure[n]; 
+      tmpmeasure[N].averef = i;
+      n = next[n];
+    }
+  }
+  free (catalog[0].measure);
+  catalog[0].measure = tmpmeasure;
+    
+  /* fix order of Missing (memory intensive, but fast) */
+  N = 0; 
+  ALLOCATE (tmpmissing, Missing, Nmiss);
+  for (i = 0; i < Nave; i++) {
+    if (catalog[0].average[i].Nn > 0) {
+      n = catalog[0].average[i].missing;
+      catalog[0].average[i].missing = N;
+      for (k = 0; k < catalog[0].average[i].Nn; k++, N++) {
+	tmpmissing[N] = catalog[0].missing[n]; 
+	n = next_miss[n];
+      }
+    }
+  }
+  free (catalog[0].missing);
+  catalog[0].missing = tmpmissing;
+
+  /* note stars which have been found in this catalog */
+  for (i = 0; i < Nstars; i++) {
+    if (stars[i][0].found > -1) {
+      stars[i][0].found = -2;
+    } else {
+      stars[i][0].found = -3;
+    }
+  }
+
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (X2);
+  free (Y2);
+  free (N2);
+  free (next);
+  free (next_miss);
+
+  catalog[0].Naverage = Nave;
+  catalog[0].Nmeasure = Nmeas;
+  catalog[0].Nmissing = Nmiss;
+  if (VERBOSE) fprintf (stderr, "Nstars, Nave, Nmeas, Nmiss: %d %d %d %d, (%d matches)\n", Nstars, Nave, Nmeas, Nmiss, Nmatch);
+  return (Nmatch);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/find_proper.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/find_proper.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/find_proper.c	(revision 9206)
@@ -0,0 +1,158 @@
+# include "addusno.h"
+
+find_proper (catstats, catalog, usnostats, usno, Nusno)
+CatStats catstats[];
+Catalog catalog[];
+USNOstats usnostats[];
+USNOdata usno[];
+int Nusno;
+{
+
+  int i, j, k, n, m, N, first_j;
+  double RADIUS2, PROPER2;
+  float *X1, *Y1, *X2, *Y2, *usnodist;
+  float dX, dY, dR, dR2;
+  int *N1, *N2,  *next, last;
+  int Nave, Nmeas, NMEAS, Nmatch;
+  unsigned int flags;
+  Measure *tmpmeasure;
+  Coords *tcoords;
+  int already_matched, far_enough;
+
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  N1 = catstats[0].N;
+  Nave = catalog[0].Naverage;
+
+  /* no need to do this twice!! */
+  ALLOCATE (usnodist, float, Nave);
+  bzero (usnodist, Nave*sizeof(float));
+
+  X2 = usnostats[0].X;
+  Y2 = usnostats[0].Y;
+  N2 = usnostats[0].N;
+
+ /* set up link listed pointers for new measurements */
+  Nmatch = 0;
+  Nmeas = catalog[0].Nmeasure;
+  NMEAS = Nmeas + 1000;
+  ALLOCATE (next, int, NMEAS);
+  REALLOCATE (catalog[0].measure, Measure, NMEAS);
+  /* set up pointers for linked list of measurements */
+  for (i = 0; i < Nmeas - 1; i++) {
+    next[i] = i+1;
+  }
+  next[i] = -1;
+  last = i;
+  
+  /* choose a radius for matches */
+  PROPER2 = PROPER*PROPER;
+  RADIUS2 = RADIUS*RADIUS;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nave) && (j < Nusno); ) {
+    if (catalog[0].average[N1[i]].code & ID_MOVING) { 
+      /* this is not a star, skip */
+      i++;
+      continue;
+    }
+    if (catalog[0].average[N1[i]].Nm < 3) { 
+      /* may just be a noise spike, skip */
+      i++;
+      continue;
+    }
+    if (catalog[0].average[N1[i]].code & ID_USNO) {
+      /* already matched with USNO, skip this one */
+      i++;
+      continue;
+    }
+    dX = X1[i] - X2[j];
+    if (dX <= -2*PROPER) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*PROPER) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    for (; (dX > -2*PROPER) && (j < Nusno); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < PROPER2) {  
+	n = N1[i];  /* N1 refers to the average[] list */
+	N = N2[j];  /* N2 refers to the usno[] list */
+	if (usnostats[0].match[N] > -1) 
+	  continue;
+	if ((catalog[0].average[n].code & ID_USNO) && (usnodist[i] < dR)) {
+	  /* existing USNO match is closer than this new one, skip this one */
+	  continue;
+	}
+	usnodist[i] = dR;
+	m = catalog[0].average[n].offset;  /* first measurement of this star */
+	for (k = 0; k < catalog[0].average[n].Nm - 1; k++)
+	  m = next[m];
+	next[Nmeas+1] = next[m]; /* insert 2 measurements in linked list */
+	next[Nmeas] = Nmeas + 1;
+	next[m] = Nmeas;
+	if (next[Nmeas+1] == -1) { /* last just was moved */
+	  last = Nmeas+1;
+	}
+	Nmatch ++;
+	
+	/** add measurements for this star **/
+	catalog[0].measure[Nmeas].dR  = 360000.0*(catalog[0].average[n].R - usno[N].R);
+	catalog[0].measure[Nmeas].dD  = 360000.0*(catalog[0].average[n].D - usno[N].D);
+	catalog[0].measure[Nmeas].M   = 1000.0*fabs(usno[N].r);
+	catalog[0].measure[Nmeas].Mcal= 0;    /* above measurement is exact */
+	catalog[0].measure[Nmeas].dM  = 100;  /* error in input files stored in thousandths of mag */
+	catalog[0].measure[Nmeas].t   = 0;    /* a flag: if 0, image is not in database */
+	catalog[0].measure[Nmeas].averef  = n;
+	catalog[0].measure[Nmeas].source = USNO_RED; 
+	catalog[0].measure[Nmeas+1].dR  = catalog[0].measure[Nmeas].dR;
+	catalog[0].measure[Nmeas+1].dD  = catalog[0].measure[Nmeas].dD;
+	catalog[0].measure[Nmeas+1].M   = 1000.0*fabs(usno[N].b);
+	catalog[0].measure[Nmeas+1].Mcal= 0;    /* above measurement is exact */
+	catalog[0].measure[Nmeas+1].dM  = 100;  /* error in input files stored in thousandths of mag */
+	catalog[0].measure[Nmeas+1].t   = 0;    /* a flag: if 0, image is not in database */
+	catalog[0].measure[Nmeas+1].averef  = n;
+	catalog[0].measure[Nmeas+1].source = USNO_BLUE; 
+	/* add flag in average to mark as matched with the USNO catalog */
+	catalog[0].average[n].code |= (ID_PROPER | ID_USNO);
+	
+	/* we add two measurement for each star: 1 in r, 1 in b */
+	catalog[0].average[n].Nm +=2;
+	Nmeas +=2;  
+	if (Nmeas == NMEAS - 2) {  /* just to be safe... */
+	  NMEAS = Nmeas + 1000;
+	  REALLOCATE (next, int, NMEAS);
+	  REALLOCATE (catalog[0].measure, Measure, NMEAS);
+	}
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  REALLOCATE (catalog[0].measure, Measure, Nmeas);
+
+  /* fix order of Measure (memory intensive, but fast) */
+  N = 0; 
+  ALLOCATE (tmpmeasure, Measure, Nmeas);
+  for (i = 0; i < Nave; i++) {
+    n = catalog[0].average[i].offset;
+    catalog[0].average[i].offset = N;
+    for (k = 0; k < catalog[0].average[i].Nm; k++, N++) {
+      tmpmeasure[N] = catalog[0].measure[n]; 
+      n = next[n];
+    }
+  }
+  free (catalog[0].measure);
+  catalog[0].measure = tmpmeasure;
+    
+  catalog[0].Nmeasure = Nmeas;
+  if (VERBOSE) fprintf (stderr, "Nusno, Nave, Nmeas: %d %d %d, (%d matches)\n", Nusno, Nave, Nmeas, Nmatch);
+}
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/find_subset.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/find_subset.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/find_subset.c	(revision 9206)
@@ -0,0 +1,36 @@
+# include "addstar.h"
+
+/* find stars within this region */
+Stars **find_subset (SkyRegion *region, Stars *stars, int Nstars, int *Nsubset) {
+
+  int i, N, NSUBSET;
+  Stars **subset;
+  double RA0, RA1, DEC0, DEC1;
+
+  NSUBSET = 1000;
+  ALLOCATE (subset, Stars *, NSUBSET);
+
+  RA0  = region[0].Rmin;
+  RA1  = region[0].Rmax;
+  DEC0 = region[0].Dmin;
+  DEC1 = region[0].Dmax;
+
+  if (VERBOSE) fprintf (stderr, "subset for %f - %f, %f - %f\n", RA0, RA1, DEC0, DEC1);
+
+  /* find stars within ra,dec region */
+  for (i = N = 0; i < Nstars; i++) {
+    if (stars[i].R <  RA0)  continue;
+    if (stars[i].R >= RA1)  continue;
+    if (stars[i].D <  DEC0) continue;
+    if (stars[i].D >= DEC1) continue;
+
+    subset[N] = &stars[i];
+    N++;
+    if (N == NSUBSET - 1) {
+      NSUBSET += 1000;
+      REALLOCATE (subset, Stars *, NSUBSET);
+    }
+  }
+  *Nsubset = N;
+  return (subset);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/get2mass.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/get2mass.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/get2mass.c	(revision 9206)
@@ -0,0 +1,121 @@
+# include "addstar.h"
+# include "2mass.h"
+
+Stars *get2mass (SkyRegion *patch, int photcode, int mode, int *NSTARS) {
+  
+  char *path;
+  char gzname[1024];
+  int i, status, Nstars, Nrefcat; 
+  Stars    *stars;
+  Stars    *refcat;
+  SkyTable *sky;
+  struct stat filestat;
+
+  NAMED_PHOTCODE (TM_J, "2MASS_J");
+  NAMED_PHOTCODE (TM_H, "2MASS_H");
+  NAMED_PHOTCODE (TM_K, "2MASS_K");
+  if (photcode == TM_J) goto good_code;
+  if (photcode == TM_H) goto good_code;
+  if (photcode == TM_K) goto good_code;
+  Shutdown ("2MASS photcode not specified");
+
+good_code:
+  path = TWO_MASS_DIR_AS;
+  if (mode == 1) path = TWO_MASS_DIR_DR2;
+
+  // the accel.dat file has the raw filenames
+  // test if the file exists, or else try the .gz version
+  sky = get2mass_acc (patch, path, "accel.dat");
+  
+  Nstars = 0;
+  ALLOCATE (stars, Stars, 1);
+
+  for (i = 0; i < sky[0].Nregions; i++) {
+    refcat = NULL;
+    switch (mode) {
+      case 0:
+	// XXX put filename from table here
+	status = stat (sky[0].filename[i], &filestat);
+	if ((status == -1) && (errno == ENOENT)) {
+	  sprintf (gzname, "%s.gz", sky[0].filename[i]);
+	  refcat = get2mass_AS_data (&sky[0].regions[i], gzname, patch, photcode, &Nrefcat);
+	} else {
+	  refcat = get2mass_AS_rawdata (&sky[0].regions[i], sky[0].filename[i], patch, photcode, &Nrefcat);
+	}
+	if (VERBOSE) fprintf (stderr, "loaded %d stars from 2MASS (allsky) : %s\n", Nrefcat, sky[0].filename[i]);
+	break;
+      case 1:
+	refcat = get2mass_2DR_data (&sky[0].regions[i], sky[0].filename[i], patch, photcode, &Nrefcat);
+	if (VERBOSE) fprintf (stderr, "loaded %d stars from 2MASS (dr2)\n", Nrefcat);
+	break;
+    }
+
+    REALLOCATE (stars, Stars, MAX (1, Nstars + Nrefcat));
+    memcpy (&stars[Nstars], refcat, Nrefcat*sizeof(Stars));
+    Nstars += Nrefcat;
+
+    free (refcat);
+  }
+  
+  if (VERBOSE) fprintf (stderr, "loaded total %d stars from 2MASS\n", Nstars);
+  *NSTARS = Nstars;
+  return (stars);
+}  
+
+/* watch for patches which cross 0,360 boundary */
+SkyTable *get2mass_acc (SkyRegion *patch, char *path, char *accel) {
+
+  int Nregions, NREGIONS, Nrec;
+  char accelfile[1024], line[256], filename[128], datafile[256], **filenames;
+  FILE *f;
+  double Rs, Re, Ds, De;
+
+  SkyTable *sky;
+  SkyRegion *regions;
+
+  sprintf (accelfile, "%s/%s", path, accel);
+  f = fopen (accelfile, "r");
+  if (f == NULL) Shutdown ("can't read data from accelerator %s", accelfile);
+
+  Nregions = 0;
+  NREGIONS = 200;
+  ALLOCATE (regions, SkyRegion, NREGIONS);
+  ALLOCATE (filenames, char *, NREGIONS);
+
+  /* read in stars line-by-line */
+  while (scan_line (f, line) != EOF) {
+    stripwhite (line);
+    if (line[0] == 0) continue;
+    if (line[0] == '#') continue;
+    sscanf (line, "%s %lf %lf %lf %lf %d", filename, &Rs, &Re, &Ds, &De, &Nrec);
+    Rs *= 15.0;
+    Re *= 15.0;
+    if (Rs > patch[0].Rmax) continue;
+    if (Re < patch[0].Rmin) continue;
+    if (Ds > patch[0].Dmax) continue;
+    if (De < patch[0].Dmin) continue;
+    regions[Nregions].Rmin = Rs;
+    regions[Nregions].Rmax = Re;
+    regions[Nregions].Dmin = Ds;
+    regions[Nregions].Dmax = De;
+    regions[Nregions].childE = Nrec; // a cheat since 2MASS only has one depth
+    fprintf (stderr, "choosing: %10.6f - %10.6f, %10.6f - %10.6f\n", Rs, Re, Ds, De);
+
+    sprintf (datafile, "%s/%s", path, filename);
+    filenames[Nregions] = strcreate (datafile);
+
+    Nregions ++;
+    if (Nregions >= NREGIONS) {
+	NREGIONS += 20;
+	REALLOCATE (regions, SkyRegion, NREGIONS);
+	REALLOCATE (filenames, char *, NREGIONS);
+    }
+  }    
+  fclose (f);
+
+  ALLOCATE (sky, SkyTable, 1);
+  sky[0].regions = regions;
+  sky[0].filename = filenames;
+  sky[0].Nregions = Nregions;
+  return (sky);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_as.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_as.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_as.c	(revision 9206)
@@ -0,0 +1,128 @@
+# include "addstar.h"
+# include "2mass.h"
+
+/* unlike the DR2 data, the AS data is NOT fixed bytes/row 
+ * we need to handle fractional lines at the end of each read block
+ */
+
+/* read in chunks of ~16MB */
+# define NBYTE 0x1000000
+
+Stars *get2mass_AS_data (SkyRegion *region, char *filename, SkyRegion *patch, int photcode, int *nstars) {
+  
+  int Nstars, NSTARS, Nbyte, Nextra;
+  Stars *stars;
+  gzFile gf;
+  char *buffer;
+  char *p, *q, *tmp;
+  double RA, DEC;
+  double RA0, RA1, DEC0, DEC1;
+
+  ALLOCATE (buffer, char, NBYTE);
+
+  RA0  = MAX (patch[0].Rmin, UserPatch.Rmin);
+  RA1  = MIN (patch[0].Rmax, UserPatch.Rmax);
+  DEC0 = MAX (patch[0].Dmin, UserPatch.Dmin);
+  DEC1 = MIN (patch[0].Dmax, UserPatch.Dmax);
+
+  get2mass_setup (photcode);
+
+  gf = gzopen (filename, "rb");
+  if (gf == NULL) Shutdown ("can't read 2mass data file: %s", filename);
+
+  Nstars = 0;
+  NSTARS = 10000;
+  ALLOCATE (stars, Stars, NSTARS);
+
+  /* I want to add a seek-ahead test to find a good starting position in the file
+     this is very expensive using gzseek / gzread.  */
+
+  Nextra = 0;
+  while ((Nbyte = gzread (gf, &buffer[Nextra], NBYTE-Nextra)) != 0) {
+    if (Nbyte == -1) Shutdown ("error reading from gzipped file %s", filename);
+    Nbyte += Nextra;
+
+    if (VERBOSE) fprintf (stderr, ".");
+
+    /* find bounds on first complete line */
+    p = buffer;
+    q = memchr (p, '\n', Nbyte);
+    if (q == NULL) Shutdown ("incomplete line at end of file\n");
+
+    while (1) {
+
+      get2mass_coords (p, &RA, &DEC, Nbyte - (p - buffer));
+
+      /* skip stars which are outside desired region */
+      if (DEC > DEC1) goto skip_star;
+      if (DEC < DEC0) goto skip_star;
+      if (RA <  RA0)  goto skip_star;
+      if (RA >  RA1)  goto skip_star;
+
+      get2mass_star (&stars[Nstars], p, Nbyte - (p - buffer));
+
+      Nstars ++;
+      CHECK_REALLOCATE (stars, Stars, NSTARS, Nstars, 5000);
+
+    skip_star:
+      /* start of the next line */
+      tmp = p;
+      p = q + 1;
+      if (p - buffer == Nbyte) {
+	Nextra = 0;
+	break;
+      }
+      /* end of the next line */
+      q = memchr (p, '\n', Nbyte - (p - buffer));
+      if (q == NULL) {
+	Nextra = Nbyte - (p - buffer);
+	memmove (buffer, p, Nextra);
+	break;
+      } 
+    }
+  }
+  if (VERBOSE) fprintf (stderr, "\n");
+  
+  gzclose (gf);
+  free (buffer);
+  *nstars = Nstars;
+  return (stars);
+}
+
+/* this just scans along in the file.  file is sorted by dec, so we 
+   should be skipping large chunks - but we would need to have
+   the size from the accel file (won't fit in SkyRegion) and need
+   to use gzseek, if it exists.
+*/
+/* don't bother to seek ahead : position is not sufficiently predictable 
+   and gzseek is as expensive as gzread */
+/* 
+   Noffset = region[0].Nrec * (patch[0].DEC[0] + 90) / 180.0;
+   gzseek (gf, Noffset * NBYTE, SEEK_SET);
+   Nbyte = gzread (gf, buffer, NLINE*NBYTE);
+*/
+
+# if (0)
+    /** need to re-think this test **/
+    if (0) {
+      /* search for end of last complete line */
+      p = memrchr (buffer, '\n', Nbyte);
+      if (p == NULL) Shutdown ("incomplete line in at end of file\n");
+
+      /* search for start of last complete line */
+      /* last block may be only one line */
+      q = memrchr (buffer, '\n', (p - buffer - 1));
+      if (q == NULL) {
+	q = buffer;
+      } else {
+	q ++;
+      }
+
+      /* skip past block not yet in range */
+      RA = strtod (q, NULL);
+      ptr = skipNbounds (q, '|', 1, Nbyte - (q - buffer));
+      DEC = strtod (ptr, NULL);
+      if (DEC < DEC0) continue;
+    }
+
+# endif
Index: /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_as_raw.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_as_raw.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_as_raw.c	(revision 9206)
@@ -0,0 +1,89 @@
+# include "addstar.h"
+# include "2mass.h"
+
+/* unlike the DR2 data, the AS data is NOT fixed bytes/row 
+ * we need to handle fractional lines at the end of each read block
+ */
+
+/* read in chunks of ~16MB */
+# define NBYTE 0x1000000
+# define NBREC 330
+
+Stars *get2mass_AS_rawdata (SkyRegion *region, char *filename, SkyRegion *patch, int photcode, int *nstars) {
+  
+  int Nstars, NSTARS, Nbyte, Nextra;
+  Stars *stars;
+  FILE *f;
+  char *buffer;
+  char *p, *q, *tmp;
+  double RA, DEC;
+  double RA0, RA1, DEC0, DEC1;
+
+  ALLOCATE (buffer, char, NBYTE);
+
+  RA0  = MAX (patch[0].Rmin, UserPatch.Rmin);
+  RA1  = MIN (patch[0].Rmax, UserPatch.Rmax);
+  DEC0 = MAX (patch[0].Dmin, UserPatch.Dmin);
+  DEC1 = MIN (patch[0].Dmax, UserPatch.Dmax);
+
+  get2mass_setup (photcode);
+
+  f = fopen (filename, "r");
+  if (f == NULL) Shutdown ("can't read 2mass data file: %s", filename);
+  // test if this is a raw datafile or gzipped...
+
+  Nstars = 0;
+  NSTARS = 10000;
+  ALLOCATE (stars, Stars, NSTARS);
+
+  Nextra = 0;
+  while ((Nbyte = fread (&buffer[Nextra], 1, NBYTE-Nextra, f)) != 0) {
+    if (Nbyte == -1) Shutdown ("error reading from raw file %s", filename);
+    Nbyte += Nextra;
+
+    if (VERBOSE) fprintf (stderr, ".");
+
+    /* find bounds on first complete line */
+    p = buffer;
+    q = memchr (p, '\n', Nbyte);
+    if (q == NULL) Shutdown ("incomplete line at end of file\n");
+
+    while (1) {
+
+      get2mass_coords (p, &RA, &DEC, Nbyte - (p - buffer));
+
+      /* skip stars which are outside desired region */
+      if (DEC > DEC1) goto skip_star;
+      if (DEC < DEC0) goto skip_star;
+      if (RA <  RA0)  goto skip_star;
+      if (RA >  RA1)  goto skip_star;
+
+      get2mass_star (&stars[Nstars], p, Nbyte - (p - buffer));
+
+      Nstars ++;
+      CHECK_REALLOCATE (stars, Stars, NSTARS, Nstars, 5000);
+
+    skip_star:
+      /* start of the next line */
+      tmp = p;
+      p = q + 1;
+      if (p - buffer == Nbyte) {
+	Nextra = 0;
+	break;
+      }
+      /* end of the next line */
+      q = memchr (p, '\n', Nbyte - (p - buffer));
+      if (q == NULL) {
+	Nextra = Nbyte - (p - buffer);
+	memmove (buffer, p, Nextra);
+	break;
+      } 
+    }
+  }
+  if (VERBOSE) fprintf (stderr, "\n");
+  
+  fclose (f);
+  free (buffer);
+  *nstars = Nstars;
+  return (stars);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_dr2.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_dr2.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_dr2.c	(revision 9206)
@@ -0,0 +1,109 @@
+# include "addstar.h"
+# include "2mass.h"
+
+# define NBYTE 302
+# define NLINE 30000
+
+Stars *get2mass_2DR_data (SkyRegion *region, char *filename, SkyRegion *patch, int photcode, int *nstars) {
+  
+  int i, Nstars, NSTARS, Nbyte, Nline;
+  Stars *stars;
+  gzFile gf;
+  char *buffer;
+  char line[303];
+  double RA, DEC, J, H, K, dJ, dH, dK;
+  double RA0, RA1, DEC0, DEC1;
+
+  ALLOCATE (buffer, char, (NBYTE*NLINE));
+
+  if (region == NULL) exit (2);
+  if (patch == NULL) exit (3);
+
+  RA0  = MAX (patch[0].Rmin, UserPatch.Rmin);
+  RA1  = MIN (patch[0].Rmax, UserPatch.Rmax);
+  DEC0 = MAX (patch[0].Dmin, UserPatch.Dmin);
+  DEC1 = MIN (patch[0].Dmax, UserPatch.Dmax);
+
+  fprintf (stderr, "overlap: %f - %f, %f - %f\n", RA0, RA1, DEC0, DEC1);
+
+  gf = gzopen (filename, "rb");
+  if (gf == NULL) Shutdown ("can't read 2mass data file: %s", filename);
+
+  Nstars = 0;
+  NSTARS = 10000;
+  ALLOCATE (stars, Stars, NSTARS);
+
+  while ((Nbyte = gzread (gf, buffer, NLINE*NBYTE)) != 0) {
+    if (Nbyte ==  0) Shutdown ("error reading from gzipped file %s", filename);
+    if (Nbyte == -1) Shutdown ("error reading from gzipped file %s", filename);
+    if (Nbyte % NBYTE) Shutdown ("error reading complete line from gzipped file %s", filename);
+    Nline = Nbyte / NBYTE;
+
+    /* skip past block not yet in range */
+    sscanf (&buffer[NBYTE*(Nline - 1)], "%lf %lf", &RA, &DEC);
+    if (DEC < DEC0) continue;
+
+    memcpy (line, &buffer[NBYTE*(Nline-1)], NBYTE);
+    line[302] = 0;
+
+    for (i = 0; i < Nline; i++) {
+      
+      dparse (&RA,  1, &buffer[NBYTE*i+  0]);
+      dparse (&DEC, 2, &buffer[NBYTE*i+  0]);
+
+      /* dr2 is nicely sorted in dec order */
+      if (DEC > DEC1) goto finished;
+      if (DEC < DEC0) continue;
+      if (RA <  RA0) continue;
+      if (RA >  RA1) continue;
+
+      stars[Nstars].R  	  = RA;
+      stars[Nstars].D  	  = DEC;
+      stars[Nstars].t  	  = short_date_to_sec (&buffer[NBYTE*i + 164]);
+      stars[Nstars].found = -1;
+
+      if (photcode == TM_J) {
+	dparse (&J,  1, &buffer[NBYTE*i + 53]);
+	dparse (&dJ, 2, &buffer[NBYTE*i + 53]);
+	stars[Nstars].M    = J;
+	stars[Nstars].dM   = dJ;
+	stars[Nstars].code = TM_J;
+      }
+      if (photcode == TM_H) {
+	dparse (&H,  1, &buffer[NBYTE*i + 72]);
+	dparse (&dH, 2, &buffer[NBYTE*i + 72]);
+	stars[Nstars].M    = H;
+	stars[Nstars].dM   = dH;
+	stars[Nstars].code = TM_H;
+      }
+      if (photcode == TM_K) {
+	dparse (&K,  1, &buffer[NBYTE*i + 91]);
+	dparse (&dK, 2, &buffer[NBYTE*i + 91]);
+	stars[Nstars].M    = K;
+	stars[Nstars].dM   = dK;
+	stars[Nstars].code = TM_K;
+      }
+      Nstars ++;
+      CHECK_REALLOCATE (stars, Stars, NSTARS, Nstars, 5000);
+    }
+  }  
+finished:
+  gzclose (gf);
+  free (buffer);
+
+  *nstars = Nstars;
+  return (stars);
+}
+
+/* this just scans along in the file.  file is sorted by dec, so we should be
+   skipping large chunks - but we would need to have the size from the accel
+   file in (and need to use gzseek, if the data is compressed)
+*/
+/* don't bother to seek ahead : position is not sufficiently predictable 
+   and gzseek is as expensive as gzread */
+/* 
+   Noffset = region[0].Nrec * (patch[0].Dmin + 90) / 180.0;
+   gzseek (gf, Noffset * NBYTE, SEEK_SET);
+   Nbyte = gzread (gf, buffer, NLINE*NBYTE);
+*/
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_ops.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_ops.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/get2mass_ops.c	(revision 9206)
@@ -0,0 +1,242 @@
+# include "addstar.h"
+# include "2mass.h"
+
+static int FilterSkip;
+static int TimeSkip;
+static int Qentry;
+static int Photcode;
+
+int get2mass_setup (int photcode) {
+
+  NAMED_PHOTCODE (TM_J, "2MASS_J");
+  NAMED_PHOTCODE (TM_H, "2MASS_H");
+  NAMED_PHOTCODE (TM_K, "2MASS_K");
+
+  FilterSkip = TimeSkip = Qentry = 0;
+  Photcode = photcode;
+  if (photcode == -1) return TRUE;
+
+  if (photcode == TM_J) {
+      FilterSkip = 6;
+      TimeSkip = 28;
+      Qentry   = 0;
+  }
+  if (photcode == TM_H) {
+      FilterSkip = 10;
+      TimeSkip = 24;
+      Qentry   = 1;
+  }
+  if (photcode == TM_K) {
+      FilterSkip = 14;
+      TimeSkip = 20;
+      Qentry   = 2;
+  }
+  if (!FilterSkip) Shutdown ("invalid photcode %s", GetPhotcodeNamebyCode(photcode));
+  return TRUE;
+}
+
+// fill in the data for a single star.  takes a pointer to the start of the line
+int get2mass_star (Stars *star, char *line, int Nmax) {
+
+  char *ptr, qc;
+  double M, dM;
+  e_time time;
+
+  ptr = skipNbounds (line, '|', FilterSkip, Nmax);
+  if (ptr == NULL) Shutdown ("format error in 2mass");
+  M  = strtod (ptr, NULL);
+  ptr = skipNbounds (ptr, '|', 1, Nmax - (ptr - line));
+  dM = strtod (ptr, NULL);
+  time = get2mass_time (ptr, TimeSkip, Nmax - (ptr - line));
+
+  /* filter on the ph_qual flag for this filter (field 19) */
+  if (SELECT_2MASS_QUALITY != NULL) {
+    ptr = skipNbounds (line, '|', 18, Nmax);
+    qc  = ptr[Qentry];
+    if (strchr (SELECT_2MASS_QUALITY, qc) == NULL) return (FALSE);
+  }
+
+  star[0].M     = M;
+  star[0].dM    = dM;
+  star[0].code  = Photcode;
+  star[0].t     = time;
+  star[0].found = -1;
+
+  return TRUE;
+}
+
+// fill in the data for a JHK triplet star.  takes a pointer to the start of the line
+int get2mass_3star (Stars *star, char *line, int Nmax) {
+
+  char *ptr;
+  char Jquality, Hquality, Kquality;
+  double J, dJ, H, dH, K, dK;
+  e_time time;
+
+  ptr = line;
+  if (ptr == NULL) Shutdown ("format error in 2mass");
+
+  ptr = skipNbounds (ptr, '|', 6, Nmax - (ptr - line));
+  J  = strtod (ptr, NULL);
+  ptr = skipNbounds (ptr, '|', 1, Nmax - (ptr - line));
+  dJ = strtod (ptr, NULL);
+
+  ptr = skipNbounds (ptr, '|', 3, Nmax - (ptr - line));
+  H  = strtod (ptr, NULL);
+  ptr = skipNbounds (ptr, '|', 1, Nmax - (ptr - line));
+  dH = strtod (ptr, NULL);
+
+  ptr = skipNbounds (ptr, '|', 3, Nmax - (ptr - line));
+  K  = strtod (ptr, NULL);
+  ptr = skipNbounds (ptr, '|', 1, Nmax - (ptr - line));
+  dK = strtod (ptr, NULL);
+
+  /* filter on the ph_qual flag for this filter (field 19) */
+  if (SELECT_2MASS_QUALITY != NULL) {
+    ptr = skipNbounds (ptr, '|', 3, Nmax - (ptr - line));
+    Jquality = (strchr (SELECT_2MASS_QUALITY, ptr[0]) != NULL);
+    Hquality = (strchr (SELECT_2MASS_QUALITY, ptr[1]) != NULL);
+    Kquality = (strchr (SELECT_2MASS_QUALITY, ptr[2]) != NULL);
+    time = get2mass_time (ptr, 18, Nmax - (ptr - line));
+  } else {
+    time = get2mass_time (ptr, 20, Nmax - (ptr - line));
+  }
+
+  star[0].M     = J;
+  star[0].dM    = dJ;
+  star[0].code  = TM_J;
+  star[0].t     = time;
+  star[0].found = -1;
+
+  star[1].M     = H;
+  star[1].dM    = dH;
+  star[1].code  = TM_H;
+  star[1].t     = time;
+  star[1].found = -1;
+
+  star[2].M     = K;
+  star[2].dM    = dK;
+  star[2].code  = TM_K;
+  star[2].t     = time;
+  star[2].found = -1;
+
+  return TRUE;
+}
+
+// fill in the coords for a single star.  takes a pointer to the start of the line
+int get2mass_coords (char *line, double *R, double *D, int Nmax) {
+
+  char *ptr;
+
+  *R = strtod (line, NULL);
+  ptr = skipNbounds (line, '|', 1, Nmax);
+  *D = strtod (ptr, NULL);
+  if (*D > 90) Shutdown ("weird DEC value: something is wrong");
+
+  return TRUE;
+}
+
+// this function retrieves the time from the DATE field
+e_time get2mass_date (char *ptr, int Nbound, int Nmax) {
+
+  e_time time;
+  char *p, *end;
+
+  p = skipNbounds (ptr, '|', Nbound, Nmax);
+  if (p == NULL) Shutdown ("format error in 2mass");
+  end = memchr (p, '|', Nmax - (p - ptr));
+  if (end == NULL) Shutdown ("format error in 2mass");
+  *end = 0;
+  time = date_to_sec (ptr);
+  *end = '|';
+
+  return (time);
+}
+
+// this function retrieves the time from the JDATE field (%12.4f)
+e_time get2mass_time (char *ptr, int Nbound, int Nmax) {
+
+  e_time time;
+  double jd;
+  char *p, *end;
+
+  p = skipNbounds (ptr, '|', Nbound, Nmax);
+  if (p == NULL) Shutdown ("format error in 2mass");
+  end = memchr (p, '|', Nmax - (p - ptr));
+  if (end == NULL) Shutdown ("format error in 2mass");
+  *end = 0;
+  jd = strtod (p, NULL);
+  time = jd_to_sec (jd);
+  *end = '|';
+
+  return (time);
+}
+
+/* return a pointer to the first char after Nbound of value bound */
+char *skipNbounds (char *line, char bound, int Nbound, int Nbyte) {
+
+  int i;
+  char *p, *q;
+
+  p = line;
+  for (i = 0; i < Nbound; i++) {
+    q = memchr (p, bound, Nbyte - (p - line));
+    if (q == NULL) return (NULL);
+    p = q + 1;
+    if (p - line == Nbyte) return (NULL);
+  }
+  return (p);
+}
+  
+/* watch for patches which cross 0,360 boundary */
+SkyTable *load2mass_acc (char *path, char *accel) {
+
+  int Nregions, NREGIONS, Nrec;
+  char accelfile[1024], line[256], filename[128], datafile[256], **filenames;
+  FILE *f;
+  double Rs, Re, Ds, De;
+
+  SkyTable *sky;
+  SkyRegion *regions;
+
+  sprintf (accelfile, "%s/%s", path, accel);
+  f = fopen (accelfile, "r");
+  if (f == NULL) Shutdown ("can't read data from accelerator %s", accelfile);
+
+  Nregions = 0;
+  NREGIONS = 200;
+  ALLOCATE (regions, SkyRegion, NREGIONS);
+  ALLOCATE (filenames, char *, NREGIONS);
+
+  /* read in stars line-by-line */
+  while (scan_line (f, line) != EOF) {
+    stripwhite (line);
+    if (line[0] == 0) continue;
+    if (line[0] == '#') continue;
+    sscanf (line, "%s %lf %lf %lf %lf %d", filename, &Rs, &Re, &Ds, &De, &Nrec);
+    Rs *= 15.0;
+    Re *= 15.0;
+    regions[Nregions].Rmin = Rs;
+    regions[Nregions].Rmax = Re;
+    regions[Nregions].Dmin = Ds;
+    regions[Nregions].Dmax = De;
+    regions[Nregions].childE = Nrec; // a cheat since 2MASS only has one depth
+
+    sprintf (datafile, "%s/%s", path, filename);
+    filenames[Nregions] = strcreate (datafile);
+
+    Nregions ++;
+    if (Nregions >= NREGIONS) {
+	NREGIONS += 20;
+	REALLOCATE (regions, SkyRegion, NREGIONS);
+	REALLOCATE (filenames, char *, NREGIONS);
+    }
+  }    
+  fclose (f);
+
+  ALLOCATE (sky, SkyTable, 1);
+  sky[0].regions = regions;
+  sky[0].filename = filenames;
+  sky[0].Nregions = Nregions;
+  return (sky);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/getgsc.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/getgsc.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/getgsc.c	(revision 9206)
@@ -0,0 +1,85 @@
+# include "addstar.h"
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+static short GSC_M;
+
+Stars *getgsc (SkyRegion *patch, int *NSTARS) {
+  
+  int i, Ngsc, Nstars; 
+  Stars *gsc;
+  Stars *stars;
+  SkyList *skylist;
+  SkyTable *sky;
+
+  NAMED_PHOTCODE (GSC_M, "GSC_M");
+
+  /* load regions from GSC table, restrict to patch */
+  sky = SkyTableFromGSC (GSCFILE, SKY_DEPTH_HST, VERBOSE);
+  SkyTableSetFilenames (sky, GSCDIR, "cpt");
+  skylist = SkyListByPatch (sky, -1, patch);
+  
+  Nstars = 0;
+  ALLOCATE (stars, Stars, 1);
+  
+  for (i = 0; i < skylist[0].Nregions; i++) {
+    gsc = rd_gsc (skylist[0].filename[i], &Ngsc);
+
+    REALLOCATE (stars, Stars, MAX (1, Nstars + Ngsc));
+    memcpy (&stars[Nstars], gsc, Ngsc*sizeof(Stars));
+    Nstars += Ngsc;
+
+    free (gsc);
+  }
+  SkyTableFree (sky);
+
+  if (VERBOSE) fprintf (stderr, "%d stars from HST GSC\n", Nstars);
+  *NSTARS = Nstars;
+  return (stars);
+}  
+
+Stars *rd_gsc (char *filename, int *nstars) {
+  
+  int i, NSTARS, Nstars, Nbytes, nbytes, Nline, Nbyte;
+  char *buffer;
+  FILE *f;
+  Stars *stars;
+
+  Nstars = 0;
+  NSTARS = 1000;
+  ALLOCATE (stars, Stars, NSTARS);
+
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find catalog file %s\n", filename);
+    exit (2);
+  }
+  
+  Nbytes = BLOCK*BYTES_STAR;
+  ALLOCATE (buffer, char, Nbytes);
+  while ((nbytes = fread (buffer, 1, Nbytes, f)) > 0) {
+    Nline = nbytes / BYTES_STAR;
+    for (i = 0; i < Nline; i++) {
+      Nbyte = i*BYTES_STAR;
+      dparse (&stars[Nstars].R, 1, &buffer[Nbyte]);
+      dparse (&stars[Nstars].D, 2, &buffer[Nbyte]);
+      if (stars[Nstars].R < UserPatch.Rmin) continue;
+      if (stars[Nstars].R > UserPatch.Rmax) continue;
+      if (stars[Nstars].D < UserPatch.Dmin) continue;
+      if (stars[Nstars].D > UserPatch.Dmax) continue;
+
+      dparse (&stars[Nstars].M, 3, &buffer[Nbyte]);
+      stars[Nstars].dM 	  = NO_ERR;
+      stars[Nstars].t  	  = 0;
+      stars[Nstars].code  = GSC_M;
+      stars[Nstars].found = -1;
+      Nstars ++;
+      CHECK_REALLOCATE (stars, Stars, NSTARS, Nstars, 1000);
+    }
+  }
+  free (buffer);
+  REALLOCATE (stars, Stars, Nstars);
+  *nstars = Nstars;
+  return (stars);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/gettycho.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/gettycho.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/gettycho.c	(revision 9206)
@@ -0,0 +1,133 @@
+# include "addstar.h"
+# define NZONE 180
+# define NBYTE 207
+# define NITEM 100
+
+static SkyTable *tychoTable = NULL;
+
+Stars *gettycho (SkyRegion *catstats, int photcode, int *nstars) {
+
+  int i, j, nitems;
+  char *buffer;
+  char filename[128], *line;
+  FILE *f;
+  int NTYCHO, Ntycho;
+  int firstRow, firstByte;
+  short int TYCHO_B, TYCHO_V;
+  e_time TychoEpoch;
+  SkyRegion *region;
+  SkyList  *skylist;
+  Stars *stars;
+
+  /* require photcode */
+  NAMED_PHOTCODE (TYCHO_B, "TYCHO_B");
+  NAMED_PHOTCODE (TYCHO_V, "TYCHO_V");
+  if (photcode == TYCHO_B) goto good_code;
+  if (photcode == TYCHO_V) goto good_code;
+  Shutdown ("TYCHO photcode not specified");
+good_code:
+
+  fprintf (stderr, "loading TYCHO catalog\n");
+
+  /* load tycho index file into sky table */
+  if (tychoTable == NULL) {
+    sprintf (filename, "%s/index.dat", TYCHO_DIR);
+    tychoTable = SkyTableFromTychoIndex (filename, VERBOSE);
+    if (tychoTable == NULL) {
+      fprintf (stderr, "ERROR: problem loading tycho data\n");
+      exit (2);
+    }
+  }
+
+  /* identify tycho region files overlapping the requested region */
+  skylist = SkyListByPatch (tychoTable, 2, catstats);
+
+  /* open the Tycho catalog file */
+  sprintf (filename, "%s/tycho.dat", TYCHO_DIR);
+  f = fopen (filename, "r");
+
+  Ntycho = 0;
+  NTYCHO = 5000;
+  ALLOCATE (stars, Stars, NTYCHO);
+
+  ALLOCATE (buffer, char, NITEM*NBYTE);
+
+  TychoEpoch = date_to_sec ("1991/04/02,07:30:00");
+
+  for (i = 0; i < skylist[0].Nregions; i++) {
+    region = skylist[0].regions[i];
+    if (VERBOSE) fprintf (stderr, "section %d (%f - %f, %f - %f)...", i, 
+			  region[0].Rmin, region[0].Rmax, region[0].Dmin, region[0].Dmax);
+
+    firstRow  = atoi (region[0].name);
+    firstByte = firstRow * NBYTE;
+    fseek (f, firstByte, SEEK_SET);
+
+    while (1) {
+      nitems = fread (buffer, NBYTE, NITEM, f);
+      if (nitems == 0) break;
+
+      for (j = 0; j < nitems; j++) {
+	line = &buffer[j*NBYTE];
+	stars[Ntycho].R = atof (&line[15]);
+	stars[Ntycho].D = atof (&line[28]);
+
+	if (stars[Ntycho].R < region[0].Rmin) goto next_section;
+	if (stars[Ntycho].R > region[0].Rmax) goto next_section;
+	if (stars[Ntycho].D < region[0].Dmin) goto next_section;
+	if (stars[Ntycho].D > region[0].Dmax) goto next_section;
+
+	if (stars[Ntycho].R < UserPatch.Rmin) continue;
+	if (stars[Ntycho].R > UserPatch.Rmax) continue;
+	if (stars[Ntycho].D < UserPatch.Dmin) continue;
+	if (stars[Ntycho].D > UserPatch.Dmax) continue;
+
+	stars[Ntycho].dR  = 1000 * atof (&line[57]);
+	stars[Ntycho].dD  = 1000 * atof (&line[64]);
+
+	/* XXX : we need to apply uR,uD to R,D to advance to 2000.0 */
+	stars[Ntycho].uR  = atof (&line[41]);
+	stars[Ntycho].uD  = atof (&line[49]);
+
+	stars[Ntycho].duR = atof (&line[69]);
+	stars[Ntycho].duD = atof (&line[75]);
+	
+	stars[Ntycho].P   = 0;
+	stars[Ntycho].dP  = 0;
+
+	/* Tycho uses J2000 equinox and 1991.25 epoch for coordinates */
+	/* the magnitudes have no temporal information */ 
+	stars[Ntycho].t   = TychoEpoch;
+	stars[Ntycho].found = -1;
+      
+	/* one pass of addstar does either r or b */
+	if (photcode == TYCHO_B) {
+	  stars[Ntycho].M     = atof (&line[110]);
+	  stars[Ntycho].dM    = atof (&line[117]);
+	  stars[Ntycho].code  = TYCHO_B;
+	} else {
+	  stars[Ntycho].M     = atof (&line[123]);
+	  stars[Ntycho].dM    = atof (&line[130]);
+	  stars[Ntycho].code  = TYCHO_V;
+	}	
+      
+	Ntycho ++;
+	CHECK_REALLOCATE (stars, Stars, NTYCHO, Ntycho, 5000);
+      }
+
+      if (nitems != NITEM) break;
+    }
+  next_section:
+    if (VERBOSE) fprintf (stderr, "%d stars\n", Ntycho);
+  }
+  fclose (f);
+
+  SkyListFree (skylist, FALSE);
+
+  free (buffer);
+  REALLOCATE (stars, Stars, MAX (1, Ntycho));
+
+  *nstars = Ntycho;
+  if (VERBOSE) fprintf (stderr, "%d stars from Tycho\n", Ntycho);
+  return (stars);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/getusno.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/getusno.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/getusno.c	(revision 9206)
@@ -0,0 +1,159 @@
+# include "addstar.h"
+# define NZONE 24
+# define NBYTE  4
+# define NELEM  3
+
+Stars *getusno (SkyRegion *catstats, int photcode, int *nstars) {
+
+  long int offset;
+  int i, bin, first, last, nitems, Nitems, Nbins, Nstars;
+  float hours[100];
+  int start[100], number[100], *buffer, *buf;
+  char filename[128];
+  FILE *f;
+  int iRA0, iRA1, iDEC0, iDEC1;
+  double dec;
+  int spd, spd_start, spd_end;
+  int NUSNO, Nusno;
+  Stars *stars;
+  short int USNO_RED, USNO_BLUE;
+
+  /* require photcode */
+  NAMED_PHOTCODE (USNO_RED, "USNO_RED");
+  NAMED_PHOTCODE (USNO_BLUE, "USNO_BLUE");
+  if (photcode == USNO_RED) goto good_code;
+  if (photcode == USNO_BLUE) goto good_code;
+  Shutdown ("USNO photcode not specified");
+good_code:
+
+  /* identify ra & dec range of interest */
+  /* note: the use of UserPatch to restrict here limits general utility of function */
+  iRA0  =  MAX (catstats[0].Rmin, UserPatch.Rmin) * 360000.0;
+  iRA1  =  MIN (catstats[0].Rmax, UserPatch.Rmax) * 360000.0;
+  iDEC0 = (MAX (catstats[0].Dmin, UserPatch.Dmin) + 90.0) * 360000.0;
+  iDEC1 = (MIN (catstats[0].Dmax, UserPatch.Dmax) + 90.0) * 360000.0;
+  
+  /* data is organized in south-pole distance zones */
+  spd_start = (int)((catstats[0].Dmin + 90) / 7.5) * 75.0;
+  dec = (catstats[0].Dmax + 90) / 7.5;
+  if (dec > (int)(dec)) {
+    spd_end =   (int)(1 + (catstats[0].Dmax + 90) / 7.5) * 75.0;
+  } else {
+    spd_end =   (int)(0 + (catstats[0].Dmax + 90) / 7.5) * 75.0;
+  }
+
+  Nusno = 0;
+  NUSNO = 5000;
+  ALLOCATE (stars, Stars, NUSNO);
+
+  for (spd = spd_start; spd < spd_end; spd += 75) {
+    
+    /* load accelerator file */
+    sprintf (filename, "%s/zone%04d.acc", USNO_A_DIR, spd); 
+    if (VERBOSE) fprintf (stderr, "reading from %s\n", filename);
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open accelerator file %s\n", filename);
+      exit (1);  
+    }
+    for (i = 0; fscanf (f, "%f %d %d", &hours[i], &start[i], &number[i]) != EOF; i++);
+    Nbins = i;
+    fclose (f);
+    
+    first = catstats[0].Rmin / 3.75;
+    if ((catstats[0].Rmax / 3.75) == (int) (catstats[0].Rmax / 3.75)) 
+      last  = catstats[0].Rmax / 3.75;
+    else 
+      last  = 1 + catstats[0].Rmax / 3.75;
+
+    if ((first > Nbins) || (last > Nbins)) {
+      fprintf (stderr, "ERROR: RA out of range\n");
+      exit (1);
+    }
+    
+    /* open data file */
+    sprintf (filename, "%s/zone%04d.cat", USNO_A_DIR, spd);
+    if (VERBOSE) fprintf (stderr, "reading from %s\n", filename);
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open file %s\n", filename);
+      exit (1);
+    }
+
+    /** USNO-A consists of 3 x 4byte (int) records **/
+    /* advance file pointer to first slice */
+    offset = NELEM*NBYTE*(start[first] - 1);
+    fseek (f, offset, SEEK_SET);
+
+    /* sum the number of stars in data segment of interest */
+    Nstars = 0;
+    for (bin = first; bin < last; bin++) {
+      Nstars += number[bin];
+    }
+    Nitems = NELEM*Nstars;  
+    /* number of blocks to read -- we need to use Fread for byte-swapping read */
+
+    /* read stars from catalog */
+    ALLOCATE (buffer, int, Nitems);
+    nitems = Fread (buffer, NBYTE, Nitems, f, "int");
+    if (nitems != Nitems) {
+      fprintf (stderr, "ERROR: failure reading data from file %s\n", filename);
+      exit (1);
+    }
+
+    /* extract the data of interest from segment (in RA and DEC range) */
+    buf = buffer;
+    for (i = 0; i < Nstars; i++, buf += NELEM) {
+      if (buf[0] < iRA0) continue;
+      if (buf[0] > iRA1) continue;
+      if (buf[1] < iDEC0) continue;
+      if (buf[1] > iDEC1) continue;
+
+      bzero (&stars[Nusno], sizeof(Stars));
+      stars[Nusno].R     = buf[0]/360000.0;
+      stars[Nusno].D     = buf[1]/360000.0 - 90.0;
+      stars[Nusno].dM    = NO_ERR;
+      stars[Nusno].t     = 0;
+      stars[Nusno].found = -1;
+
+      /* one pass of addstar does either r or b */
+      if (photcode == USNO_RED) {
+	stars[Nusno].code  = USNO_RED;
+	stars[Nusno].M     = fabs (0.1*(buf[2] - 1000*((int)(buf[2]/1000))));
+      } 
+      if (photcode == USNO_BLUE) {	
+	stars[Nusno].code  = USNO_BLUE;
+	stars[Nusno].M     = fabs (0.1*((int)(buf[2] - 1000000*((int)(buf[2]/1000000))) / 1000));
+      }
+      Nusno ++;
+      CHECK_REALLOCATE (stars, Stars, NUSNO, Nusno, 5000);
+    }
+    free (buffer);
+    fclose (f);
+  }
+  REALLOCATE (stars, Stars, Nusno);
+
+  *nstars = Nusno;
+  if (VERBOSE) fprintf (stderr, "%d stars from USNO 1.0\n", Nusno);
+  return (stars);
+}
+
+
+
+
+/* these entries are legacy code incase you want to read from one of the USNO CDRoms
+int SPDzone[]  = {0, 75, 450, 375, 1500, 1650, 300, 1425, 1725, 525, 1275, 225, 675, 150, 600, 1575, 750, 975, 900, 1050, 1125, 1200, 825, 1350};
+int USNOdisk[] = {1,  1,   1,   2,    2,    2,   3,    3,    3,   4,    4,   5,   5,   6,   6,    6,   7,   7,   8,    8,    9,    9,  10,   10};
+
+    disk = -1;
+    for (i = 0; i < NZONE; i++) {
+      if (spd == SPDzone[i]) 
+	disk = USNOdisk[i];
+    }
+    if (disk < 0) {
+      fprintf (stderr, "ERROR: can't find cdrom for spd %d\n",  spd);
+      exit (1);
+    }
+
+*/
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/getusnob.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/getusnob.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/getusnob.c	(revision 9206)
@@ -0,0 +1,178 @@
+# include "addstar.h"
+# define NBYTE   4
+# define NELEM  20
+
+Stars *getusnob (SkyRegion *catstats, int photcode, int *nstars) {
+
+  long int offset;
+  int i, bin, first, last, nitems, Nitems, Nbins;
+  float hours[100];
+  int start[100], number[100], *buffer, *buf;
+  char filename[128];
+  FILE *f;
+  double dec;
+  float m1, m2, mag;
+  int iDEC0, iDEC1, iRA0, iRA1;
+  int spd, spd_start, spd_end;
+  int NUSNO, Nusno, Nstars;
+  short int USNO_RED, USNO_BLUE;
+  e_time USNOepoch;
+  Stars *stars;
+
+  /* require photcode */
+  NAMED_PHOTCODE (USNO_RED, "USNO_RED");
+  NAMED_PHOTCODE (USNO_BLUE, "USNO_BLUE");
+  if (photcode == USNO_RED) goto good_code;
+  if (photcode == USNO_BLUE) goto good_code;
+  Shutdown ("USNO photcode not specified");
+good_code:
+
+  fprintf (stderr, "loading USNO-B 1.0\n");
+
+  /* identify ra & dec range of interest */
+  /* note: the use of UserPatch to restrict here limits general utility of function */
+  iRA0  =  MAX (catstats[0].Rmin, UserPatch.Rmin) * 360000.0;
+  iRA1  =  MIN (catstats[0].Rmax, UserPatch.Rmax) * 360000.0;
+  iDEC0 = (MAX (catstats[0].Dmin, UserPatch.Dmin) + 90.0) * 360000.0;
+  iDEC1 = (MIN (catstats[0].Dmax, UserPatch.Dmax) + 90.0) * 360000.0;
+  /* note that iDECn is in SPD, while both have units of 0.01 degrees */
+  
+  /* data is organized in south-pole distance zones, 1 deg per direction, 0.1 deg per file */
+  spd_start = (int)(10*(catstats[0].Dmin + 90));
+  dec = 10*(catstats[0].Dmax + 90);
+  if (dec > (int)(dec)) {
+    spd_end =   (int)(1 + 10*(catstats[0].Dmax + 90));
+  } else {
+    spd_end =   (int)(0 + 10*(catstats[0].Dmax + 90));
+  }
+
+  Nusno = 0;
+  NUSNO = 5000;
+  ALLOCATE (stars, Stars, NUSNO);
+
+  for (spd = spd_start; spd < spd_end; spd ++) {
+    
+    /* load accelerator file */
+    sprintf (filename, "%s/%03d/b%04d.acc", USNO_B_DIR, (int)(spd/10), spd); 
+    if (VERBOSE) fprintf (stderr, "reading from %s\n", filename);
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open accelerator file %s\n", filename);
+      exit (1);  
+    }
+    for (i = 0; fscanf (f, "%f %d %d", &hours[i], &start[i], &number[i]) != EOF; i++);
+    Nbins = i;
+    fclose (f);
+    
+    first = catstats[0].Rmin / 3.75;
+    if ((catstats[0].Rmax / 3.75) == (int) (catstats[0].Rmax / 3.75)) 
+      last  = catstats[0].Rmax / 3.75;
+    else 
+      last  = 1 + catstats[0].Rmax / 3.75;
+
+    if ((first > Nbins) || (last > Nbins)) {
+      fprintf (stderr, "ERROR: RA out of range\n");
+      exit (1);
+    }
+    
+    /* open data file */
+    sprintf (filename, "%s/%03d/b%04d.cat", USNO_B_DIR, (int)(spd/10), spd); 
+    if (VERBOSE) fprintf (stderr, "reading from %s\n", filename);
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open file %s\n", filename);
+      exit (1);
+    }
+
+    /** USNO-B consists of 20 x 4byte (int) records **/
+    /* advance file pointer to first slice */
+    offset = NELEM*NBYTE*(start[first] - 1);
+    fseek (f, offset, SEEK_SET);
+
+    /* sum the number of stars in data segment of interest */
+    Nstars = 0;
+    for (bin = first; bin < last; bin++) {
+      Nstars += number[bin];
+    }
+    Nitems = NELEM*Nstars;  
+    /* number of blocks to read -- we need to use Fread for byte-swapping read */
+
+    /* allocate space for stars in segment and read */
+    ALLOCATE (buffer, int, Nitems);
+    // data has the WRONG byte order?
+    // nitems = Fread (buffer, sizeof(int), Nitems, f, "int");
+    nitems = fread (buffer, NBYTE, Nitems, f);
+    if (nitems != Nitems) {
+      fprintf (stderr, "ERROR: failure reading data from file %s\n", filename);
+      exit (1);
+    }
+
+    USNOepoch = date_to_sec ("2000/01/01,00:00:00");
+
+    buf = buffer;
+    /* print out data from slice within RA and DEC range */
+    for (i = 0; i < Nstars; i++, buf += NELEM) {
+      if (buf[0] < iRA0) continue;
+      if (buf[0] > iRA1) continue;
+      if (buf[1] < iDEC0) continue;
+      if (buf[1] > iDEC1) continue;
+      
+      /* USNO coords are reported for J2000 / epoch 2000.0 */
+      /* extract the basic stellar data */
+      bzero (&stars[Nusno], sizeof(Stars));
+      stars[Nusno].R   = buf[0]/360000.0;
+      stars[Nusno].D   = buf[1]/360000.0 - 90.0;
+
+      /* XXX uR cos(D) or just uR ??? */
+      stars[Nusno].uR  = 2.0 * ((buf[2]       % 10000) - 5000);
+      stars[Nusno].uD  = 2.0 * ((buf[2]/10000 % 10000) - 5000);
+
+      stars[Nusno].duR = (buf[3]      % 1000);
+      stars[Nusno].duD = (buf[3]/1000 % 1000);
+
+      stars[Nusno].dR  = 0.001 * (buf[4]      % 1000);
+      stars[Nusno].dD  = 0.001 * (buf[4]/1000 % 1000);
+
+      stars[Nusno].P   = 0;
+      stars[Nusno].dP  = 0;
+
+      /* USNO magnitude errors are reported as a fixed 0.3 mag */
+      stars[Nusno].dM    = 0.3;
+      stars[Nusno].found = -1;
+      
+      /* USNO-B uses J2000 equinox and 2000.0 epoch for coordinates */
+      /* the magnitudes have no temporal information */ 
+      stars[Nusno].t     = USNOepoch;
+
+      /* one pass of addstar does either r or b */
+      if (photcode == USNO_BLUE) {
+	m1 = fabs(0.01 * (buf[5] % 10000)); /* 1st blue mag */
+	m2 = fabs(0.01 * (buf[7] % 10000)); /* 1st blue mag */
+	stars[Nusno].code  = USNO_BLUE;
+      } else {
+	m1 = fabs(0.01 * (buf[6] % 10000)); /* 1st red mag */
+	m2 = fabs(0.01 * (buf[8] % 10000)); /* 2nd red mag */
+	stars[Nusno].code  = USNO_RED;
+      }	
+
+      /* if two mags are available, get an average */
+      if (m1 && m2) {
+	mag = 0.5*(m1 + m2);
+      } else {
+	mag = (m1) ? m1 : m2;
+      }
+      stars[Nusno].M = (mag == 0.0) ? 32.0 : mag;
+
+      Nusno ++;
+      CHECK_REALLOCATE (stars, Stars, NUSNO, Nusno, 5000);
+    }
+    free (buffer);
+    fclose (f);
+  }
+
+  REALLOCATE (stars, Stars, MAX (1, Nusno));
+
+  *nstars = Nusno;
+  if (VERBOSE) fprintf (stderr, "%d stars from USNO-B 1.0\n", Nusno);
+  return (stars);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/gimages.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/gimages.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/gimages.c	(revision 9206)
@@ -0,0 +1,170 @@
+# include "addstar.h"
+void SetImageCorners (double *X, double *Y, Image *image);
+
+/* given image, find catalog images which overlap it */
+Image *gimages (FITS_DB *db, Image *image, Coords *mosaic, int *Npimage) {
+  
+  int i, j, k, addtolist;
+  int NPIMAGE, npimage, Ntimage;
+  Image *timage, *pimage;
+  Coords tcoords;
+  double r, d, x, y;
+  double Xb[5], Yb[5], Xi[5], Yi[5], Xo[5], Yo[5];  /* image and original corners */
+  double zeropt;
+
+  /* if image.db is opened successfully, f will not be NULL.
+     if image.db is empty, dbstate will be LCK_EMPTY 
+     if image.db is not locked & opened successfully, we will not reach here!
+  */
+  if (db[0].dbstate == LCK_EMPTY) {
+    *Npimage = 0;
+    return (NULL);
+  }
+
+  /* read entire db table (use block read eventually?) */
+  if (!dvo_image_load (db, VERBOSE, FORCE_READ)) {
+    Shutdown ("can't read image catalog %s", db[0].filename);
+  }
+  timage = gfits_table_get_Image (&db[0].ftable, &Ntimage, &db[0].swapped);
+
+  gfits_scan (&db[0].header, "ZERO_PT", "%lf", 1, &zeropt);
+  if (fabs (ZeroPt - zeropt) > 1e-4) {
+    Shutdown ("zero point in image (%f:%s) inconsistent with zero point in catalog (%f)",
+	     ZeroPt, image[0].name, zeropt);
+  }
+
+  /* project onto rectilinear grid with 1 arcsec pixels */
+  /* we keep the original crpix1,2 and crref1,2 */
+  /* for mosaic astrometry, the grid should be w.r.t. the tangent-plane, not chip coords */
+  if (!strcmp (&image[0].coords.ctype[4], "-WRP")) {
+    tcoords = mosaic[0];
+    tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+    tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+    tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+    tcoords.Npolyterms = 1;
+    strcpy (tcoords.ctype, "RA---TAN");
+    RegisterMosaic (mosaic);
+    /* register so image->sky conversions below have correct mosaic */
+  } else {
+    tcoords = image[0].coords;
+    tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+    tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+    tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+    strcpy (tcoords.ctype, "RA---TAN");
+  }
+
+  /* define original corners */
+  SetImageCorners (Xo, Yo, &image[0]);
+  Xo[4] = Xo[0]; Yo[4] = Yo[0];  /* so we can make a loop easily */
+
+  for (j = 0; j < 5; j++) {
+    /* XY-to_RD is two-level if ctype == WRP */
+    XY_to_RD (&r, &d, Xo[j], Yo[j], &image[0].coords);
+    RD_to_XY (&Xo[j], &Yo[j], r, d, &tcoords);
+  }
+  
+  /* pimage represents the subset of overlapping images */
+  npimage = 0;
+  NPIMAGE = 20;
+  ALLOCATE (pimage, Image, NPIMAGE);
+
+  /* setup links for mosaic WRP and DIS entries */
+  BuildChipMatch (timage, Ntimage);
+
+  /* run through image table and search for overlaps
+     also define the vtable entries for the images we keep  */
+
+  for (i = 0; i < Ntimage; i++) {
+
+    /* if any of these images are WRP images, need to find matching DIS */
+    if (!FindMosaicForImage (timage, Ntimage, i)) continue;
+
+    addtolist = FALSE;
+
+    /* define image corners */
+    SetImageCorners (Xi, Yi, &timage[i]);
+    Xi[4] = Xi[0]; Yi[4] = Yi[0];
+    /* transform to tcoords */
+    for (j = 0; j < 5; j++) {
+      XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+      RD_to_XY (&Xi[j], &Yi[j], r, d, &tcoords);
+    }
+    /* check if any edges cross */
+    for (j = 0; (j < 4) && !addtolist; j++) {
+      for (k = 0; (k < 4) && !addtolist; k++) {
+	addtolist |= edge_check (&Xi[j], &Yi[j], &Xo[k], &Yo[k]);
+      }
+    }
+    
+    /* note that 0,0 is a valid pixel for both DIS and !DIS */
+    /* if no edges cross, check if 0,0 pixel of timage[i] is inside image[0] */
+    SetImageCorners (Xb, Yb, &image[0]);
+    if (!addtolist) {
+      XY_to_RD (&r, &d, 0.0, 0.0, &timage[i].coords);
+      RD_to_XY (&x, &y, r, d, &image[0].coords);
+      addtolist = TRUE;
+      addtolist &= (x < Xb[0]);
+      addtolist &= (y < Yb[0]);
+      addtolist &= (x > Xb[2]);
+      addtolist &= (y > Yb[2]);
+    }
+
+    /* if no edges cross, check if one corner of image[0] is inside timage[i] */
+    SetImageCorners (Xb, Yb, &timage[i]);
+    if (!addtolist) {
+      XY_to_RD (&r, &d, 0.0, 0.0, &image[0].coords);
+      RD_to_XY (&x, &y, r, d, &timage[i].coords);
+      addtolist = TRUE;
+      addtolist &= (x < Xb[0]);
+      addtolist &= (y < Yb[0]);
+      addtolist &= (x > Xb[2]);
+      addtolist &= (y > Yb[2]);
+    }
+
+    if (addtolist) {
+      pimage[npimage] = timage[i];
+      npimage ++;
+      if (npimage == NPIMAGE) {
+	NPIMAGE += 20;
+	REALLOCATE (pimage, Image, NPIMAGE);
+      }
+    }
+  }
+
+  BuildChipMatch (pimage, npimage);
+  
+  if (VERBOSE) fprintf (stderr, "found %d overlapping images\n", npimage);
+
+  *Npimage = npimage;
+  return (pimage);
+}
+  
+/* this function tries to find overlapping images with the current image.
+   it loads the image table in blocks (up to 1000 at a time) and looks
+   for overlaps within the set.  the search is not very robust. in 
+   addition, it needs to look for mosaic DIS images matching any WRP images.
+   if the WRP image is loaded near the beginning of a block, then the corresponding DIS 
+   may be in the previous block, and thus missed 
+
+   we are not adding the matching DIS image to the table.
+
+   we are now loading in the entire image db table into memory.  
+
+*/
+
+# if (0)
+void SetImageCorners (double *X, double *Y, Image *image) {
+
+  if (!strcmp(&image[0].coords.ctype[4], "-DIS")) {
+    X[0] = -0.5*image[0].NX; Y[0] = -0.5*image[0].NY;
+    X[1] = +0.5*image[0].NX; Y[1] = -0.5*image[0].NY;
+    X[2] = +0.5*image[0].NX; Y[2] = +0.5*image[0].NY;
+    X[3] = -0.5*image[0].NX; Y[3] = +0.5*image[0].NY;
+  } else {
+    X[0] = 0;           Y[0] = 0;
+    X[1] = image[0].NX; Y[1] = 0;
+    X[2] = image[0].NX; Y[2] = image[0].NY;
+    X[3] = 0;           Y[3] = image[0].NY;
+  }
+}
+# endif
Index: /tags/addstar-1-7/Ohana/src/addstar/src/greference.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/greference.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/greference.c	(revision 9206)
@@ -0,0 +1,56 @@
+# include "addstar.h"
+# define LOAD_ALLSKY 0
+# define LOAD_DR2    1
+
+Stars *grefcat (char *Refcat, SkyRegion *region, int photcode, int *nstars) {
+
+  int Nstars;
+  Stars *stars;
+
+  if (VERBOSE) fprintf (stderr, "loading reference catalog data from %s\n", Refcat); 
+  if (VERBOSE) fprintf (stderr, "full region: %f - %f, %f - %f\n", region[0].Rmin, region[0].Rmax, region[0].Dmin, region[0].Dmax);
+
+  Nstars = 0;
+  stars = NULL;
+
+  /* get stars from USNO for the given region */
+  if (!strcasecmp (Refcat, "USNO")) {
+    stars = getusno (region, photcode, &Nstars);
+  }
+
+  /* get stars from the USNO B catalog for the given region */
+  if (!strcasecmp (Refcat, "USNOB")) {
+    stars = getusnob (region, photcode, &Nstars);
+  }
+
+  /* get stars from the USNO B catalog for the given region */
+  if (!strcasecmp (Refcat, "TYCHO")) {
+    stars = gettycho (region, photcode, &Nstars);
+  }
+
+  /* get stars from HST GSC for the given region */
+  if (!strcasecmp (Refcat, "GSC")) {
+    stars = getgsc (region, &Nstars);
+  }
+  
+  /* get stars from 2MASS for the given region */
+  if (!strcasecmp (Refcat, "2MASS")) {
+    stars = get2mass (region, photcode, LOAD_ALLSKY, &Nstars);
+  }
+  
+  /* get stars from 2MASS for the given region */
+  if (!strcasecmp (Refcat, "2MASS-ALLSKY")) {
+    stars = get2mass (region, photcode, LOAD_ALLSKY, &Nstars);
+  }
+  
+  /* get stars from 2MASS for the given region */
+  if (!strcasecmp (Refcat, "2MASS-DR2")) {
+    stars = get2mass (region, photcode, LOAD_DR2, &Nstars);
+  }
+  
+  if (VERBOSE && (Nstars == 0)) fprintf (stderr, "no ref objects in region %s\n", region[0].name);
+
+  *nstars = Nstars;
+  return (stars);
+
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/grefstars.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/grefstars.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/grefstars.c	(revision 9206)
@@ -0,0 +1,41 @@
+# include "addstar.h"
+
+/* read ASCII file with ref star data */
+Stars *grefstars (char *file, int photcode, int *Nstars) {
+
+  FILE *f;
+  int N, NSTARS;
+  Stars *stars;
+  char line[256];
+
+  /* open file */
+  f = fopen (file, "r");
+  if (f == NULL) Shutdown ("can't read data from %s", file);
+
+  NSTARS = 100;
+  ALLOCATE (stars, Stars, NSTARS);
+
+  /* read in stars line-by-line */
+  for (N = 0; scan_line (f, line) != EOF; N++) {
+    stripwhite (line);
+    if (line[0] == 0) continue;
+    if (line[0] == '#') continue;
+    dparse (&stars[N].R,  1, line);
+    dparse (&stars[N].D,  2, line);
+    dparse (&stars[N].M,  3, line);
+    dparse (&stars[N].dM, 4, line);
+    while (stars[N].R < 0.0) stars[N].R += 360.0;
+    while (stars[N].R >= 360.0) stars[N].R -= 360.0;
+    stars[N].t = 0;
+    stars[N].code = photcode;
+    stars[N].found = FALSE;
+    CHECK_REALLOCATE (stars, Stars, NSTARS, N+1, 100);
+  }
+  *Nstars = N;
+  return (stars);
+}
+
+/* stars.found is set here to FALSE.
+   find_match_refstars uses stars.found to identify the seq number of the
+   star which is found.  it requires an initial value of -1 XXX
+*/
Index: /tags/addstar-1-7/Ohana/src/addstar/src/gstars.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/gstars.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/gstars.c	(revision 9206)
@@ -0,0 +1,244 @@
+# include "addstar.h"
+
+Stars *gstars (char *file, int *NSTARS, int photcode, Image *image) {
+
+  FILE *f;
+  int j, N, Nbytes, naxis;
+  int itmp, hour, min, simple;
+  char *name, *c, photname[64], line[80];
+  double tmp, sec, dMs;
+  Stars *stars, *rdstars;
+  Header header;
+
+  /* XXX which of these values are required, which are just interesting? */
+
+  if (!gfits_read_header (file, &header)) {
+    fprintf (stderr, "ERROR: can't read header for %s\n", file);
+    exit (1);
+  }
+
+  /* find image rootname */
+  name = filebasename (file);
+  strcpy (image[0].name, name);
+  free (name);
+
+  /* get astrometry information */
+  if (!GetCoords (&image[0].coords, &header)) {
+    fprintf (stderr, "ERROR: no astrometric solution in header\n");
+    exit (1);
+  }
+  itmp = 0;
+  gfits_scan (&header, "NASTRO",   "%d", 1, &itmp);
+  if ((itmp == 0) && !ACCEPT_ASTROM) {
+    fprintf (stderr, "ERROR: bad astrometric solution in header\n");
+    exit (1);
+  }
+  if (!strcmp (&image[0].coords.ctype[4], "-WRP")) {
+    if (MOSAIC == NULL) {
+      fprintf (stderr, "ERROR: no mosaic for WRP image (use -mosaic)\n");
+      exit (1);
+    }
+    RegisterMosaic (MOSAIC);
+  } else {
+    /* force image to lie in 0-360 range */
+    while (image[0].coords.crval1 < 0) image[0].coords.crval1 += 360.0;
+    while (image[0].coords.crval1 > 360.0) image[0].coords.crval1 -= 360.0;
+  }
+    
+  /* CERROR in data file is in arcsec */
+  if (!gfits_scan (&header, "CERROR",   "%lf", 1, &tmp)) tmp = 1.0;
+  image[0].cerror = tmp * 50.0;
+  gfits_scan (&header, "NAXIS1",   "%hd", 1, &image[0].NX); 
+  gfits_scan (&header, "NAXIS2",   "%hd", 1, &image[0].NY);
+ 
+  /* get photcode from header */
+  if (photcode == 0) {
+    if (!gfits_scan (&header, "PHOTCODE", "%s", 1, photname)) {
+      fprintf (stderr, "ERROR: photcode not supplied in header\n");
+      exit (1);
+    }
+    photcode = GetPhotcodeCodebyName (photname);
+    if (photcode == 0) {
+      fprintf (stderr, "ERROR: photcode %s not found in photcode table\n", photname);
+      exit (1);
+    }
+  }
+  if (photcode == 0) {
+    fprintf (stderr, "ERROR: no valid photcode is supplied\n");
+    exit (1);
+  }
+  image[0].source = photcode;
+
+  image[0].NX -= XOVERSCAN;
+  image[0].NY -= YOVERSCAN;
+  gfits_scan (&header, ExptimeKeyword,  "%lf", 1, &tmp);
+  image[0].exptime = tmp;
+  
+  /*** why are we no longer using APMIFIT?? ***/
+  tmp = 0;
+  /* gfits_scan (&header, "APMIFIT",  "%lf", 1, &tmp); */
+  image[0].apmifit_PS = tmp;
+
+  tmp = 0;
+  /* gfits_scan (&header, "dAPMIFIT", "%lf", 1, &tmp); */
+  image[0].dapmifit_PS = tmp;
+
+  tmp = 0;
+  gfits_scan (&header, "FLIMIT",   "%lf", 1, &tmp);
+  image[0].detection_limit = tmp * 10.0;
+
+  tmp = 0;
+  gfits_scan (&header, "FSATUR",   "%lf", 1, &tmp);
+  image[0].saturation_limit = tmp * 10.0;
+
+  tmp = 0;
+  gfits_scan (&header, "FWHM_X",   "%lf", 1, &tmp);
+  image[0].fwhm_x = tmp * 25.0 * image[0].coords.cdelt1 * 3600.0;
+
+  tmp = 0;
+  gfits_scan (&header, "FWHM_Y",   "%lf", 1, &tmp);
+  image[0].fwhm_y = tmp * 25.0 * image[0].coords.cdelt1 * 3600.0;
+
+  if (!gfits_scan (&header, "TZERO",   "%d",  1, &image[0].tzero)) {
+    image[0].tzero = parse_time (&header);
+  }
+
+  if (STKeyword[0]) {
+    /* get ST (used for airmass calculation) */
+    gfits_scan (&header, STKeyword, "%s", 1, line);
+    /* remove ':' characters */
+    for (c = strchr (line, ':'); c != (char *) NULL; c = strchr (line, ':')) { *c = ' '; }
+    sscanf (line, "%d %d %lf", &hour, &min, &sec);
+    image[0].sidtime = hour + min/60.0 + sec/3600.0;
+  } else {
+    double jd;
+    jd = sec_to_jd (image[0].tzero);
+    image[0].sidtime  = ohana_lst (jd, Longitude);
+  }
+  image[0].latitude = Latitude;
+
+  tmp = 0;
+  gfits_scan (&header, "TRATE",   "%lf", 1, &tmp);
+  image[0].trate = 10000 * tmp;
+
+  tmp = 0;
+  gfits_scan (&header, AirmassKeyword, "%lf", 1, &tmp);
+  image[0].secz_PS = MIN (NO_MAG, tmp);
+
+  if (!gfits_scan (&header, CCDNumKeyword, "%d", 1, &itmp)) {
+    image[0].ccdnum = 0xff;
+  } else {
+    image[0].ccdnum = itmp;
+  }
+
+  gfits_scan (&header, "ZERO_PT", "%lf", 1, &ZeroPt);
+  SetZeroPoint (ZeroPt);
+
+  /* secz is in units milli-airmass */
+  image[0].Mcal_PS = 0.0;
+  image[0].Xm   = NO_MAG;
+  image[0].code = 0;
+  bzero (image[0].dummy, sizeof(image[0].dummy));
+
+  /* find expected number of stars */
+  if (!gfits_scan (&header, "NSTARS", "%d", 1, &image[0].nstar)) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    exit (1);
+  }
+
+  /* this is really lame.  get sky background from Flips data */
+  /*** the problems are: 
+       1) need to define sky entry in image table
+       2) need to have sky measurement (in reg.db) 
+       (could be derived from star data?)
+       
+    XXX EAM : make a different SKYPROBE format with sky in appropriate place? 
+  ***/
+
+  /** I'm essentially using subpix to be synonymous with SKYPROBE */
+  if (SUBPIX) {
+    char *p;
+    int sky;
+    
+    sky = 0;
+    gfits_scan (&header, "HISTORY", "%S", 10, line);
+    p = strstr (line, "|I=");
+    if (p != (char *) NULL) {
+      p += 3;
+      sky = atoi (p);
+    }
+    image[0].Myyyy = MIN (sky - 0x8000, 0xffff);
+  }
+
+  /* read in data section */
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't read data from %s\n", file);
+    exit (1);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  /* don't try to read stars for mosaic */
+  if (!strcmp (&image[0].coords.ctype[4], "-DIS")) {
+    rdstars = NULL;
+    image[0].nstar = 0;
+  } else {
+    /* read from FITS table or from text table */
+    naxis = 2;
+    gfits_scan (&header, "NAXIS",  "%d", 1, &naxis);
+    gfits_scan (&header, "SIMPLE", "%t", 1, &simple);
+    if ((naxis == 0) && !TEXTMODE && simple) {
+      Nbytes = gfits_matrix_size (&header);
+      fseek (f, Nbytes, SEEK_CUR); 
+      rdstars = rfits (f, &image[0].nstar);
+      if (rdstars == NULL) {
+	fprintf (stderr, "ERROR: failed to read fits table\n");
+	exit (1);
+      }
+    } else {
+      /* allocate space for stars */
+      if (!gfits_scan (&header, "NSTARS", "%d", 1, &image[0].nstar)) {
+	fprintf (stderr, "ERROR: failed to find NSTARS\n");
+	exit (1);
+      }
+      rdstars = rtext (f, &image[0].nstar);
+    }
+  }
+  fclose (f);
+
+  /* modify resulting star list */
+  ALLOCATE (stars, Stars, image[0].nstar);
+  for (N = j = 0; j < image[0].nstar; j++) {
+    /* allow for some dynamic filtering of star list */
+    if (SNLIMIT && rdstars[j].dM > SNLIMIT) continue;
+    if (XMAX && (rdstars[j].X > XMAX)) continue;
+    if (XMIN && (rdstars[j].X < XMIN)) continue;
+    if (YMAX && (rdstars[j].Y > YMAX)) continue;
+    if (YMIN && (rdstars[j].Y < YMIN)) continue;
+    stars[N] = rdstars[j];
+
+    XY_to_RD (&stars[N].R, &stars[N].D, stars[N].X, stars[N].Y, &image[0].coords);
+    while (stars[N].R <    0.0) stars[N].R += 360.0;
+    while (stars[N].R >= 360.0) stars[N].R -= 360.0;
+    stars[N].found = -1;
+    stars[N].code = photcode;
+
+    if (SUBPIX) {
+      dMs = get_subpix (stars[N].X, stars[N].Y);
+      stars[N].M    -= dMs;
+      stars[N].Mgal -= dMs;
+      stars[N].Map  -= dMs;
+      dMs = scat_subpix (stars[N].X, stars[N].Y);
+      stars[N].dM = hypot (stars[N].dM, dMs);
+    }
+    N ++;
+  }
+  image[0].nstar = N;
+  REALLOCATE (stars, Stars, image[0].nstar);
+  free (rdstars);
+
+  if (VERBOSE) fprintf (stderr, "read %d stars from target file\n", image[0].nstar);
+  *NSTARS = image[0].nstar;
+
+  return (stars);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/gztest.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/gztest.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/gztest.c	(revision 9206)
@@ -0,0 +1,99 @@
+# include "ohana.h"
+# include "zlib.h"
+# define DTIME(A,B) ((A.tv_sec - B.tv_sec) + 1e-6*(A.tv_usec - B.tv_usec))
+
+main (int argc, char **argv) {
+
+  int N, Nread, Nseek, Nback;
+  char *filename, *buffer;
+  gzFile gf;
+  FILE *f;
+  struct timeval start, stop;
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: gztest (mode) (file) (Nseek) (Nread) (Nback)\n");
+    exit (2);
+  }
+
+  filename = argv[2];
+  Nseek = atoi (argv[3]);
+  Nread = atoi (argv[4]);
+  Nback = -1 * atoi (argv[5]);
+  ALLOCATE (buffer, char, Nread);
+
+  if (!strcmp (argv[1], "gz")) {
+    gf = gzopen (filename, "rb");
+    if (gf == NULL) {
+      fprintf (stderr, "can't read data file: %s", filename);
+      exit (1);
+    }
+
+    gettimeofday (&start, NULL);
+    N = gzseek (gf, Nseek, SEEK_SET);
+    gettimeofday (&stop, NULL);
+    if (N != Nseek) {
+      fprintf (stderr, "error seeking\n");
+      exit (1);
+    }
+    fprintf (stdout, "seek: %f\n", DTIME (stop, start));
+
+    gettimeofday (&start, NULL);
+    N = gzread (gf, buffer, Nread);
+    if (N != Nread) {
+      fprintf (stderr, "error reading\n");
+      exit (1);
+    }
+    gettimeofday (&stop, NULL);
+    fprintf (stdout, "read: %f\n", DTIME (stop, start));
+
+    gettimeofday (&start, NULL);
+    N = gzseek (gf, Nback, SEEK_CUR);
+    gettimeofday (&stop, NULL);
+    if (N == -1) {
+      fprintf (stderr, "error seeking\n");
+      exit (1);
+    }
+    fprintf (stdout, "back: %f\n", DTIME (stop, start));
+    exit (0);
+  } 
+
+  if (!strcmp (argv[1], "raw")) {
+    f = fopen (filename, "r");
+    if (f == NULL) {
+      fprintf (stderr, "can't read data file: %s", filename);
+      exit (1);
+    }
+
+    gettimeofday (&start, NULL);
+    N = fseek (f, Nseek, SEEK_SET);
+    gettimeofday (&stop, NULL);
+    if (N) {
+      fprintf (stderr, "error seeking\n");
+      exit (1);
+    }
+    fprintf (stdout, "seek: %f\n", DTIME (stop, start));
+
+    gettimeofday (&start, NULL);
+    N = fread (buffer, 1, Nread, f);
+    gettimeofday (&stop, NULL);
+    if (N != Nread) {
+      fprintf (stderr, "error reading\n");
+      exit (1);
+    }
+    fprintf (stdout, "read: %f\n", DTIME (stop, start));
+
+    gettimeofday (&start, NULL);
+    N = fseek (f, Nback, SEEK_CUR);
+    gettimeofday (&stop, NULL);
+    if (N) {
+      fprintf (stderr, "error seeking\n");
+      exit (1);
+    }
+    fprintf (stdout, "back: %f\n", DTIME (stop, start));
+    exit (0);
+  }
+    
+  
+  fprintf (stderr, "unknown mode\n");
+  exit (1);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/in_image.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/in_image.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/in_image.c	(revision 9206)
@@ -0,0 +1,14 @@
+# include "addstar.h"
+
+int in_image (double r, double d, Image *image) {
+
+  double X, Y;
+
+  RD_to_XY (&X, &Y, r, d, &image[0].coords);
+  if (X < 0) return (FALSE);
+  if (Y < 0) return (FALSE);
+  if (X >= image[0].NX) return (FALSE);
+  if (Y >= image[0].NY) return (FALSE);
+  return (TRUE);
+}
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/load2mass.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/load2mass.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/load2mass.c	(revision 9206)
@@ -0,0 +1,29 @@
+# include "addstar.h"
+# include "2mass.h"
+
+int main (int argc, char **argv) {
+
+  char *path;
+  int i;
+  SkyTable *sky, *sky2mass;
+  AddstarClientOptions options;
+
+  // need to construct these options with args_load2mass...
+  options = ConfigInit (&argc, argv);
+  options = args_load2mass (argc, argv, options);
+
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  path = TWO_MASS_DIR_AS;
+
+  // the accel.dat file has the raw filenames
+  // test if the file exists, or else try the .gz version
+  sky2mass = load2mass_acc (path, "accel.dat");
+  
+  for (i = 0; i < sky2mass[0].Nregions; i++) {
+    fprintf (stderr, "loading %s\n", sky2mass[0].filename[i]);
+    load2mass_as_rawdata (sky, sky2mass[0].filename[i], options);
+  }
+  exit (0);
+}  
Index: /tags/addstar-1-7/Ohana/src/addstar/src/load2mass_as_rawdata.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/load2mass_as_rawdata.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/load2mass_as_rawdata.c	(revision 9206)
@@ -0,0 +1,206 @@
+# include "addstar.h"
+# include "2mass.h"
+
+/* unlike the DR2 data, the AS data is NOT fixed bytes/row 
+ * we need to handle fractional lines at the end of each read block
+ */
+
+/* read in chunks of ~64MB */
+# define NBYTE 0x4000000
+# define NBREC 330
+# define DEBUG 0
+
+int load2mass_as_rawdata (SkyTable *skytable, char *filename, AddstarClientOptions options) {
+  
+  int i, j, verbose;
+  int Nstars, NSTARS, Ntstars, NTSTARS;
+  int Nbyte, Nextra, Ntotal, offset;
+
+  double Rmin, Rmax, Dmin, Dmax;
+
+  FILE *f;
+  char *buffer, *p, *q;
+
+  Stars *stars;
+  TMStars *tstars;
+  SkyList *skylist;
+  SkyRegion *region;
+  Catalog catalog;
+
+  get2mass_setup (-1);
+
+  ALLOCATE (buffer, char, NBYTE);
+
+  // scan through the entire 2MASS file
+  f = fopen (filename, "r");
+  if (f == NULL) Shutdown ("can't read 2mass data file: %s", filename);
+  // test if this is a raw datafile or gzipped...
+
+  Nextra = 0;  // number excess bytes from lsat partial row
+  Ntotal = 0;  // track the total number of bytes read 
+  while ((Nbyte = fread (&buffer[Nextra], 1, NBYTE-Nextra, f)) != 0) {
+    if (Nbyte == -1) Shutdown ("error reading from raw file %s", filename);
+    if (DEBUG) fprintf (stderr, "read %d bytes", Nbyte);
+
+    Nbyte += Nextra;
+
+    if (VERBOSE) fprintf (stderr, ".");
+
+    /* find bounds on first complete line */
+    p = buffer;
+    q = memchr (p, '\n', Nbyte);
+    if (q == NULL) Shutdown ("incomplete line at end of file\n");
+    offset = p - buffer; // offset within this scan
+
+    Ntstars = 0;
+    NTSTARS = 10000;
+    ALLOCATE (tstars, TMStars, NTSTARS);
+
+    Rmin = 360.0;
+    Rmax =   0.0;
+    Dmin = +90.0;
+    Dmax = -90.0;
+
+    // scan through entire buffer for star coords
+    while (1) {
+      get2mass_coords (p, &tstars[Ntstars].R, &tstars[Ntstars].D, Nbyte - offset);
+      tstars[Ntstars].offset = offset; // offset within scan
+      tstars[Ntstars].flag = FALSE;
+
+      if (VERBOSE) {
+	Rmin = MIN (Rmin, tstars[Ntstars].R);
+	Rmax = MAX (Rmax, tstars[Ntstars].R);
+	Dmin = MIN (Dmin, tstars[Ntstars].D);
+	Dmax = MAX (Dmax, tstars[Ntstars].D);
+      }
+
+      Ntstars ++;
+      CHECK_REALLOCATE (tstars, TMStars, NTSTARS, Ntstars, 10000);
+
+      /* start of the next line */
+      p = q + 1;
+      offset = p - buffer; // offset within this scan
+      if (offset == Nbyte) {
+	// last line in buffer is a complete line
+	Nextra = 0;
+	break;
+      }
+      /* end of the next line */
+      q = memchr (p, '\n', Nbyte - offset);
+      if (q == NULL) {
+	// last, incomplete line in buffer
+	Nextra = Nbyte - offset;
+	break;
+      } 
+    }
+    if (VERBOSE) fprintf (stderr, "read %d stars (%10.6f - %10.6f, %10.6f - %10.6f)\n", Ntstars, Rmin, Rmax, Dmin, Dmax);
+
+
+    // scan through the stars, loading the containing catalogs
+    // skip through table for unsaved stars
+    for (i = 0; i < Ntstars; i++) {
+      if (tstars[i].flag) continue;
+
+      // collect stars in a new output catalog
+      Nstars = 0;
+      NSTARS = 3000;
+      ALLOCATE (stars, Stars, NSTARS);
+	
+      // identify the relevant catalog
+      skylist = SkyRegionByPoint (skytable, -1, tstars[i].R, tstars[i].D);
+      region = skylist[0].regions[0];
+      if (DEBUG) fprintf (stderr, "writing to %s\n", skylist[0].filename[0]);
+
+      for (j = i; j < Ntstars; j++) {
+	if (tstars[j].flag) continue;
+
+	// check if in skyregion
+	if (tstars[j].R < region[0].Rmin) continue;
+	if (tstars[j].R > region[0].Rmax) continue;
+	if (tstars[j].D < region[0].Dmin) continue;
+	if (tstars[j].D > region[0].Dmax) continue;
+	  
+	offset = tstars[j].offset;
+
+	stars[Nstars+0].R = tstars[j].R;
+	stars[Nstars+0].D = tstars[j].D;
+	stars[Nstars+1].R = tstars[j].R;
+	stars[Nstars+1].D = tstars[j].D;
+	stars[Nstars+2].R = tstars[j].R;
+	stars[Nstars+2].D = tstars[j].D;
+	get2mass_3star (&stars[Nstars], &buffer[offset], Nbyte - offset);
+	// get2mass_star (&stars[Nstars], &buffer[offset], Nbyte - offset);
+
+	tstars[j].flag = TRUE;
+
+	Nstars += 3;
+	if (Nstars >= NSTARS - 3) {
+	  NSTARS += 3000;
+	  REALLOCATE (stars, Stars, NSTARS);
+	}
+      }
+      if (!Nstars) {
+	free (stars);
+	continue;
+      }
+      if (DEBUG) fprintf (stderr, "selected %d stars (%10.6f - %10.6f, %10.6f - %10.6f\n", Nstars, 
+			  region[0].Rmin, region[0].Rmax, region[0].Dmin, region[0].Dmax);
+
+      if (1) {
+	verbose = VERBOSE;
+	VERBOSE = FALSE;
+
+	// now we have all of the loaded stars in this catalog
+	catalog.filename = skylist[0].filename[0];
+	catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+	catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+	catalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+	catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+
+	// an error exit status here is a significant error
+	if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+	  fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+	  exit (2);
+	}
+
+	// assume no input star matches an existing star 
+	// simply add to the existing table
+	load2mass_catalog (&catalog, stars, Nstars);
+
+	dvo_catalog_save (&catalog, VERBOSE);
+	dvo_catalog_unlock (&catalog);
+	dvo_catalog_free (&catalog);
+	// free (catalog.filename);
+	// XXX don't free this! it points to an element of the skytable
+      }
+
+      SkyListFree (skylist, FALSE);
+      free (stars);
+      VERBOSE = verbose;
+    }
+    free (tstars);
+
+    // at end, p points at the start of last, partial line
+    if (Nextra) memmove (buffer, p, Nextra);
+  }
+
+  if (VERBOSE) fprintf (stderr, "\n");
+  
+  fclose (f);
+  free (buffer);
+  return (TRUE);
+}
+
+/*
+  for each 2mass file:
+  for each data block
+  generate a table of: R, D, byte, flag
+  for each unsaved star
+  find containing catalog
+  load catalog
+  find all contained stars
+  add to catalog
+  save catalog 
+  mark all contained stars
+*/
+
Index: /tags/addstar-1-7/Ohana/src/addstar/src/load2mass_catalog.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/load2mass_catalog.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/load2mass_catalog.c	(revision 9206)
@@ -0,0 +1,86 @@
+# include "addstar.h"
+
+int load2mass_catalog (Catalog *catalog, Stars *stars, int Nstars) {
+
+  int i, j, Nsec, Nmeas, Nave, NMEAS, NAVE;
+
+  Nsec = GetPhotcodeNsecfilt ();
+  Nave = catalog[0].Naverage;
+  Nmeas = catalog[0].Nmeasure;
+   
+  NAVE = Nave + 100;
+  NMEAS = Nmeas + 100;
+  REALLOCATE (catalog[0].average, Average, NAVE);
+  REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*Nsec);
+  REALLOCATE (catalog[0].measure, Measure, NMEAS);
+
+  for (i = 0; i < Nstars; i+=3) {
+
+    // construct an average object for this object
+    // XXX for now, the output objects will have limited astrometric interpretation...
+    // XXX every 3 stars represents 3 measurements and 1 average
+    catalog[0].average[Nave].R     = stars[i].R;
+    catalog[0].average[Nave].D     = stars[i].D;
+    catalog[0].average[Nave].dR    = 0;
+    catalog[0].average[Nave].dD    = 0;
+    catalog[0].average[Nave].uR    = 0;
+    catalog[0].average[Nave].uD    = 0;
+    catalog[0].average[Nave].duR   = 0;
+    catalog[0].average[Nave].duD   = 0;
+    catalog[0].average[Nave].P     = 0;
+    catalog[0].average[Nave].dP    = 0;
+
+    // XXX for now, set the average mag data to NULL
+    catalog[0].average[Nave].M         = NO_MAG;
+    catalog[0].average[Nave].dM        = NO_MAG;
+    catalog[0].average[Nave].Nm        = 0;
+    catalog[0].average[Nave].Nn        = 0;
+    catalog[0].average[Nave].Xp        = NO_MAG;
+    catalog[0].average[Nave].Xm        = NO_MAG;
+    catalog[0].average[Nave].Xg        = NO_MAG;
+    catalog[0].average[Nave].offset    = Nmeas;
+    catalog[0].average[Nave].missing   = -1;
+    catalog[0].average[Nave].code      = 0;
+
+    for (j = 0; j < Nsec; j++) {
+      catalog[0].secfilt[Nave*Nsec+j].M_PS  = NO_MAG;
+      catalog[0].secfilt[Nave*Nsec+j].dM_PS = NO_MAG;
+      catalog[0].secfilt[Nave*Nsec+j].Xm    = NO_MAG;
+    }
+
+    // we now have the min chisq row. use this to supply the other filter values....
+    for (j = 0; j < 3; j++) {
+      catalog[0].measure[Nmeas].dR_PS       = 0.0;
+      catalog[0].measure[Nmeas].dD_PS       = 0.0;
+      catalog[0].measure[Nmeas].M_PS        = MIN (stars[i+j].M,  NO_MAG);
+      catalog[0].measure[Nmeas].dM_PS       = MIN (stars[i+j].dM,  NO_ERR);
+      catalog[0].measure[Nmeas].Mcal_PS     = 0;
+      catalog[0].measure[Nmeas].t           = stars[i+j].t;
+      catalog[0].measure[Nmeas].averef      = Nave;
+      catalog[0].measure[Nmeas].source      = stars[i+j].code;
+      catalog[0].measure[Nmeas].dophot      = 0;
+      catalog[0].measure[Nmeas].flags       = 0;
+      catalog[0].measure[Nmeas].dt_PS       = 0xffff;
+
+      catalog[0].measure[Nmeas].Mgal_PS     = NO_MAG;
+      catalog[0].measure[Nmeas].airmass_PS  = 0;
+      catalog[0].measure[Nmeas].FWx         = NO_MAG;
+      catalog[0].measure[Nmeas].FWy         = NO_ERR;
+      catalog[0].measure[Nmeas].theta       = NO_ERR;
+
+      catalog[0].average[Nave].Nm++;
+      Nmeas ++;
+      CHECK_REALLOCATE (catalog[0].measure, Measure, NMEAS, Nmeas, 100);
+    }
+
+    Nave ++;
+    if (Nave >= NAVE) {
+      NAVE += 100;
+      REALLOCATE (catalog[0].average, Average, NAVE);
+      REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*Nsec);
+    }
+  }
+  catalog[0].Naverage = Nave;
+  catalog[0].Nmeasure = Nmeas;
+  return (TRUE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/load_subpix.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/load_subpix.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/load_subpix.c	(revision 9206)
@@ -0,0 +1,51 @@
+# include "addstar.h"
+
+typedef struct {
+  double Amp;
+  double Phase;
+  double dM;
+} SubPixFix;
+
+static int Nsubpix;
+static SubPixFix *Subpix;
+
+void load_subpix () {
+
+  int i;
+  FILE *f;
+
+  Nsubpix = 40;
+  ALLOCATE (Subpix, SubPixFix, Nsubpix);
+
+  f = fopen (SubpixDatafile, "r");
+  if (f == NULL) Shutdown ("can't load subpix datafile %s", SubpixDatafile);
+
+  for (i = 0; i < Nsubpix; i++) {
+    fscanf (f, "%*s %*s %lf %lf %lf %*s\n", 
+	    &Subpix[i].Amp, &Subpix[i].Phase, &Subpix[i].dM);
+  }
+  fclose (f);
+
+}
+
+double get_subpix (double x, double y) {
+
+  int bin;
+  double dy, dM;
+
+  dy = y - (int)(y);
+  bin = 5 * (int)(x/100) + (int)(y/100);
+  dM = Subpix[bin].Amp*sin(2*3.14159*dy + Subpix[bin].Phase);
+  return (dM);
+}
+
+double scat_subpix (double x, double y) {
+
+  int bin;
+  double dy, dM;
+
+  dy = y - (int)(y);
+  bin = 5 * (int)(x/100) + (int)(y/100);
+  dM = Subpix[bin].dM;
+  return (dM);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/mkacc-2mass.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/mkacc-2mass.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/mkacc-2mass.c	(revision 9206)
@@ -0,0 +1,74 @@
+# include "addstar.h"
+# include "2mass.h"
+
+int main (int argc, char **argv) {
+
+  int i, N, Nrefcat;
+  Stars *refcat;
+  SkyRegion *regions, accregion;
+
+  ConfigInit (&argc, argv);
+
+  /* override any header PHOTCODE values */
+  thiscode = NULL;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    remove_argument (N, &argc, argv);
+    thiscode = GetPhotcodebyName (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: mkacc.2mass (file)\n");
+    exit (2);
+  }
+
+  NAMED_PHOTCODE (TM_J, "2MASS_J");
+  NAMED_PHOTCODE (TM_H, "2MASS_H");
+  NAMED_PHOTCODE (TM_K, "2MASS_K");
+  if (thiscode == NULL) Shutdown ("photcode not specified");
+  if (thiscode[0].code == TM_J) goto good_code;
+  if (thiscode[0].code == TM_H) goto good_code;
+  if (thiscode[0].code == TM_K) goto good_code;
+  Shutdown ("2MASS photcode not specified");
+
+good_code:
+  UserPatch.RAmin = 0;
+  UserPatch.RAmax = 360;
+  UserPatch.DECmin = -90;
+  UserPatch.DECmax = +90;
+
+  ALLOCATE (regions, SkyRegion, 1);
+  strcpy (regions[0].filename, argv[1]);
+  regions[0].RAmin = 0;
+  regions[0].RAmax = 360;
+  regions[0].DECmin = -90;
+  regions[0].DECmax = +90;
+
+  refcat = get2mass_AS_data (regions, &UserPatch, &Nrefcat);
+
+  /* find upper and lower file limits in RA and DEC */
+
+  strcpy (accregion.filename, regions[0].filename);
+  accregion.RAmin  = 360;
+  accregion.RAmax  =   0;
+  accregion.DECmin = +90;
+  accregion.DECmax = -90;
+
+  for (i = 0; i < Nrefcat; i++) {
+    accregion.RAmin  = MIN (refcat[i].R, accregion.RAmin);
+    accregion.RAmax  = MAX (refcat[i].R, accregion.RAmax);
+    accregion.DECmin = MIN (refcat[i].D, accregion.DECmin);
+    accregion.DECmax = MAX (refcat[i].D, accregion.DECmax);
+  }
+
+  fprintf (stderr, "%s %10.6f %10.6f  %10.6f %10.6f  %d\n", 
+	   accregion.filename, accregion.RAmin/15.0, accregion.RAmax/15.0, accregion.DECmin, accregion.DECmax, Nrefcat);
+
+  exit (0);
+}
+
+/* XXX update this function to create an additional accelerator file for each 2mass file
+   each file: one row per DEC band
+   each row: Rmin, Rmax, Dmin, Dmax, Nbyte(i)
+   where Nbyte(i) = byte for each Rmin + i*30 deg transition
+*/
Index: /tags/addstar-1-7/Ohana/src/addstar/src/opening_angle.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/opening_angle.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/opening_angle.c	(revision 9206)
@@ -0,0 +1,20 @@
+# include "addstar.h"
+
+double opening_angle (double x1, double y1, double x2, double y2, double x3, double y3) {
+
+  double dx1, dy1, dx2, dy2, ct, st, theta;
+
+  dx1 = x1 - x2;
+  dy1 = y1 - y2;
+  
+  dx2 = x3 - x2;
+  dy2 = y3 - y2;
+  
+  ct = (dx1*dx2 + dy1*dy2);
+  st = (dx1*dy2 - dx2*dy1);
+
+  theta = atan2 (st, ct);
+
+  return (theta);
+
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/parse_time.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/parse_time.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/parse_time.c	(revision 9206)
@@ -0,0 +1,134 @@
+# include "addstar.h"
+
+int parse_time (Header *header) {
+
+  double jd;
+  int Ny, Nf, mode;
+  int Nsec, hour, min, sec, year, month, day;
+  char *py, *pm, *pd, *c;
+  char line[256];
+
+  /* we want to find JD or MJD to get Nsec (seconds since 01/01/1970) */
+
+  /* try JD first */
+  if (strcasecmp (JDKeyword, "NONE")) {
+    uppercase (JDKeyword);
+    gfits_scan (header, JDKeyword, "%lf", 1, &jd);
+    Nsec = (jd - 2440587.5)*86400;
+    return (Nsec);
+  }
+
+  /* try MJD next */
+  if (strcasecmp (MJDKeyword, "NONE")) {
+    uppercase (MJDKeyword);
+    gfits_scan (header, MJDKeyword, "%lf", 1, &jd);
+    Nsec = (jd - 40587.0)*86400;
+    return (Nsec);
+  }
+    
+  if (!strcasecmp (UTKeyword, "NONE")) {
+      fprintf (stderr, "ERROR: no valid Date/Time keywords\n");
+      exit (1);
+  }
+  if (!strcasecmp (DateKeyword, "NONE")) {
+      fprintf (stderr, "ERROR: no valid Date/Time keywords\n");
+      exit (1);
+  }
+  if (!strcasecmp (DateMode, "NONE")) {
+      fprintf (stderr, "ERROR: no valid Date/Time keywords\n");
+      exit (1);
+  }
+
+  /* get UT and DATE */
+  uppercase (UTKeyword);
+  gfits_scan (header, UTKeyword, "%s", 1, line);
+  /* remove ':' characters */
+  for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (line, 0x3a)) { *c = ' '; }
+  sscanf (line, "%d %d %d", &hour, &min, &sec);
+
+  /* parse mode line */
+  uppercase (DateMode);
+  for (Ny = 0, c = strchr (DateMode, 'Y'); c != (char ) NULL; c = strchr (c + 1, 'Y'), Ny++);
+  if ((Ny != 2) && (Ny != 4)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  py = strchr (DateMode, 'Y');
+  pm = strchr (DateMode, 'M');
+  pd = strchr (DateMode, 'D');
+  if ((py == (char *) NULL) || (pm == (char *) NULL) || (pd == (char *) NULL)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  if ((py > pm) && (py < pd)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  if ((py > pd) && (py < pm)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  mode = 0;
+  if ((py < pm) && (pm < pd)) { mode = 1; }  /* yyyy-mm-dd */
+  if ((py < pm) && (pm > pd)) { mode = 2; }  /* yyyy-dd-mm */
+  if ((py > pm) && (pm < pd)) { mode = 3; }  /* mm-dd-yyyy */
+  if ((py > pm) && (pm > pd)) { mode = 4; }  /* dd-mm-yyyy */
+  if (!mode) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+
+  /* parse date entry */
+  uppercase (DateKeyword);
+  gfits_scan (header, DateKeyword, "%s",  1, line);
+  /* remove possible separators: ':', '/' '.', '-' */
+  for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (line, 0x3a)) { *c = ' '; }
+  for (c = strchr (line, 0x2f); c != (char *) NULL; c = strchr (line, 0x2f)) { *c = ' '; }
+  for (c = strchr (line, 0x2e); c != (char *) NULL; c = strchr (line, 0x2e)) { *c = ' '; }
+  for (c = strchr (line, 0x2d); c != (char *) NULL; c = strchr (line, 0x2d)) { *c = ' '; }
+
+  Nf = 0;
+  switch (mode) {
+  case 1:
+    Nf = sscanf (line, "%d %d %d", &year, &month, &day);
+    break;
+  case 2:
+    Nf = sscanf (line, "%d %d %d", &year, &day, &month);
+    break;
+  case 3:
+    Nf = sscanf (line, "%d %d %d", &month, &day, &year);
+    break;
+  case 4:
+    Nf = sscanf (line, "%d %d %d", &day, &month, &year);
+    break;
+  }
+  if (Nf != 3) {
+    fprintf (stderr, "error in date entry (%s) or DATE-MODE format (%s)\n", line, DateMode);
+    exit (1);
+  }
+
+  if (year > 1000) {
+    if (Ny == 2) {
+      fprintf (stderr, "warning: mode line claims 2 digit year, but 4 digit year found\n");
+    }
+  } else {
+    if (Ny == 4) {
+      fprintf (stderr, "warning: mode line claims 4 digit year, but 2 digit year found\n");
+    }
+    if (year < 50) year += 100;
+    year += 1900;
+  }    
+
+  /* this should probably use localtime */
+
+  /* convert yy.mm.dd hh.mm.ss to Nsec since 1970 (jd = 2440587.5) */
+  /* note that in this section, tm_mon has range 1-12, unlike for gmtime () */
+  jd = day - 32075 + (int)(1461*(year + 4800 + (int)(((month)-14)/12))/4)
+    + (int)(367*((month) - 2 - (int)(((month) - 14)/12)*12)/12)
+    - (int)(3*(int)((year + 4900 + (int)(((month) - 14)/12))/100)/4) - 0.5;
+  /* jd is the julian day of the whole day only not the time */
+  Nsec = (jd - 2440587.5)*86400 + 3600.0*hour + min*60.0 + sec;
+  
+  return (Nsec);
+
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/replace_match.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/replace_match.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/replace_match.c	(revision 9206)
@@ -0,0 +1,18 @@
+# include "addstar.h"
+
+int replace_match (Average *average, Measure *measure, Stars *star) {
+
+  int i;
+
+  /* search for entry and replace values M, dM, R, D */
+  for (i = 0; i < average[0].Nm; i++) {
+    if (measure[i].source != star[0].code) continue;
+    measure[i].dR_PS       = 3600.0*(average[0].R - star[0].R);
+    measure[i].dD_PS       = 3600.0*(average[0].D - star[0].D);
+    measure[i].M_PS        = MIN (star[0].M,  NO_MAG);
+    measure[i].dM_PS       = MIN (star[0].dM, NO_ERR);
+    star[0].found          = average[0].offset + i;
+    return (TRUE);
+  }
+  return (FALSE);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/resort_catalog.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/resort_catalog.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/resort_catalog.c	(revision 9206)
@@ -0,0 +1,29 @@
+# include "addstar.h"
+
+void resort_catalog (Catalog *catalog) {
+
+  int *next_meas;
+  int Naves, Nmeas;
+  double dtime;
+  struct timeval start, stop;
+
+  if (catalog[0].sorted == TRUE) return;
+
+  gettimeofday (&start, NULL);
+
+  /* internal counters */
+  Nmeas = catalog[0].Nmeasure;
+  Naves = catalog[0].Naverage;
+  
+  /* set up pointers for linked list of measure, missing */
+  next_meas = build_measure_links (catalog[0].average, Naves, catalog[0].measure, Nmeas);
+
+  catalog[0].sorted = TRUE;
+  catalog[0].measure = sort_measure (catalog[0].average, Naves, catalog[0].measure, Nmeas, next_meas);
+
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "  match time %9.4f sec for %7d measures, %6d average\n", dtime, Nmeas, Naves);
+
+  return;
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/rfits.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/rfits.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/rfits.c	(revision 9206)
@@ -0,0 +1,44 @@
+# include "addstar.h"
+
+Stars *rfits (FILE *f, unsigned int *nstars) {
+
+  int i, Nstars;
+  Header theader;
+  FTable table;
+  Stars *stars;
+  SMPData *smpdata;
+
+  /* if no stars, no table */
+  if (*nstars == 0) return (NULL);
+
+  /* init & load in table data */
+  table.header   = &theader;
+  if (!gfits_fread_ftable (f, &table, "SMPFILE")) goto escape;
+
+  smpdata = gfits_table_get_SMPData (&table, &Nstars, NULL);
+
+  ALLOCATE (stars, Stars, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    stars[i].X      = smpdata[i].X;
+    stars[i].Y      = smpdata[i].Y;
+    stars[i].M      = smpdata[i].M;
+    stars[i].dM     = smpdata[i].dM;
+    stars[i].dophot = smpdata[i].dophot;
+
+    stars[i].Mgal   = smpdata[i].M;
+    stars[i].Map    = smpdata[i].dM;
+    stars[i].fx     = smpdata[i].fx;
+    stars[i].fy     = smpdata[i].fy;
+    stars[i].df     = smpdata[i].df;
+  }    
+  *nstars = Nstars;
+  return (stars);
+
+escape:
+  fprintf (stderr, "error reading file\n");
+  *nstars = 0;
+  return (NULL);
+}
+
+// **** this needs to be fixed to handle MEF smp files...
+// there will be multiple extension names, how will these get passed?
Index: /tags/addstar-1-7/Ohana/src/addstar/src/rtext.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/rtext.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/rtext.c	(revision 9206)
@@ -0,0 +1,85 @@
+# include "addstar.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 66
+# define BLOCK 1000
+
+Stars *rtext (FILE *f, unsigned int *nstars) {
+
+  int j, N, Nextra, Ninstar, Nskip, Nbytes, nbytes;
+  int done;
+  char *buffer, *c, *c2;
+  double tmp;
+  Stars *stars;
+  
+  /* load in stars by blocks of 1000 */
+  N = 0;
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR) + 1);
+  buffer[BLOCK*BYTES_STAR] = 0;
+  Nextra = 0;
+
+  ALLOCATE (stars, Stars, *nstars);
+
+  while (N < *nstars) {
+    /* load next data block */
+    Nbytes = BYTES_STAR * BLOCK - Nextra;
+    nbytes = fread (&buffer[Nextra], 1, Nbytes, f);
+    if (nbytes == 0) {
+      *nstars = N;
+      return (stars);
+    }
+    nbytes += Nextra;
+
+    /* check line-by-line integrity */
+    c = buffer;
+    done = FALSE;
+    while ((c < buffer + nbytes) && (!done)) { 
+      for (c2 = c; *c2 == '\n'; c2++);
+      if (c2 > c) { /* extra return chars */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+	if (VERBOSE) fprintf (stderr, "deleted %d extra return chars\n", Nskip);
+      }
+      c2 = strchr (c, '\n');
+      if (c2 == (char *) NULL) {
+	done = TRUE;	
+	continue;
+      }
+      c2++;
+      if ((c2 - c) != BYTES_STAR) { /* bad line, delete it */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+	if (VERBOSE) fprintf (stderr, "deleted line, %d extra chars\n", Nskip);
+      } else {
+	c = c2;
+      }
+    }
+
+    /* extract data for stars */
+    Ninstar = nbytes / BYTES_STAR;
+    Nextra = nbytes % BYTES_STAR;
+    for (j = 0; (j < Ninstar) && (N < *nstars); j++, N++) {
+      dparse (&stars[N].X,  1, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].Y,  2, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].M,  3, &buffer[j*BYTES_STAR]);
+
+      /* cmp files carry dM in millimags */
+      dparse (&tmp, 4, &buffer[j*BYTES_STAR]);
+      stars[N].dM = 0.001*tmp;
+
+      dparse (&tmp,         5, &buffer[j*BYTES_STAR]);
+      stars[N].dophot = tmp;
+
+      dparse (&stars[N].Mgal, 7, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].Map,  8, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].fx,   9, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].fy,  10, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].df,  11, &buffer[j*BYTES_STAR]);
+    }
+  }
+  *nstars = N;
+  return (stars);
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/sedstar.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/sedstar.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/sedstar.c	(revision 9206)
@@ -0,0 +1,85 @@
+# include "sedstar.h"
+
+int main (int argc, char **argv) {
+
+  char *root, *ext, tmp;
+  int i, Nbytes;
+  SkyList *skylist;
+  SkyTable *sky;
+  AddstarClientOptions options;
+  Catalog incatalog, outcatalog;
+  SEDtable *sedtable;
+
+  // need to construct these options with args_load2mass...
+  options = ConfigInit (&argc, argv);
+  options = args_sedstar (argc, argv, options);
+
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  // select regions of interest
+  skylist = SkyListByPatch (sky, -1, &UserPatch);
+
+  // load the SED data table
+  sedtable = SEDtableLoad (argv[1]);
+
+  for (i = 0; i < skylist[0].Nregions; i++) {
+    incatalog.filename = skylist[0].filename[i];
+    incatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_SECF;
+
+    // an error exit status here is a significant error
+    if (!dvo_catalog_open (&incatalog, skylist[0].regions[i], VERBOSE, "r")) {
+      fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", incatalog.filename);
+      exit (2);
+    }
+
+    // Nave_disk == 0 implies an empty catalog file
+    if ((incatalog.Nave_disk == 0) && options.only_match) {
+      if (VERBOSE) fprintf (stderr, "skipping empty region\n");
+      dvo_catalog_unlock (&incatalog);
+      dvo_catalog_free (&incatalog);
+      continue;
+    }
+
+    // create output catalog filename
+    root = strstr (incatalog.filename, CATDIR);
+    if (root == NULL) Shutdown ("error with input catalog name");
+    ext = incatalog.filename + strlen(CATDIR);
+    while (*ext == '/') ext++;
+    Nbytes = snprintf (&tmp, 0, "%s/%s", argv[2], ext);
+    ALLOCATE (outcatalog.filename, char, Nbytes + 1);
+    snprintf (outcatalog.filename, Nbytes + 1, "%s/%s", argv[2], ext);
+
+    outcatalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+    outcatalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+    outcatalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+    // an error exit status here is a significant error
+    if (!dvo_catalog_open (&outcatalog, skylist[0].regions[i], VERBOSE, "w")) {
+      Shutdown ("ERROR: failure to open/create catalog file %s\n", outcatalog.filename);
+    }
+
+    SEDfitCatalog (&outcatalog, &incatalog, sedtable);
+    
+    dvo_catalog_save (&outcatalog, VERBOSE);
+    dvo_catalog_unlock (&outcatalog);
+    dvo_catalog_free (&outcatalog);
+
+    dvo_catalog_unlock (&incatalog);
+    dvo_catalog_free (&incatalog);
+    // XXX free filename or not?
+  }
+  exit (0);
+}  
+
+/**  sedstar: 
+
+* load in the SED data table
+* load in the catalog file (by region)
+* fit stars in the catalog file
+* load output catalog file?
+* construct output catalog file (optional)
+* save output catalog file
+
+**/
Index: /tags/addstar-1-7/Ohana/src/addstar/src/sort_lists.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/sort_lists.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/sort_lists.c	(revision 9206)
@@ -0,0 +1,186 @@
+# include "addstar.h"
+
+void sort_stars (Stars *stars, int N) {
+
+  int l,j,ir,i;
+  Stars tmp;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tmp = stars[l];
+    }
+    else {
+      tmp = stars[ir];
+      stars[ir] = stars[0];
+      if (--ir == 0) {
+	stars[0] = tmp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && stars[j].R < stars[j+1].R) j++;
+      if (tmp.R < stars[j].R) {
+	stars[i] = stars[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    stars[i] = tmp;
+  }
+}
+
+void sort_regions (SkyRegion *region, int N) {
+
+  int l,j,ir,i;
+  SkyRegion tmp;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tmp = region[l];
+    } else {
+      tmp = region[ir];
+      region[ir] = region[0];
+      if (--ir == 0) {
+	region[0] = tmp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && region[j].Dmin < region[j+1].Dmin) j++;
+      if (tmp.Dmin < region[j].Dmin) {
+	region[i] = region[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    region[i] = tmp;
+  }
+}
+
+void sort_lists (float *X, float *Y, int *S, int N) {
+
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    } else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
+
+void fsort (float *X, int N) {
+
+  int l,j,ir,i;
+  float tX;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+    } else {
+      tX = X[ir];
+      X[ir] = X[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+  }
+}
+
+void fsort2 (float *X, float *Y, int N) {
+
+  int l,j,ir,i;
+  float tX, tY;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+    }
+    else {
+      tX = X[ir];
+      tY = Y[ir];
+      X[ir] = X[0];
+      Y[ir] = Y[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+  }
+}
Index: /tags/addstar-1-7/Ohana/src/addstar/src/update_coords.c
===================================================================
--- /tags/addstar-1-7/Ohana/src/addstar/src/update_coords.c	(revision 9206)
+++ /tags/addstar-1-7/Ohana/src/addstar/src/update_coords.c	(revision 9206)
@@ -0,0 +1,53 @@
+# include "addstar.h"
+
+/* find the average and scatter for R and D - no outlier rejection */
+void update_coords (Average *average, Measure *measure, int *next) {
+
+  int i, m, Npt;
+  double R, D, r, d;
+  double r2, d2, dR2, dD2;
+
+  Npt = r = d = r2 = d2 = 0;
+
+  if (average[0].Nm < 2) return;
+
+  /* find the average & sum-square (does not use reference coordinates) */
+  m = average[0].offset;  /* first measurement of this star */
+  for (i = 0; i < average[0].Nm; i++) {
+    if (measure[m].t == 0) {
+      m = next[m];
+      continue;
+    }
+    R = measure[m].dR_PS;
+    D = measure[m].dD_PS;
+    r += R;
+    d += D;
+    r2 += R*R;
+    d2 += D*D;
+    m = next[m];
+    Npt ++;
+  }
+  if (Npt < 1) return;
+
+  /* apply average offset */
+  r = r / Npt;  /* these are corrections in 1/100 arcsec to RA and DEC */
+  d = d / Npt;
+  average[0].R -= r / 3600.0;
+  average[0].D -= d / 3600.0;
+  m = average[0].offset;  /* first measurement of this star */
+  for (i = 0; i < average[0].Nm; i++) {
+    measure[m].dR_PS -= r;
+    measure[m].dD_PS -= d;
+    m = next[m];
+  }
+  
+  /* measure scatter, if possible */
+  if (Npt < 2) return;
+
+  dR2 = r2 / Npt - r*r;
+  dD2 = d2 / Npt - d*d;
+  average[0].Xp = sqrt (dD2 + dR2 / SQ(cos(d*RAD_DEG)));
+  /* Xp is scatter in position in hundredths of arcsec */
+
+  return;
+}
